Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Rotating camera around an object


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
17 replies to this topic

#1 Hachaso77   Members   -  Reputation: 231

Like
0Likes
Like

Posted 27 February 2013 - 05:30 PM

I've been searching the web and can't find any good tutorial or example of how to rotate the camera around an object.

 

Imagine having an object in the center and the camera should rotate around it so it looks like the object itself is rotating.

 

How is this done ?

 

Please explain in detail because I'm really new at this.  Code would really help out.

 

Thanks :-)



Sponsor:

#2 ifthen   Members   -  Reputation: 820

Like
0Likes
Like

Posted 27 February 2013 - 05:36 PM

Well... I am certainly not an oracle, so... Are you talking about 2D or 3D? Which programming language are you using and which graphics library/engine?



#3 slicer4ever   Crossbones+   -  Reputation: 3943

Like
1Likes
Like

Posted 27 February 2013 - 05:52 PM

look up gluLookAt(assuming 3D)

 

you'll need to update the eye position as you move around a circle, like so:

 

float Theta = 0.0f;
float Distance = 20.0f;
while(!Done){
  gluLookAt(cosf(Theta)*Distance, 0.0f, sinf(Theta)*Distance, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
 Theta+=M_PI*0.01f; //move at a slow pace.
 
}

 

of course, you'll have to figure out where to integrate this into your code base=-)


Edited by slicer4ever, 27 February 2013 - 05:52 PM.

Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

#4 Hachaso77   Members   -  Reputation: 231

Like
0Likes
Like

Posted 27 February 2013 - 05:52 PM

I'm using C++, using Gameplay3D engine.

 

I found these operations to be used in Gameplay3D but don't know how to apply them to get the correct effect.

Any help would be appreciated.

 

 

float dt = elapsedTime / 1000.0f;


    Node* carNode = _scene->findNode("Board");


    Node *cameraNode = _scene->getActiveCamera()->getNode();


    Vector3 carPosition(carNode->getTranslation());


    Vector3 commandedPosition(carPosition + Vector3::unitY()*4.0f - carNode->getBackVector()*10.0f);


    cameraNode->translateSmooth(commandedPosition, dt, 0.2f);


    Matrix m;


    Matrix::createLookAt(cameraNode->getTranslation(), carPosition, Vector3::unitY(), &m);


    m.transpose();


    Quaternion q;


    m.getRotation(&q);


    cameraNode->setRotation(q);

 

 

I know that the code above doesn't solve my problem but I guess it helps to maybe get the solution.



#5 Hachaso77   Members   -  Reputation: 231

Like
0Likes
Like

Posted 27 February 2013 - 05:53 PM

What is M_PI ?

 

Is this maybe just PI = 3.14......


Edited by Hachaso77, 27 February 2013 - 05:56 PM.


#6 Hachaso77   Members   -  Reputation: 231

Like
0Likes
Like

Posted 27 February 2013 - 06:13 PM

static float Theta = 0.0f;
    float Distance = 20.0f;
    Node *boardNode = _scene->findNode("Board");
    Node *cameraNode = _scene->getActiveCamera()->getNode();
    Vector3 upY(0.0f, 1.0f, 0.0f);
    Matrix m;
    Matrix::createLookAt(cosf(Theta)*cameraNode->getTranslation(), sinf(Theta)*boardNode->getTranslation(), upY, &m);
    Theta += 3.14*0.01f;
    Quaternion q;
    m.getRotation(&q);
    cameraNode->setRotation(q); 

 

I gave it a try using Gameplay3D. Having a look at the code GluLookAt.  But I can't get it to work  properly. 


Edited by Hachaso77, 27 February 2013 - 06:13 PM.


#7 IkarusDowned   Members   -  Reputation: 291

Like
0Likes
Like

Posted 27 February 2013 - 08:12 PM

first of all, do you have a mental-model for what you are trying to do? Without at least understanding that, no amount of code will help you.

What you are essentially trying to do is rotate an object around a point. in this case, the object is the camera, and the point is some item's location.

 

each object, including your camera, should have some way of specifying both location and direction (usually in the form of vectors).

 

Armed with these, some basic math:

you can make a vector from the point you want to rotate around to the camera (camera's coordinates - point you want to rotate around).

Once you have this, you can do some matrix math (or quaternions or whatever) to rotate that vector some X degrees. This will give you a resultant vector which points in the direction you want your object to be in. be scaling this to the length of the original vector, you get the exact coordinates you want to move the camera to. So...translate the camera to that point!

 

Ok, that's half the problem. You now know how to move the camera to the spot you want, but it is still facing the ORIGINAL direction. so how do we rotate the camera?

well, if you take the vector you made above for translation (the end-result vector) and reverse it, you now have a vector pointing in the direction you want to be looking. using the components from this vector, you can get the amount you need to rotate the Camera's x, y, z DIRECTION vectors by to rotate it. Again, do your matrix math (or quaternion or whatever) to rotate these vectors (and thus the camera) around its local origin (or, translate first to the origin and then rotate, and translate back).

 

on a fundamental level, the above is one way to think about it. I make no claim that it is fastest / best (in fact, i'm a bit rusty so might even be wrong?)

once you have these fundamentals in hand I think it will be a lot easier for you since the rest is mostly lining up the right function calls...



#8 IkarusDowned   Members   -  Reputation: 291

Like
0Likes
Like

Posted 27 February 2013 - 08:15 PM

also here's a nice note on the subject

http://stackoverflow.com/questions/786293/opengl-rotate-around-a-spot

 

maybe that is easier for you to understand?



#9 Hachaso77   Members   -  Reputation: 231

Like
0Likes
Like

Posted 28 February 2013 - 07:07 AM

Thanks all for the help.

The theory sounds really good and interesting but the actual programming part is what is missing. 

Too bad that it seems to be so hard to find practical examples or tutorial regarding this problem.

 

Someone told me also that there is the old way of doing things using older versions of OpenGL and then there's the more recent method, meaning that you have to do the actual Matrix math. I assume the later part is what I need practical examples of.



#10 BCullis   Crossbones+   -  Reputation: 1813

Like
0Likes
Like

Posted 28 February 2013 - 09:49 AM

The theory sounds really good and interesting but the actual programming part is what is missing.

Too bad that it seems to be so hard to find practical examples or tutorial regarding this problem.

That's the part that you do yourself as a programmer.  Thinly veiled "just give me the code" request, anyone?

 

The latest code you posted is confused at best.  createLookAt creates a view matrix.  It does not, in any way, represent the rotation/orbit you're seeking.

 

The object you're rotating around has its own translation, a point in worldspace.  That will always be the target of your lookAt function.

All you need to do is calculate a matrix for rotating the camera's translation around the car's translation.  Calling lookAt with an origin of the camera's (updated) location and a target of the car's location will orient your camera's view matrix correctly.

 

To rotate an object around a point in space, you have to do two things:

  • treat that point as the origin
  • determine what axis you're rotating around 

 

The first bullet is what the translate calls are for in the stackoverflow link Ikarus posted.  Gameplay3D has Matrix::translate, so you're good there.  Let's assume you just want to rotate around a universal "vertical" axis, so a Y axis running through the car.  Matrix multiplication for the camera's position would then use

Matrix::translate(the opposite/negative version of the car's position)

Matrix::createRotationY(to rotate a set number of degrees around the Y axis...assuming the Y axis is "up" in your game)

Matrix::translate again (this time pushing the rotated camera back to it's relative location near the car)

 

The result of these three operations can be multiplied together (in the correct order, I'm always bad about remembering matrix multiplication order, whether it's backwards or forwards) and applied to the camera's position to rotate around the target.

 

Arguments to your Matrix::createLookAt function shouldn't change.  The camera will always want to "look at" the same target from its own position.


Edited by BCullis, 28 February 2013 - 09:51 AM.

Hazard Pay :: FPS/RTS in SharpDX
DeviantArt :: Because right-brain needs love too

#11 Hachaso77   Members   -  Reputation: 231

Like
0Likes
Like

Posted 28 February 2013 - 05:48 PM

I have this code that almost solves my problem. The problem I see now is that it rotates around my object but gets gradually closer to the center of the object. Meaning that the distance from the camera to the object gets smaller which is wrong. I want the camera to always have the same distance.

 

 

What am I doing wrong here?

 

Here is the code

 




void PegSolitaire::update(float elapsedTime)
{
    Node *eye_node = _scene->getActiveCamera()->getNode();
    Node *target_node = _scene->findNode("Board");
    Vector3 up(0.0f, 1.0f, 0.0f);
    
    eye_node->setTranslationX(eye_node->getTranslationZ() * sinf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f)) + eye_node->getTranslationX() * cosf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f)));
    eye_node->setTranslationY(eye_node->getTranslationY());
    eye_node->setTranslationZ(eye_node->getTranslationZ() * cosf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f)) - eye_node->getTranslationX() * sinf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f)));



