• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
BroderickCalpe

Rotating camera around an object

17 posts in this topic

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 :-)

0

Share this post


Link to post
Share on other sites

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?

0

Share this post


Link to post
Share on other sites

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
1

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites
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
0

Share this post


Link to post
Share on other sites

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...

0

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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
0

Share this post


Link to post
Share on other sites

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);
}
0

Share this post


Link to post
Share on other sites

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
0

Share this post


Link to post
Share on other sites

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
0

Share this post


Link to post
Share on other sites
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
0

Share this post


Link to post
Share on other sites

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 ?

0

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0