Jump to content
  • Advertisement
Sign in to follow this  
Wavesonics

LookAt() functionality for FPS (Euler Angle) Camera

This topic is 3154 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

[I had posted this in the Game Programming forum, but thought it might be better here] I have a FPS style camera that accumulates Euler angles, and works well. But now I want to implement a lookAt( Vector ) method which will take in a vector, and then calculate an absolute rotation in Euler Angles to aim the camera at that point in space. This is what I have so far:
    void lookAt( float x1, float y1, float z1 )
    {
        VectorR3 v( x1, y1, z1 );
        v.x = m_position.x - v.x;
        v.y = m_position.y - v.y;
        v.z = m_position.z - v.z;

        float r = v.length();
        float yaw = acos( v.z / r );
        float pitch = atan2( v.y, v.x );

        setRotation( yaw, pitch, 0.0f, true ); // This just wraps the values to ensure they stay within range
    }



Bbuutt... things aren't working. This is Cartesian Coordinate to Spherical coordinate conversion, or at least it's suppose to be. Does anything jump out as majorly wrong here?

Share this post


Link to post
Share on other sites
Advertisement
I'd think you'd want target - position, rather than position - target. Also, it looks like you might have yaw and pitch backwards. That is, it should be:
float pitch = acos( v.z / r );
float yaw = atan2( v.y, v.x );
Also, since acos() can fail if the input falls outside of the range [-1, 1] (e.g. due to numerical error), an (IMO) better way to compute the pitch is:
float length = sqrt(v.x*v.x+v.y*v.y);
float pitch = atan2(v.z, length);

Share this post


Link to post
Share on other sites
Ok so let me see if I get this right:

void lookAt( float x1, float y1, float z1 )
{
VectorR3 v( x1, y1, z1 );
v -= m_position;

float r = sqrt( v.x*v.x + v.y*v.y ); // I'm not suppose to take Z into account?
float yaw = atan2( v.y, v.x );
float pitch = atan2( v.z, r );

setRotation( yaw, pitch, 0.0f, true );
}





I'm not getting proper rotations with this.

Share this post


Link to post
Share on other sites
Quote:
Original post by Wavesonics
Ok so let me see if I get this right:
*** Source Snippet Removed ***

I'm not getting proper rotations with this.
Take another look at my example code (you're computing 'r' differently than what was shown).

But yeah, you don't need to include z there. Think about it this way. Take the vector to the target (v) and project it orthogonally onto the ground plane (call the projected vector v'). v and v' taken together form a right triangle. The length of one of the legs is |v'|, and the length of the other leg is v.z. The lengths of these edges are proportional to the cosine and sine (respectively) of the opposite angle, which means you can submit them directly to atan2(), as shown, to get the angle.

Ok, that wasn't a very good explanation, but maybe it'll be enough to give you the general idea...

Share this post


Link to post
Share on other sites
I had miss-typed and left out the sqrt() but fixed it, is that what you are referring to? Even with the sqrt() i'm still getting incorrect results though.

If there is something else amiss, i don't see it.

Share this post


Link to post
Share on other sites

inline float zeroClamp( float x )
{
return ( std::fabs(x) > std::numeric_limits<float>::epsilon() ? x : 0.0f );
}

inline float wrap( float a )
{
while( a >= RAD360 || a < 0.0f )
{
if(a >= RAD360 )
a -= RAD360;
else if( a < 0.0f )
a += RAD360;
}

return a;
}

void setRotation( float yaw, float pitch, float roll, bool isInRadians = false ) {

m_yaw = 0.0f;
m_pitch = 0.0f;
m_roll = 0.0f;

rotate( yaw, pitch, roll, isInRadians );
}

void rotate( float yaw, float pitch, float roll, bool isInRadians = false ) {

yaw = zeroClamp( yaw );
pitch = zeroClamp( pitch );
roll = zeroClamp( roll );

if( !isInRadians )
{
yaw = Rotation3D::deg2rad( yaw );
pitch = Rotation3D::deg2rad( pitch );
roll = Rotation3D::deg2rad( roll );
}

m_yaw += yaw;
m_yaw = wrap( m_yaw ); // Keep the angle between 0 and 360

m_pitch += pitch;
m_pitch = wrap( m_pitch );

m_roll += roll;
m_roll = wrap( m_roll );
}




[Edited by - Wavesonics on February 26, 2010 2:51:07 PM]

Share this post


Link to post
Share on other sites
Hi Wavesonics,

I tried the following code and it works; It's pretty much what jyk was suggesting, however I still post it. However here I explicitly assume a right-hand setting in which plane XZ is the ground and y-axis is the UP direction, which I think would be the case in a typical OpenGL setting.

The program outputs:

Pitch = -35
Yaw = 135

Which makes sense for the input.

Bye!


#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
{
float x1 = -1;
float y1 = -1;
float z1 = 3;

float position_x = 1;
float position_y = 1;
float position_z = 1;

float v_x = x1 - position_x;
float v_y = y1 - position_y;
float v_z = z1 - position_z;

float length = sqrt(v_x * v_x + v_z * v_z);
float pitch = atan2(v_y, length);
float yaw = atan2(v_z, v_x);

printf("Pitch = %d\n", (int)(180 * (pitch / 3.1415)));
printf("Yaw = %d\n", (int)(180 * (yaw / 3.1415)));

return 0;
}

Share this post


Link to post
Share on other sites
I don't see anything wrong with your code, after triple checking things. Are you sure the problem does not lie outside of this function?

For instance, you are using the yaw and pitch to rotate a vector (1, 0, 0) by first applying the pitch (rotation around Y), then the yaw (rotation around Z)? This vector should of course be added to your viewpoint to get your target point back.

And you are certain your Z axis is your up axis? If this would be Y, then you need to swap some coordinates and possibly place a - sign somewhere.

Share this post


Link to post
Share on other sites
Ah no my Z axis is not up, it's standard OpenGL coordinate system so -Z should be forward if I'm not mistaken, and +y is up.

Also how I'm applying the rotation is by generating a quaternion from the Euler Angles, then extracting a matrix from that (Just for convince at the moment).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!