void PegSolitaire::lookAt(Node* node, const Vector3& eye, const Vector3& target, const Vector3& up)
{
    // Create lookAt matrix
    Matrix matrix;
    Matrix::createLookAt(eye, target, up, &matrix);
    matrix.invert();
    
    // Pull SRT components out of matrix
    Vector3 scale;
    Quaternion rotation;
    Vector3 translation;
    matrix.decompose(&scale, &rotation, &translation);
    
    // Set SRT on node
    node->setScale(scale);
    node->setTranslation(translation);
    node->setRotation(rotation);
}


#12 slicer4ever   Crossbones+   -  Reputation: 3943

Like
0Likes
Like

Posted 28 February 2013 - 06:08 PM

void PegSolitaire::update(float elapsedTime)
{
    Node *eye_node = _scene->getActiveCamera()->getNode();
    Node *target_node = _scene->findNode("Board");
    Vector3 up(0.0f, 1.0f, 0.0f);
    
    eye_node->setTranslationX(eye_node->getTranslationZ() * sinf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f)) + eye_node->getTranslationX() * cosf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f)));
    eye_node->setTranslationY(eye_node->getTranslationY());
    eye_node->setTranslationZ(eye_node->getTranslationZ() * cosf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f)) - eye_node->getTranslationX() * sinf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f)));


