Algorithm for camera translation in 3D

Started by JemBot, July 06, 2005, 02:15:27

Previous topic - Next topic

JemBot

Hi there.

I'm trying to calculate the camera or 'player' position in 3D space.

I can calculate it in 2D (ie a single plane) using sin(heading * pi/180) and cos(heading * pi/180), as is well documented on the net.

But I want to have free movement in 3D. I.e. I want to include a heading on the X plane as well as the Y plane.

At first I thought I could use a Y-plane heading to calculate X & Z camera positions, and an X-plane heading to calculate the Y camera position. This *almost* worked, but falls over when my headings are non-zero on all 3 axes.

Someone at work suggested I use glLookAt, but I don't think this answers my problem, as the first three parameters (location of eye point) are exactly the numbers I'm trying to calculate.

Any help is tremendously appreciated!

Thanks
JemBot

Funkapotamus

Take a look at the code I posted here: http://lwjgl.org/forum/viewtopic.php?t=1182

You don't need to worry about calculating everything.  Just give the camera a position in space, a random direction to point it in, and set it's up vector to (0, 1, 0) as that's typically "up" in most 3d worlds.

If you want the camera to point in a specific direction or look at a particular thing when it loads- just set the target vector to that entity's position.  You don't have to deal with angles at all using this approach.

Fool Running

Are you trying to position your camera in relationship to a specific point? If you want the camera to just be at a point in space, then gluLookAt() is what you want.
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

JemBot

Thanks guys.

It's the input to glLookAt that I need to determine - location of the eye. My camera has speed and a vector. Each time I need to recalculate its position along the vector.

I think I've nutted my problem, but I haven't had a chance to code it yet. I was calculating a new point on the Y plane, then shifting on the Y axis by the correct amount. This means I was effectively mapping a new point on the edge of a cylinder, not a sphere.

My new approach will be:
    Use X plane to determine position on Y axis
    Determine radius of the crosscentre at this point (this is the bit I was missing)
    Determine X & Z positions on the crosscentre using the Y plane.

It makes sense in my head. I'll put some code here when I create it. I realise I should probably reuse other people's solutions, but this has become a bit of a challenge for me now.

Funkapotamus, thanks for the link to your snippet. I'll peruse that too when I can break from work.

Cheers
JemBot

JemBot

Funk, how do you determine the target? If I had a target I could use your approach. But all I have is a vector. Determining a target along a vector is exactly the problem I'm trying to solve.

JemBot

I think this is what I've been trying to figure out...

       double y = Math.sin(headingPlaneX * PI_OVER_180);
        double modifier = Math.cos(headingPlaneX * PI_OVER_180);
        double x = modifier * Math.sin(headingPlaneY * PI_OVER_180);
        double z = modifier * Math.cos(headingPlaneY * PI_OVER_180);
        
        // target is a double[], length = 3, and is used to store the camera's position at the next iteration
        target [0] += x;
        target [1] += y;
        target [2] += z;


Effectively giving me 1 unit of movement in any direction I happen to be facing (as recorded by the two angles, headingPlaneY and headingPlaneX).

Does this make sense to people?
Does it finally explain what I was trying to do? (Calcuate the 'target' parameter for the glLookAt function)
Is there a better way to do this?
Is it broken in any way?

Cheers
Jem

Fool Running

The best way is to rotate a point arount the orgin and then translate it to the location that you want

   /**
     * Rotates the specified Vector3f around the x-axis by the specified angle
     * @param  point The Vector3f to rotate
     * @param  angle The angle (in degrees) to rotate the Vector3f
     */
    private static void pitch(final Vector3f point, final float angle){
        final float yTemp = point.y * getCosValue(angle) + point.z * getSinValue(angle);
        point.z = point.z * getCosValue(angle) - point.y * getSinValue(angle);
        point.y = yTemp;
    }

and
   /**
     * Rotates the specified Vector3f around the y-axis by the specified angle
     * @param  point The Vector3f to rotate
     * @param  angle The angle (in degrees) to rotate the Vector3f
     */
    private static void yaw(final Vector3f point, final float angle){
        final float xTemp = point.x * getCosValue(angle) - point.z * getSinValue(angle);
        point.z = point.x * getSinValue(angle) + point.z * getCosValue(angle);
        point.x = xTemp;
    }

so you would call it like this:
Vector3f point = new Vector3f(1.0f, 0.0f, 0.0f);
pitch(point, headingPlaneX);
yaw(point, headingPlaneY);
target[0] += point.x;
target[1] += point.y;
target[2] += point.z;

(I think that will work)  :roll:
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Funkapotamus

Just randomly give it a target.  It doesn't matter really.  Try (0, 1, 0) for the target.  Close your eyes and spin around so fast you land on the floor, then get up and open your eyes- there's your target.  

Once your world content gets underway you can do more things such as spawning the camera while looking at a particular wall.  

To be crafty, if you don't know what coordinates your object is you want to look at-, give your camera a random target, then run the game.  Manually move the camera to look at the spot you desire.  Then have it spit out the current target vector (System.out or something)- use this as your target vector the next time you run your game.

So basically:  

Camera.setOrigin(new Vector3df(0, 0, 0), new Vector3df(0, 1, 0), new Vector3df(0, 1, 0));

Then look at the spot you want, record the xyz of the target vector and use that as the value you init setOrigin() with.