Red Richardson
Red Richardson

Reputation: 29

Camera not stable as it orbits an object

I'm trying to have a camera orbit a planet in a JOGL solar system model but the planet doesn't want to stay in the center of view. The camera should basically follow a perfect circle around the planet, literally orbiting it on a fixed radius. The planet should appear consistently in the center of the screen but it's not staying there. I've tried to figure out if there's a distance between the calculated position of the planet and the actual position of the planet or if I need to use some trig manipulation but all I get is just a more messed up camera and planet.

==========EDIT==================

I switched to using gluLookAt and made sure that the order of function calling is as follows:

  1. Projection matrix (gluPerspective, not included in the edit)
  2. modelview matrix (gluLookAt)
  3. Transformations (rotate, translate)
  4. Actually drawing the planet (gluSphere)

But the camera is following an erroneous path as if near the origin. What I'm seeing is (I think) the solar system model from the inside of the sun with the camera's back to the origin.

Here's my display function

public void display(GLAutoDrawable drawable) {
        gl = initMatrix(drawable, GL2.GL_MODELVIEW);
        
//      Calculates the orbital and rotational angles of each planet
        for(Planet art : artbook) {
            orbitPlanet(art);
            art.rotate(frameCount);
        }
        
        //The planet the camera is tracking is Earth
        Planet earth = artbook.get(3);
        float planetX = earth.getX(),
                planetZ = earth.getZ(),
                rotation = earth.getRotation(),
                camOffset = 0.1f, //radius of camera's distance from earth
                planetRadius;
        
//determine and set the camera coordinates, focal point
        float camX = planetX + (float) (camOffset * Math.cos(rotation)),
                camZ = planetZ + (float) (camOffset * Math.sin(rotation));
        System.out.println("Camera located at < " + camX + ", 1, " + camZ + " >");
        System.out.println("Camera focused at < " + planetX + ", 1, " + planetZ + " >\n");
        glu.gluLookAt(camX, 0.0f, camZ, planetX, 0.0f, planetZ, 0.0f, 1.0f, 0.0f);
        
        //Draw each planet
        for(Planet art : artbook) {
            returnToOrigin();
            gl.glTranslatef(planetX, 0.0f, planetZ); //orbit
            gl.glRotatef(-rotation, 0.0f, 1.0f, 0.0f); //rotation
            setColor(art);
            glu.gluSphere(quad, planetRadius, 10, 10);
        }
        frameCount += 1;
    }

This orbit function finds the current orbital angle the planet makes with the sun

private void orbitPlanet(Planet art) {
    float sunRadius = 109.3f,
            radius = art.getRadius(),
            offset = art.getOffset(),
            orbit;
    
    //if the planet isn't the sun, skew the offset
    float skew = sunRadius + radius;
    if(radius != sunRadius) offset += skew;
    
    //Get the new orbital position of the planet
    orbit = art.orbit(frameCount) % 360;
    
    //set the position of the planet
    float x = (float) (offset * Math.cos(Math.toRadians(orbit)));
    float z = (float) (offset * Math.sin(Math.toRadians(orbit)));
    art.setX(x);
    art.setZ(z);
}

And here's the Planet class function that determines the orbital angle during a given frame.

public float orbit(float frameCount) {
    //find the new orbit angle theta and the delta between the current and new orbit
    float theta = frameCount * 1/(this.orbitRate);
    this.orbit = theta;
    return this.orbit;
}

Upvotes: -1

Views: 83

Answers (1)

Orbiting a rotating planet around its axis {0,1,0} that itself is orbiting the sun (at origin {0,0,0}).

The general algorithm would be

P' = ProjectionMatrix * ViewMatrix * ModelMatrix * P

then (before going into details) the steps would be as follows:

ProjectionMatrix:

  • set matrix mode to GL_PROJECTION
  • load projection matrix

ViewMatrix:

  • set matrix mode to GL_MODELVIEW
  • set view matrix via lookAt

ModelMatrix:

  • translate planet to its orbital position:
    • rotate (planet orbit radians)
    • translate (radius of orbit)
  • rotate planet around its axis

P:

  • render planet

ViewMatrix

Since the camera is orbiting the planet, we need to calculate the position of the planet. For this we assume, that the orbital plane is the xz-plane and y is the up vector.

where

angle: the orbit angle in radians
radius: the distance from the origin to the center of the planet

planet_x = cos(angle) * radius;
planet_y = 0;
planet_z = sin(angle) * radius;

Now that we have the planet position, which is the target argument to the lookAt function, all that's left is to calculate the eye position. Here we assume again, that the orbital plane is the same as above (xz-plane).

From your description, we know that the camera is orbiting the planet at the same speed of its own rotation around its own axis, therefore we simply reuse the calculated sin/cos values (cx, sz) from said operation and multiply it by the distance to the center of the planet.

eye_x = cx * distance;
eye_y = 0;
eye_z = sz * distance;

but, that is around the origin, we still have to translate it to the actual planet position

eye_x += planet_x;
eye_z += planet_z;

ModelMatrix

Since we calculated the planet position manually (see section ViewMatrix), we can leave the rotation portion out and simply translate it to the calculated position.


Example:

/* calculate orbit coordinates based on an angle and radius */
float[] getCoords(float angle, float radius) {
    float[] pos = {
        Math.cos(angle) * radius,
        0f,
        Math.sin(angle) * radius
    };
    return pos;
}

/* planet orbit position based on an angle and radius */
float[] planet_pos = getCoords(
    angle, //planet around origin
    radius //distance planet to origin
);

/* camera (eye) orbit position based on an angle and radius */
float[] camera_pos = getCoords(
    angle, //camera around planet
    radius //distance camera to planet
);
/* translate to planet pos */
camera_pos[0] += planet_pos[0];
camera_pos[1] += planet_pos[1];
camera_pos[2] += planet_pos[2];

/*--- Display ---*/

/* ProjectionMatrix */
glMatrixMode(GL_PROJECTION);
gluPerspective(fovy, aspect, zNear, zFar);

/* ViewMatrix */
glMatrixMode(GL_MODELVIEW);
gluLookAt(
    //eye
    camera_pos[0], 
    camera_pos[1],
    camera_pos[2],
    //target
    planet_pos[0],
    planet_pos[1],
    planet_pos[2],
    //up vector: y-axis
    0f, 1f, 0f
);

/* ModelMatrix */
glTranslatef(
    planet_pos[0],
    planet_pos[1],
    planet_pos[2]
);
glRotatef(
    angle,     //planet around its own axis
    0f, 1f, 0f //rotation vector: y-axis
);

/* planet */
//e.g. gluSphere(...);

Upvotes: -1

Related Questions