why are you multiplying by your eyeNode's current z/x(and adding the results?)?

 

think about it, the values are changing constantly, so you are going to end up at different distances from the object, just do:

 

 

  float DistanceFromCube = 20.0f;
  Node *eye_node = _scene->getActiveCamera()->getNode();
Node *target_node = _scene->findNode("Board");
Vector3 up(0.0f, 1.0f, 0.0f);

eye_node->setTranslationX(cosf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f))*DistanceFromCube);
eye_node->setTranslationY(eye_node->getTranslationY()); //this line is redundant, can can be removed, but keeping it for clarity sake.
eye_node->setTranslationZ(sinf(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f))*DistanceFromCube);

Edited by slicer4ever, 28 February 2013 - 07:20 PM.

Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

#13 IkarusDowned   Members   -  Reputation: 291

Like
0Likes
Like

Posted 28 February 2013 - 07:10 PM

The theory sounds really good and interesting but the actual programming part is what is missing. 

Too bad that it seems to be so hard to find practical examples or tutorial regarding this problem.

 

 

its not, actually. i linked an article for you immediately after my first post. 

Also, this is not "theory," what i gave you was a practical technique. Theory would have been trying to explain how you can do N-dimensional rotations and translations using Matrix math...

As it has been noted, you are asking just for code but even if we give it to you, how will you know what to change to make it work for you, when you haven't fully understood the concepts?

 

Thanks @ BCullis and slicer4ever for their responses, as well


Edited by IkarusDowned, 28 February 2013 - 07:11 PM.


