Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Look At implementation  (Read 3759 times)

0 Members and 1 Guest are viewing this topic.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Look At implementation
« on: July 11, 2011, 10:36:00 pm »
Alright per request for my engine I am going to implement a LookAt function for the camera. I can do it to a matrix but the problem that arises is that my rotation vector will be wrong, it won't get the new values from the LookAt operation.

Is there anyone here that knows how to do a LookAt with just a rotation vector?

Here's my code so far:
Code: [Select]
void GGE::Interface::Camera::LookAt( const Vector3f aCenter, const Vector3f aUp )
{
Vector3f forward = (aCenter - myPosition).Normalize();
Vector3f side = forward.Cross( aUp.Normalize() );
Vector3f up = side.Cross( forward );
SetRotation( /* This is what I don't know? */ );
}


I can apply those 3 vectors to a matrix but like I said then GetRotation won't return the right rotation. So how do I combine these to one rotation vector? I thought I was close when I multiplied them together, but that always resulted in a zero vector.

I am no math brain, so I am having a really hard time figuring this by myself. Any pointers would be nice.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Look At implementation
« Reply #1 on: July 11, 2011, 11:11:12 pm »
Quote from: "Groogy"
Is there anyone here that knows how to do a LookAt with just a rotation vector?
What do you understand by "rotation vector"? You cannot store a general rotation in 3D space in a single vector.

Is it the direction vector of the camera? Then, it can be computed as target position - camera position. Or do you mean the triple (yaw, pitch, roll) in degrees?

Quote from: "Groogy"
I thought I was close when I multiplied them together, but that always resulted in a zero vector.
How did you multiply them? The dot product of perpendicular vectors is zero (scalar value, no zero vector).
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Look At implementation
« Reply #2 on: July 11, 2011, 11:19:27 pm »
No matter how you build your rotation matrix, you can always extract rotations (in your preferred way) -- if the matrix is still a rotation matrix of course.

You may also have a look at quaternions, they are usually more convenient (and cheaper) for manipulating rotations -- typically for cameras.

For formulas & maths stuff about matrices and quaternions, check the "Matrix and Quaternion FAQ".
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Look At implementation
« Reply #3 on: July 12, 2011, 12:17:56 am »
This is how the orientation is created for camera in the engine Nexus. As you can see a rotation matrix is created from a single vector. That vector is what you get from the GetRotation() function. It works the same for the camera. So I need to set that vector so the camera faces the point specified in the LookAt function.
Code: [Select]

Matrix33f rotation = Matrix33f::CreateRotateAroundX( myRotation.x );
rotation = Matrix33f::CreateRotateAroundY( myRotation.y ) * rotation;
rotation = Matrix33f::CreateRotateAroundZ( myRotation.z ) * rotation;
myOrientation.SetRotation( rotation );
myOrientation.SetPosition( myPosition );
myOrientation.SetScale( myScale );


Quote from: "Laurent"
No matter how you build your rotation matrix, you can always extract rotations (in your preferred way) -- if the matrix is still a rotation matrix of course.

So how would I do that from:
Code: [Select]
void GGE::Interface::Camera::LookAt( const Vector3f aCenter, const Vector3f aUp )
{
   Vector3f forward = (aCenter - myPosition).Normalize();
   Vector3f side = forward.Cross( aUp.Normalize() );
   Vector3f up = side.Cross( forward );
   Matrix33f rotation;
   // ... Set x rotation to side, y rotation to up and z rotation to -forward ... Already know how to do this
   SetRotation( /* This is what I don't know? */ );
}

UPDATE: Nevermind, I'll post what I think is correct from the FAQ you mentioned and then you can say if it's good or not ^^
Otherwise I don't learn.

Or should I just change it so the engine stores a rotation matrix instead of a vector? I felt that the vector would be simpler to work against. So the creation becomes instead:
Code: [Select]
myOrientation.SetRotation( myRotation );
myOrientation.SetPosition( myPosition );
myOrientation.SetScale( myScale );
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Look At implementation
« Reply #4 on: July 12, 2011, 02:06:40 am »
Alright seems to be working like it should. Though after following the FAQ it seemed like I got the inversion of the rotation. Might be that I handle camera space wrong or something, or since it is camera space I have to invert it to get it right. Anyway I just inverted the vector before setting it and it worked just fine.

Code: [Select]
void GGE::Graphics::Camera::SetRotationMatrix( const Matrix33f &aRotation )
{
Vector3f angles = Vector3f::Zero;
angles.y = asin( aRotation.myData[ INDEX3( 2, 0 ) ] );
float c = cos( angles.y );
if( fabs( c ) > 0.005f )
{
float tempX = aRotation.myData[ INDEX3( 2, 2 ) ] / c;
float tempY = -aRotation.myData[ INDEX3( 2, 1 ) ] / c;
angles.x = atan2( tempY, tempX );
tempX = aRotation.myData[ INDEX3( 0, 0 ) ] / c;
tempY = -aRotation.myData[ INDEX3( 1, 0 ) ] / c;
angles.z = atan2( tempY, tempX );
}
else
{
angles.x = 0;
float tempX = aRotation.myData[ INDEX3( 1, 1 ) ];
float tempY = aRotation.myData[ INDEX3( 0, 1 ) ];
angles.z = atan2( tempY, tempX );
}
SetRotation( angles * -1 );
}

void GGE::Graphics::Camera::LookAt( const Vector3f aCenter, const Vector3f aUp )
{
Vector3f forward = (aCenter - myPosition).Normalize();
Vector3f side = forward.Cross( aUp.Normalize() );
Vector3f up = side.Cross( forward );
Matrix33f rotation;
rotation.myData[ INDEX3( 0, 0 ) ] = side.x;
rotation.myData[ INDEX3( 1, 0 ) ] = side.y;
rotation.myData[ INDEX3( 2, 0 ) ] = side.z;
rotation.myData[ INDEX3( 0, 1 ) ] = up.x;
rotation.myData[ INDEX3( 1, 1 ) ] = up.y;
rotation.myData[ INDEX3( 2, 1 ) ] = up.z;
rotation.myData[ INDEX3( 0, 2 ) ] = -forward.x;
rotation.myData[ INDEX3( 1, 2 ) ] = -forward.y;
rotation.myData[ INDEX3( 2, 2 ) ] = -forward.z;
SetRotationMatrix( rotation );
}


Do you see anything Laurent you think should be improved? Maybe even know why the vector is inverted. Also if you see anything in my interface/API you feel should be changed then just let me know. My engine is still in alpha stage so I love any comments I can get.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio