Use RotateAround for orbiting at custom axis

Sorry, english is not my native language.
I’m making some work with objects orbiting another objects. Axises is custom.
I’m want to make object orbit another object on (for example) 65 degrees.

Orbit must look like “GPM core orbit” here or some sort of: http://www.wmo.int/pages/prog/sat/images/non-sunsync-orbits_409.jpg

But all what I can do - rotate around on 0, 45 or 90 degrees inclination. How can I create random (!) custom axis (what will be perpendicular for line “center of object1 - center of object2”) and rotate around it?

using UnityEngine;
using System.Collections;

public class RotateCenter : MonoBehaviour
{
	public float speed;
	public float angle_1;
	public float angle_2;
	public float angle_3;
	void Start()
	{

	}
	void Update()
	{
this.transform.RotateAround(GameObject.FindGameObjectWithTag("MainCube").transform.position, new Vector3(angle_1,angle_2,angle_3), Time.deltaTime * speed);
	}
}

Edit: Ok, here’s the deal. On pic we have some objects. Axises is for World, not local. Object2…4 orbiting object1 with their own orbits. How can I create that orbits? They also may be rotatet around any other axis, not only Z (like on pic).

I guess you could use Quaternion.AngleAxis.

Vector3 direction = Vector3.Normalize(obj1.position - obj2.position);
Quaternion rotation = Quaternion.AngleAxis(speed * Time.deltaTime, direction);
transform.rotation *= rotation;

Not sure if it’ll produce the effect you want. You could also convert it to a Vector3 with Quaternion.ToAngleAxis.

Edit: I’ve made an example on how you can set your own axis rotation based on inclination to a central body called “orbiting”. I’ve actually wrestled with this far longer than I thought I would have to. It’s a bit long because it’s got ample comments about implementation decisions and problems I hit to give you an idea where to continue if you want to base anything off this.

The easy way to make some things orbit another object is just to make empty child game objects that act as a root for your satellites. The satellites are then moved in X for any distance you desire to define as a radius and the root objects rotate around their own pivot. The game object heirarchy could look something like this:

  • Planet
    • Satellite Rotator (centered on parent)
      • Satellite (offset from parent)
    • Satellite Rotator (centered on parent)
      • Satellite (offset from parent)
    • Satellite Rotator (centered on parent)
      • Satellite (offset from parent)

If for any reason you don’t want to parent them together you have to use transform.RotateAround or implement rotation using Quaternions etc.

I’m pasting the example script below, but it’s not very flexible but it is something. It has decent authoring flow and it will visualize the orbit, updating in real time.

using UnityEngine;

public class RotateAroundObject : MonoBehaviour
{
    public float angularSpeed = 90;
    public Transform orbiting;

    [Range(0, 360)]
    public float inclination = 90;

    public bool randomizeInclination;

    [SerializeField]
    [HideInInspector]
    public Vector3 bakedAxis = Vector3.up;

    [SerializeField]
    [HideInInspector]
    public Vector3 bakedPivot = Vector3.zero;

    [SerializeField]
    [HideInInspector]
    public Vector3 position;

    [SerializeField]
    [HideInInspector]
    public float bakedRadius;

    void Start()
    {
        // Eh, consider move it to another script...
        if (randomizeInclination)
        {
            // Set randomizeInclination to false to let gizmo know
            // that inclination has been determined.
            randomizeInclination = false;
            inclination = Random.Range(0f, 360f);
        }
        // Bake happens during Start to give scripts a chance
        // to modify settings during their Awake.
        Bake();
    }

    void Update()
    {
        UpdatePosition();
        // Prefer not to RotateAround because if user change position 
        // in editor while playing, the orbit axis get screwed up.
        // Sorry, if you want to move object, be a better mathematician than me! :)
        // Or just do it the easy way with child transforms.
        // transform.RotateAround(bakedPivot, bakedAxis, speed * Time.deltaTime);
    }

    void UpdatePosition()
    {
        // Updates position to next point in orbit based on angular speed.
        // Position is managed and not shared through transform because
        // of problems with math, I rather prevent user/scripts to move
        // object while playing. Read note in Update.
        float angle = angularSpeed * Time.deltaTime;
        Vector3 offset = position - bakedPivot;
        Quaternion rotation = Quaternion.AngleAxis(angle, bakedAxis);
        position = bakedPivot + rotation * offset;
        transform.position = position; // Overwrite position.
    }

    public void Bake()
    {
        // "Bakes" or freezes information about the rotation setup.
        // This should not be called during play because the axis
        // will reorient depending on the offset to pivot.
        // If you can figure out how to solve LookRotation, then
        // the system could work more flexibly and does not need
        // to be baked like this. The problem is that the rotation
        // will be different for every position, so if you keep
        // updating bakedAxis with my approach, you'll get strange
        // behaviour.
        position = transform.position;
        bakedPivot = orbiting ? orbiting.position : Vector3.zero;
        bakedRadius = Vector3.Distance(bakedPivot, position);
        bakedAxis = Quaternion.LookRotation(position - bakedPivot)
            * Quaternion.Euler(90, -90, 0)
            * Quaternion.Euler(inclination, 0, 0)
            * -Vector3.forward;
    }

    void OnDrawGizmos()
    {
        if (!Application.isPlaying)
        {
            // Sorry mate, I don't know of a good way to
            // update the Axis/Pivot while it is animating
            // because the position will change the axis.
            Bake();
        }

        Gizmos.color = orbitColor * 0.5f;
        DrawOrbitGizmo();
    }

    void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.white;
        Gizmos.DrawLine(bakedPivot, position);
        Gizmos.DrawLine(bakedPivot, bakedPivot + bakedAxis);

        Gizmos.color = orbitColor;
        DrawOrbitGizmo();
    }

    Color orbitColor
    {
        // Green means OK.
        // Red means you haven't set the orbiting object in inspector.
        get { return orbiting ? Color.green : Color.red; }
    }

    void DrawOrbitGizmo(int lineCount = 20)
    {
        if (randomizeInclination)
        {
            Gizmos.DrawWireSphere(bakedPivot, bakedRadius);
        }
        else
        {
            for (int i = 0; i < lineCount; ++i)
            {
                Vector3 orbitI = OrbitPoint(i, lineCount);
                Vector3 orbitJ = OrbitPoint(i + 1, lineCount);
                Gizmos.DrawLine(orbitI, orbitJ);
            }
        }
    }

    Vector3 OrbitPoint(int i, int count)
    {
        float percent = i / (float)count;
        float angle = percent * Mathf.PI * 2;
        return bakedPivot
            + Quaternion.LookRotation(bakedAxis)
            * new Vector3(Mathf.Sin(angle) * bakedRadius, Mathf.Cos(angle) * bakedRadius);
    }
}

I guess you need to use transform.RotateAround()

transform.RotateAround(target.position, Vector3.up, 20 * Time.deltaTime);

This line of code is just rotating around global up axis. If you need to rotate around local axis of your orbiting object, You need to call lookAt() function to rotate your orbiting object too. Something like:

transform.RotateAround(target.position, transform.up, speed * Time.deltaTime); //use transform.right for another axis
transform.LookAt(target)

If gimbal lock problem exist, you might try:

 transform.LookAt(target,transform.up)

I hope that helps.