#14 Nusakan   Members   -  Reputation: 444

Like
0Likes
Like

Posted 28 February 2013 - 09:56 PM

IMPORTANT TO NOTE that I am using Row Matrix order. so multiplication of matrices happens as its written (left to right). So Make sure that you transpose your matrix before you multiplying with Model Matrices.



 

I hated the fact that the GLuLookAt() always limited me to level where I couldn't have full control of my camera. For this reason I implemented my own camera classes. I am going to assume that you want a third person camera that can  do rotation  about x (pitch) and y(yaw) axis.

Before going any further, let me remind you what is a model view matrix is. In OpenGL no such thing as camera matrix. its assumed as a matrix that lies at the origin with no rotation applied to it. In terms of 3D world, Model view matrix is a multiplication of a model matrix with the view matrix. hence unsurprisingly its been named as model-view matrix. Model matrix is as you may recall is the matrix that transforms the object into world space. Let me rephrase the fact that Model-view matrix in OpenGL is actually just Model matrix. However, its much more sensible to imagine this Model-View matrix as a product of Model matrix times the Identity matrix. Identity matrix does no transformation on the model matrix. We can think this identity matrix as a placement matrix to the camera matrix we going to create. I am going to go with full implementation first, then go through step by step explaining on whats happening.

Here comes the rather long code.

void ThirdPersonCamera::CalculateViewMatrix(mat3 modelRotation, vec3 modelPos)

{
mat4 cameraRotationMatrix; //holds the rotation of the camera.
mat3 invModelrotation; //inverted rotation matrix for models rotation
mat4 invModelTranslation; //inverted translation matrix for model's translation.

if(m_f_pitch_angle > 0.4f)
m_f_pitch_angle = 0.4f;
else if(m_f_pitch_angle < -0.4f) 
m_f_pitch_angle = -0.4f;

if(m_f_yaw_angle > TwoPi) m_f_yaw_angle = -TwoPi;
else if(m_f_yaw_angle < -TwoPi) m_f_yaw_angle += TwoPi;

m_fv3_right = fvec3(1.0f,0.0f,0.0f);
m_fv3_up = fvec3(0.0f, 1.0f, 0.0f);
m_fv3_direction = fvec3(0.0f,0.0f, 1.0f);

mat3 mat; //will hold arbitrary rotation temporarily

//rotate arbitrarily about the right base vector(x axis)
mat = mat.RotateArbitrary(m_f_pitch_angle, m_fv3_right);
m_fv3_up = m_fv3_up * mat; 
m_fv3_direction = m_fv3_direction * mat;

//rotate arbitrarily up base vector(y axis)
mat = mat.RotateArbitrary(m_f_yaw_angle, m_fv3_up);
m_fv3_right = mat * m_fv3_right;
m_fv3_direction = mat * m_fv3_direction;

//now we can create our base vectors for camera rotation matrix.
cameraRotationMatrix.x.x = m_fv3_right.x;
cameraRotationMatrix.x.y = m_fv3_right.y;
cameraRotationMatrix.x.z = m_fv3_right.z;

cameraRotationMatrix.y.x = m_fv3_up.x;
cameraRotationMatrix.y.y = m_fv3_up.y;
cameraRotationMatrix.y.z = m_fv3_up.z;

cameraRotationMatrix.z.x = m_fv3_direction.x;
cameraRotationMatrix.z.y = m_fv3_direction.y;
cameraRotationMatrix.z.z = m_fv3_direction.z;

//create local translation matrix that translates the camera at the given radius away from player
mat4 locTranslation = mat4::Translate(m_fv3_pos);

//create local rotation matrix that rotates the camera at the back of the player.
mat4 localRot = localRot.yRotate(180);

//we need to transform our view matrix into the object space of the model. To do this we need to get its inverse matrix
invModelrotation.x.x = modelRotation->x.x;
invModelrotation.x.y = modelRotation->x.y;
invModelrotation.x.z = modelRotation->x.z;

invModelrotation.y.x = modelRotation->y.x;
invModelrotation.y.y = modelRotation->y.y;
invModelrotation.y.z = modelRotation->y.z;

invModelrotation.z.x = modelRotation->z.x;
invModelrotation.z.y = modelRotation->z.y;
invModelrotation.z.z = modelRotation->z.z;

invModelrotation.Transpose();//inverse the rotation it should work since this is a matrix with orthogonal bases.

//inverse the translation
invModelTranslation.w.x = -modelPosition->x;
invModelTranslation.w.y = -modelPosition->y;
invModelTranslation.w.z = -modelPosition->z;


//now we can build our view matrix
m_viewMatrix = (invModelTranslation * invModelrotation) * (cameraRotationMatrix * (locTranslation * localRot));


}

 

