Reputation: 29
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:
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
Reputation: 5903
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:
GL_PROJECTION
ViewMatrix:
GL_MODELVIEW
ModelMatrix:
P:
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