Ok. Lets go step by step on whats going on here. first things that I do is making sure the pitch and yaw angles doesn't exceed a range. in this case I limit the pitch angle to 23 to -23 angle.this is the amount of rotation can be done about the x axis by user. Also made sure the yaw angle are in the range of 360 to -360 degree.
In addition to above, I made sure that my up, right and direction vectors are unit vectors and perpendicular to each other.

if(m_f_pitch_angle > 0.4f)
m_f_pitch_angle = 0.4f;
else if(m_f_pitch_angle < -0.4f) 
m_f_pitch_angle = -0.4f;

if(m_f_yaw_angle > TwoPi) m_f_yaw_angle = -TwoPi;
else if(m_f_yaw_angle < -TwoPi) m_f_yaw_angle += TwoPi;

m_fv3_right = fvec3(1.0f,0.0f,0.0f);
m_fv3_up = fvec3(0.0f, 1.0f, 0.0f);
m_fv3_direction = fvec3(0.0f,0.0f, 1.0f);

 

Now we need to generate a matrix that defines the orientation of or camera which going to be relative to the object we going to attach the camera.

//rotate arbitrarily about the right base vector(x axis)
mat = mat.RotateArbitrary(m_f_pitch_angle, m_fv3_right);
m_fv3_up = m_fv3_up * mat; 
m_fv3_direction = m_fv3_direction * mat;

//rotate arbitrarily up base vector(y axis)
mat = mat.RotateArbitrary(m_f_yaw_angle, m_fv3_up);
m_fv3_right = mat * m_fv3_right;
m_fv3_direction = mat * m_fv3_direction;

//now we can create our base vectors for camera rotation matrix.
cameraRotationMatrix.x.x = m_fv3_right.x;
cameraRotationMatrix.x.y = m_fv3_right.y;
cameraRotationMatrix.x.z = m_fv3_right.z;

cameraRotationMatrix.y.x = m_fv3_up.x;
cameraRotationMatrix.y.y = m_fv3_up.y;
cameraRotationMatrix.y.z = m_fv3_up.z;

cameraRotationMatrix.z.x = m_fv3_direction.x;
cameraRotationMatrix.z.y = m_fv3_direction.y;
cameraRotationMatrix.z.z = m_fv3_direction.z;

 

We are not over with the orientation of the camera yet. so far we calculated camera orientation based on what the pitch and yaw angles were. these values can be passed as part of user interaction when the player wants to move the camera. We need to now consider the displacement (or distance if you prefer) from the player. Also we want to create a rotation matrix that rotates the camera at the back of the object we want to attach to. so lets sort these out too.

//create local translation matrix that translates the camera at the given displacement  from attached model.
//Note that displacement is just there to tell us the location of the camera relative to the attached model.
mat4 locTranslation = mat4::Translate(m_fv3_displacement); 

//create local rotation matrix that rotates the camera at the back of the player.
mat4 localRot = localRot.yRotate(180);

 

Ok. So far so good. The next thing we want to do is to make this camera relative to the object we are attaching it to. We want this camera to be in an object space of an object. so this means that we need to transform our camera into the object space of the object we want to attach it to. The transformation matrix we need for this to happen is that the inverse Model matrix of the object. Thus we need to figure out this transformation matrix.
 

//we need to transform our view matrix into the object space of the model. To do this we need to get its inverse matrix
invModelrotation.x.x = m_modelRotation->x.x;
invModelrotation.x.y = m_modelRotation->x.y;
invModelrotation.x.z = m_modelRotation->x.z;

invModelrotation.y.x = m_modelRotation->y.x;
invModelrotation.y.y = m_modelRotation->y.y;
invModelrotation.y.z = m_modelRotation->y.z;

invModelrotation.z.x = m_modelRotation->z.x;
invModelrotation.z.y = m_modelRotation->z.y;
invModelrotation.z.z = m_modelRotation->z.z;

invModelrotation.Transpose();//inverse the rotation it should work since this is a matrix with orthogonal bases.

//inverse the translation
invModelTranslation.w.x = -modelPosition->x;
invModelTranslation.w.y = -modelPosition->y;
invModelTranslation.w.z = -modelPosition->z;

and finally we need to calculate the view matrix of the camera. this is the matrix we will be using it to multiply model matrices of every objects on the scene.

 

//now we can build our view matrix
m_viewMatrix = (invModelTranslation * invModelrotation) * (cameraRotationMatrix * (* localRot * locTranslation));

 

So reading from left to right.  if we multiply a model matrix with this view matrix this is what will happen.

first, it will translate the object space of the model the camera attached.

then it will rotate to the attached model's orientation.

(invModelTranslation * invModelrotation).

 

next the model matrix will be transformed in to the camera space that is relative to the object space we attached the camera at. 

 

PS: Im sure there is much efficient ways to this. However, for demonstration purpose I ignored many of them so that its easier to understand.


Edited by Nusakan, 28 February 2013 - 11:05 PM.


#15 Hachaso77   Members   -  Reputation: 231

Like
0Likes
Like

Posted 01 March 2013 - 02:21 AM

slicer4ever   - your solution did not work.

The Camera does not rotate at all. Strange.



#16 Hachaso77   Members   -  Reputation: 231

Like
0Likes
Like

Posted 01 March 2013 - 03:48 AM

I think the problem with my code is that the angle is not correct.

If it would be in degrees I assume it has to go from 0 - 359 and then start over from 0.

Is this correct ?



#17 slicer4ever   Crossbones+   -  Reputation: 3943

Like
0Likes
Like

Posted 01 March 2013 - 03:54 AM

slicer4ever   - your solution did not work.

The Camera does not rotate at all. Strange.

what unit is elapsed time in?, since it's a float, i assume it's in seconds, you divide that by a thousand, and now your at 0.001 rotation per second, multiplying by 180 gets you up to 0.0180 degrees per second.

 

it's likely it's moving, but it's moving so slow, it'd take a long time to notice it.  remove the /1000.0f and see if that changes things.


Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

#18 Hachaso77   Members   -  Reputation: 231

Like
0Likes
Like

Posted 01 March 2013 - 04:09 AM

I did a printout to see the value of elapsedTime and this is what I get:

 

 

ELAPSEDTIME: 16.646652


ELAPSEDTIME: 16.205009


ELAPSEDTIME: 17.051243


ELAPSEDTIME: 16.993181


ELAPSEDTIME: 16.299908


ELAPSEDTIME: 16.303425


ELAPSEDTIME: 17.233307


ELAPSEDTIME: 16.547491


ELAPSEDTIME: 16.575792


ELAPSEDTIME: 17.165115


ELAPSEDTIME: 16.678785


ELAPSEDTIME: 16.308386


ELAPSEDTIME: 16.509289

 

 

So changing the code by removing the / 1000.0f doesn't help. It still flickers but stronger.

 

 

I gave this a try and this works.

 

static float angle = 0;

 

 

 

angle += (elapsedTime/1000.0f)*200;


    if( angle >= 359.99)


        angle = 0;

 

 

Then I use angle in the sinf and cosf.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS