Jump to content
  • Advertisement
Sign in to follow this  
Toolmaker

OpenGL Understanding camera basics...

This topic is 3809 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'm currently learning OpenGL using the NeHe tutorials. I'm currently up to lesson 10, but I'm having some trouble understand the whole deal around the camera. It says: 1. Rotate and translate the camera position according to user commands 2. Rotate the world around the origin in the opposite direction of the camera rotation (giving the illusion that the camera has been rotated) 3. Translate the world in the opposite manner that the camera has been translated (again, giving the illusion that the camera has moved). I don't completely understand 2 and 3. 1 is updating the camera according to user input, ie. move 1 unit forward, rotate to 90 degrees. But what about 2 and 3? And why is it done like that? I want to understand WHY I have to do it. I also want to move away from doing translations/rotations by doing it the hard way, and therefor I want to switch to the use of matrices. What would be good material to dive into for that? Thank you. Toolmaker

Share this post


Link to post
Share on other sites
Advertisement
I also dislike that method of doing cameras.
My cameras work via matrices, and are API agnostic. Put simply, my camera system is a position and a direction. To move the camera forwards, I add the direction * distance to the position. To rotate the camera, I use euler rotation.

To apply the camera to my renderer, I pass it in via a set method, and the renderer then uses it with gluLookAt(___), and gluPerspective(___). There are no graphics API calls inside the camera class. the result of thsi is that I can give cameras to entities such as characters, and even physics objects, with some pretty sick results.

I trust you are familiar with euler rotation? It makes life a whole lot easier where cameras are concerned.

Would you like more details?

[update] While I recommend you start by writing your own and then upgrade to a better one later, I currently use vmath.

[Edited by - shotgunnutter on January 14, 2008 11:22:49 AM]

Share this post


Link to post
Share on other sites
You should definitely look here at some point, but the explanations there are not as beginner friendly as they could be, so I'll try to explain this as best as I can.

Obviously there is no actual camera in the world, but we want to achieve the effect of a camera that we can move and orient. How can we do this?

Suppose we have a scene with just one object, and the camera is looking directly at it. Moving the camera 1 unit forward (suppose forward means the negative Z-axis) will give the same result as moving the object 1 unit backward, the result being that the object is 1 unit closer to the camera. Similarly, rotating the camera 30 degrees to the left is the same as rotating the object 30 degrees to the right around the camera (so in this case 'orbiting' might be a better term than 'rotation').

After we understand this, we see that we can achieve the effect of a camera by properly translating and rotating the objects, but by negated distances and angles, and in reverse order so that the objects rotate around the camera's position and not around themselves. This last point requires understanding how applying transformations in a different order can affect the result. The section titled "Thinking About Transformations" in the link above covers this very well.

Of course, we might have more than one object in the scene, and we have to do this for all of them. Therefore, in your code, you specify the camera position and orientation before you specify any of the transformations for the objects. That way, any transformation you specify for the object will be combined with the camera-related transformations to simulate the effect of a movable camera (this point also requires that you understand how OpenGL transformations work and the material in the section I mentioned earlier).

Well, after reading my explanation, it's not as clear as I would have wanted it to be, but if you have any specific questions I'll try to explain further.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
You should definitely look here at some point, but the explanations there are not as beginner friendly as they could be, so I'll try to explain this as best as I can.

Obviously there is no actual camera in the world, but we want to achieve the effect of a camera that we can move and orient. How can we do this?

Suppose we have a scene with just one object, and the camera is looking directly at it. Moving the camera 1 unit forward (suppose forward means the negative Z-axis) will give the same result as moving the object 1 unit backward, the result being that the object is 1 unit closer to the camera. Similarly, rotating the camera 30 degrees to the left is the same as rotating the object 30 degrees to the right around the camera (so in this case 'orbiting' might be a better term than 'rotation').

After we understand this, we see that we can achieve the effect of a camera by properly translating and rotating the objects, but by negated distances and angles, and in reverse order so that the objects rotate around the camera's position and not around themselves. This last point requires understanding how applying transformations in a different order can affect the result. The section titled "Thinking About Transformations" in the link above covers this very well.

Of course, we might have more than one object in the scene, and we have to do this for all of them. Therefore, in your code, you specify the camera position and orientation before you specify any of the transformations for the objects. That way, any transformation you specify for the object will be combined with the camera-related transformations to simulate the effect of a movable camera (this point also requires that you understand how OpenGL transformations work and the material in the section I mentioned earlier).

Well, after reading my explanation, it's not as clear as I would have wanted it to be, but if you have any specific questions I'll try to explain further.


That explains it pretty well, but its a problematic way of handling OpenGL cameras, IMHO. I find that doing it via matrices is easier. YMMV.

[Edited by - shotgunnutter on January 14, 2008 11:51:17 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by shotgunnutter
its a problematic way of handling OpenGL cameras, IMHO. I find that doing it via matrices is easier.


The only way you could do it is with matrices (note that gluLookAt() also generates a matrix). How you create that matrix is up to you - you can use Euler angles and trigonometry, quaternions, etc., but at the end you have to create a matrix because that's all OpenGL understands. So even if you hide it behind a more convenient interface, my description above is the only way to achieve the effect of a camera.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
You should definitely look here at some point, but the explanations there are not as beginner friendly as they could be, so I'll try to explain this as best as I can.

Obviously there is no actual camera in the world, but we want to achieve the effect of a camera that we can move and orient. How can we do this?

Suppose we have a scene with just one object, and the camera is looking directly at it. Moving the camera 1 unit forward (suppose forward means the negative Z-axis) will give the same result as moving the object 1 unit backward, the result being that the object is 1 unit closer to the camera. Similarly, rotating the camera 30 degrees to the left is the same as rotating the object 30 degrees to the right around the camera (so in this case 'orbiting' might be a better term than 'rotation').

After we understand this, we see that we can achieve the effect of a camera by properly translating and rotating the objects, but by negated distances and angles, and in reverse order so that the objects rotate around the camera's position and not around themselves. This last point requires understanding how applying transformations in a different order can affect the result. The section titled "Thinking About Transformations" in the link above covers this very well.

Of course, we might have more than one object in the scene, and we have to do this for all of them. Therefore, in your code, you specify the camera position and orientation before you specify any of the transformations for the objects. That way, any transformation you specify for the object will be combined with the camera-related transformations to simulate the effect of a movable camera (this point also requires that you understand how OpenGL transformations work and the material in the section I mentioned earlier).

Well, after reading my explanation, it's not as clear as I would have wanted it to be, but if you have any specific questions I'll try to explain further.


Excellent explanation! That's pretty much what I wanted to know :). Now to brush up my matrix maths(I've had it, but I kinda forgot how to do it, so I'll have to look it up) and from there on, work further on my vector maths.

I'll give you a rate++ for the excellent explanation :). 1 question tho, all object movements should be relative to the camera in order to achieve a camera-like 'experience'. How does this affect other translations(I'll leave out rotations for now).

If I move my 'camera' to (0, 0, -10) and I have an object at (0, 0, -50) and another one at (10, 0, -50), do I need call glLoadIdentity(); -> do camera translation + object translation, or would it be best to calculate the relative position of object a to b and translate with that(ie, glTranslatef(10, 0, 0))?

Toolmaker

Share this post


Link to post
Share on other sites
Quote:
Original post by Toolmaker
Excellent explanation!


Glad you liked it :)

Quote:
Now to brush up my matrix maths(I've had it, but I kinda forgot how to do it, so I'll have to look it up) and from there on, work further on my vector maths.


You might want to look at the two sample chapters I linked to here. The first is a long chapter on vectors. You can probably skip some of it because at first it is important to understand the geometric meaning of vectors and their operations, so focus on that.

The second chapter is an excellent introduction to matrices, probably the best I have ever seen. It does a great job of explaining how to interpret matrices geometrically and not just as tables of numbers. It also emphasizes the important distinction between row vectors and column vectors. After reading this chapter, you'll want to look at the section titled "Thinking About Transformations" in the link in my first post to understand why this is especially when using OpenGL.

Quote:
If I move my 'camera' to (0, 0, -10) and I have an object at (0, 0, -50) and another one at (10, 0, -50), do I need call glLoadIdentity(); -> do camera translation + object translation, or would it be best to calculate the relative position of object a to b and translate with that(ie, glTranslatef(10, 0, 0))?


I'm not entirely sure I understand your question, but in general you don't have to think about the camera when moving your objects. You just know that it will work correctly. How do you know? Look at the following code:


void display() {
glLoadIdentity();

// Position camera at (0, 0, -10) so we translate by the negative units
glTranslatef(0, 0, 10);

// Position first object
glPushMatrix();
glTranslatef(0, 0, -50);
drawObjectA();
glPopMatrix();

// Position second object
glPushMatrix();
glTranslatef(10, 0, -50);
drawObjectA();
glPopMatrix();
}




The calls to glPush/glPop are needed when manipulating multiple objects (unless you want their transformations to be combined, but we'll forget about that for now). If you are not familiar with these calls, just pretend there's one object and you can ignore them (they are explained with nice examples in the link in my first post).

I don't want to go into too much detail (because you need to understand matrices to understand those details), but calls Like glTranslatef() combine their transformations with any transformations that were previously applied (EDIT - this is exactly why you call glLoadIdentity() at the start of each frame). In the code above, the camera related transformation was applied first, so any further transformations will be combined with it. So, we can just move our objects and be sure that they will move properly with relation to the camera, because the camera transform will be applied to them "automatically".

Again this turned out to be more confusing than I intended. I recommend that you first get comfortable with matrices, then with how transformations work in OpenGL (including the glPush/glPop functions). The sample chapter on matrices covers the former (to an extent), and the link in my first post covers the latter. Once you are comfortable with writing code that can move several objects independently with a fixed camera, come back to this post and see if what I said is somewhat clearer.

Hope this helps and sorry for the long post (again!).

[Edited by - Gage64 on January 15, 2008 1:54:57 AM]

Share this post


Link to post
Share on other sites
Thanks for the answers :). You're great at explaining it understandly. A skill which is extremely useful in our field.

I'm currently doing 2D vector math in my computer graphics class at college, so I do understand how most of the stuff works, except it has another added direction to it. And, I need to start brushing up my skills when it comes to matrices, because I need them at the exam.

For example, let's take this as our environment:


Ok, so now I want to move my camera 10 units towards the boxes. This would mean I have to translate the camera 10 units negatively on the z-axis(-10). Unless I want move all the objects, then I translate all the objects along the z-axis in +10 units.

In other words, the translation/rotation of the camera is always the inverse of the translation I would do the world. Perhaps I should stop trying to understand this all, without actually having seen all the maths and stuff.

Again, thanks a lot!

Toolmaker

Share this post


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

  • Advertisement
  • Advertisement
  • Popular Tags

  • Similar Content

    • By nOoNEE
      hello guys , i have some questions  what does glLinkProgram  and  glBindAttribLocation do?  i searched but there wasnt any good resource 
    • By owenjr
      Hi, I'm a Multimedia Engineering student. I am about to finish my dergree and I'm already thinking about what topic to cover in my final college project.
      I'm interested in the procedural animation with c++ and OpenGL of creatures, something like a spider for example. Can someone tell me what are the issues I should investigate to carry it out? I understand that it has some dependence on artificial intelligence but I do not know to what extent. Can someone help me to find information about it? Thank you very much.
       
      Examples: 
      - Procedural multi-legged walking animation
      - Procedural Locomotion of Multi-Legged Characters in Dynamic Environments
    • By Lewa
      So, i'm still on my quest to unterstanding the intricacies of HDR and implementing this into my engine. Currently i'm at the step to implementing tonemapping. I stumbled upon this blogposts:
      http://filmicworlds.com/blog/filmic-tonemapping-operators/
      http://frictionalgames.blogspot.com/2012/09/tech-feature-hdr-lightning.html
      and tried to implement some of those mentioned tonemapping methods into my postprocessing shader.
      The issue is that none of them creates the same results as shown in the blogpost which definitely has to do with the initial range in which the values are stored in the HDR buffer. For simplicity sake i store the values between 0 and 1 in the HDR buffer (ambient light is 0.3, directional light is 0.7)
      This is the tonemapping code:
      vec3 Uncharted2Tonemap(vec3 x) { float A = 0.15; float B = 0.50; float C = 0.10; float D = 0.20; float E = 0.02; float F = 0.30; return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F; } This is without the uncharted tonemapping:
      This is with the uncharted tonemapping:
      Which makes the image a lot darker.
      The shader code looks like this:
      void main() { vec3 color = texture2D(texture_diffuse, vTexcoord).rgb; color = Uncharted2Tonemap(color); //gamma correction (use only if not done in tonemapping code) color = gammaCorrection(color); outputF = vec4(color,1.0f); } Now, from my understanding is that tonemapping should bring the range down from HDR to 0-1.
      But the output of the tonemapping function heavily depends on the initial range of the values in the HDR buffer. (You can't expect to set the sun intensity the first time to 10 and the second time to 1000 and excpect the same result if you feed that into the tonemapper.) So i suppose that this also depends on the exposure which i have to implement?
      To check this i plotted the tonemapping curve:
      You can see that the curve goes only up to around to a value of 0.21 (while being fed a value of 1) and then basically flattens out. (which would explain why the image got darker.)
       
      My guestion is: In what range should the values in the HDR buffer be which then get tonemapped? Do i have to bring them down to a range of 0-1 by multiplying with the exposure?
      For example, if i increase the values of the light by 10 (directional light would be 7 and ambient light 3) then i would need to divide HDR values by 10 in order to get a value range of 0-1 which then could be fed into the tonemapping curve. Is that correct?
    • By nOoNEE
      i am reading this book : link
      in the OpenGL Rendering Pipeline section there is a picture like this: link
      but the question is this i dont really understand why it is necessary to turn pixel data in to fragment and then fragment into pixel could please give me a source or a clear Explanation that why it is necessary ? thank you so mu
       
       
    • By Inbar_xz
      I'm using the OPENGL with eclipse+JOGL.
      My goal is to create movement of the camera and the player.
      I create main class, which create some box in 3D and hold 
      an object of PlayerAxis.
      I create PlayerAxis class which hold the axis of the player.
      If we want to move the camera, then in the main class I call to 
      the func "cameraMove"(from PlayerAxis) and it update the player axis.
      That's work good.
      The problem start if I move the camera on 2 axis, 
      for example if I move with the camera right(that's on the y axis)
      and then down(on the x axis) -
      in some point the move front is not to the front anymore..
      In order to move to the front, I do
      player.playerMoving(0, 0, 1);
      And I learn that in order to keep the front move, 
      I need to convert (0, 0, 1) to the player axis, and then add this.
      I think I dont do the convert right.. 
      I will be glad for help!

      Here is part of my PlayerAxis class:
       
      //player coordinate float x[] = new float[3]; float y[] = new float[3]; float z[] = new float[3]; public PlayerAxis(float move_step, float angle_move) { x[0] = 1; y[1] = 1; z[2] = -1; step = move_step; angle = angle_move; setTransMatrix(); } public void cameraMoving(float angle_step, String axis) { float[] new_x = x; float[] new_y = y; float[] new_z = z; float alfa = angle_step * angle; switch(axis) { case "x": new_z = addVectors(multScalar(z, COS(alfa)), multScalar(y, SIN(alfa))); new_y = subVectors(multScalar(y, COS(alfa)), multScalar(z, SIN(alfa))); break; case "y": new_x = addVectors(multScalar(x, COS(alfa)), multScalar(z, SIN(alfa))); new_z = subVectors(multScalar(z, COS(alfa)), multScalar(x, SIN(alfa))); break; case "z": new_x = addVectors(multScalar(x, COS(alfa)), multScalar(y, SIN(alfa))); new_y = subVectors(multScalar(y, COS(alfa)), multScalar(x, SIN(alfa))); } x = new_x; y = new_y; z = new_z; normalization(); } public void playerMoving(float x_move, float y_move, float z_move) { float[] move = new float[3]; move[0] = x_move; move[1] = y_move; move[2] = z_move; setTransMatrix(); float[] trans_move = transVector(move); position[0] = position[0] + step*trans_move[0]; position[1] = position[1] + step*trans_move[1]; position[2] = position[2] + step*trans_move[2]; } public void setTransMatrix() { for (int i = 0; i < 3; i++) { coordiTrans[0][i] = x[i]; coordiTrans[1][i] = y[i]; coordiTrans[2][i] = z[i]; } } public float[] transVector(float[] v) { return multiplyMatrixInVector(coordiTrans, v); }  
      and in the main class i have this:
       
      public void keyPressed(KeyEvent e) { if (e.getKeyCode()== KeyEvent.VK_ESCAPE) { System.exit(0); //player move } else if (e.getKeyCode()== KeyEvent.VK_W) { //front //moveAmount[2] += -0.1f; player.playerMoving(0, 0, 1); } else if (e.getKeyCode()== KeyEvent.VK_S) { //back //moveAmount[2] += 0.1f; player.playerMoving(0, 0, -1); } else if (e.getKeyCode()== KeyEvent.VK_A) { //left //moveAmount[0] += -0.1f; player.playerMoving(-1, 0, 0); } else if (e.getKeyCode()== KeyEvent.VK_D) { //right //moveAmount[0] += 0.1f; player.playerMoving(1, 0, 0); } else if (e.getKeyCode()== KeyEvent.VK_E) { //moveAmount[0] += 0.1f; player.playerMoving(0, 1, 0); } else if (e.getKeyCode()== KeyEvent.VK_Q) { //moveAmount[0] += 0.1f; player.playerMoving(0, -1, 0); //camera move } else if (e.getKeyCode()== KeyEvent.VK_I) { //up player.cameraMoving(1, "x"); } else if (e.getKeyCode()== KeyEvent.VK_K) { //down player.cameraMoving(-1, "x"); } else if (e.getKeyCode()== KeyEvent.VK_L) { //right player.cameraMoving(-1, "y"); } else if (e.getKeyCode()== KeyEvent.VK_J) { //left player.cameraMoving(1, "y"); } else if (e.getKeyCode()== KeyEvent.VK_O) { //right round player.cameraMoving(-1, "z"); } else if (e.getKeyCode()== KeyEvent.VK_U) { //left round player.cameraMoving(1, "z"); } }  
      finallt found it.... i confused with the transformation matrix row and col. thanks anyway!
    • By Lewa
      So, i'm currently trying to implement an SSAO shader from THIS tutorial and i'm running into a few issues here.
      Now, this SSAO method requires view space positions and normals. I'm storing the normals in my deferred renderer in world-space so i had to do a conversion and reconstruct the position from the depth buffer.
      And something there goes horribly wrong (which has probably to do with worldspace to viewspace transformations).
      (here is the full shader source code if someone wants to take a look at it)
      Now, i suspect that the normals are the culprit.
      vec3 normal = ((uNormalViewMatrix*vec4(normalize(texture2D(sNormals, vTexcoord).rgb),1.0)).xyz); "sNormals" is a 2D texture which stores the normals in world space in a RGB FP16 buffer.
      Now i can't use the camera viewspace matrix to transform the normals into viewspace as the cameras position isn't set at (0,0,0), thus skewing the result.
      So what i did is to create a new viewmatrix specifically for this normal without the position at vec3(0,0,0);
      //"camera" is the camera which was used for rendering the normal buffer renderer.setUniform4m(ressources->shaderSSAO->getUniform("uNormalViewMatrix"), glmExt::createViewMatrix(glm::vec3(0,0,0),camera.getForward(),camera.getUp())//parameters are (position,forwardVector,upVector) ); Though i have the feeling this is the wrong approach. Is this right or is there a better/correct way of transforming a world space normal into viewspace?
    • By HawkDeath
      Hi,
      I'm trying mix two textures using own shader system, but I have a problem (I think) with uniforms.
      Code: https://github.com/HawkDeath/shader/tree/test
      To debug I use RenderDocs, but I did not receive good results. In the first attachment is my result, in the second attachment is what should be.
      PS. I base on this tutorial https://learnopengl.com/Getting-started/Textures.


    • By norman784
      I'm having issues loading textures, as I'm clueless on how to handle / load images maybe I missing something, but the past few days I just google a lot to try to find a solution. Well theres two issues I think, one I'm using Kotlin Native (EAP) and OpenGL wrapper / STB image, so I'm not quite sure wheres the issue, if someone with more experience could give me some hints on how to solve this issue?
      The code is here, if I'm not mistaken the workflow is pretty straight forward, stbi_load returns the pixels of the image (as char array or byte array) and you need to pass those pixels directly to glTexImage2D, so a I'm missing something here it seems.
      Regards
    • By Hashbrown
      I've noticed in most post processing tutorials several shaders are used one after another: one for bloom, another for contrast, and so on. For example: 
      postprocessing.quad.bind() // Effect 1 effect1.shader.bind(); postprocessing.texture.bind(); postprocessing.quad.draw(); postprocessing.texture.unbind(); effect1.shader.unbind(); // Effect 2 effect2.shader.bind(); // ...and so on postprocessing.quad.unbind() Is this good practice, how many shaders can I bind and unbind before I hit performance issues? I'm afraid I don't know what the good practices are in open/webGL regarding binding and unbinding resources. 
      I'm guessing binding many shaders at post processing is okay since the scene has already been updated and I'm just working on a quad and texture at that moment. Or is it more optimal to put shader code in chunks and bind less frequently? I'd love to use several shaders at post though. 
      Another example of what I'm doing at the moment:
      1) Loop through GameObjects, bind its phong shader (send color, shadow, spec, normal samplers), unbind all.
      2) At post: bind post processor quad, and loop/bind through different shader effects, and so on ...
      Thanks all! 
    • By phil67rpg
      void collision(int v) { collision_bug_one(0.0f, 10.0f); glutPostRedisplay(); glutTimerFunc(1000, collision, 0); } void coll_sprite() { if (board[0][0] == 1) { collision(0); flag[0][0] = 1; } } void erase_sprite() { if (flag[0][0] == 1) { glColor3f(0.0f, 0.0f, 0.0f); glBegin(GL_POLYGON); glVertex3f(0.0f, 10.0f, 0.0f); glVertex3f(0.0f, 9.0f, 0.0f); glVertex3f(1.0f, 9.0f, 0.0f); glVertex3f(1.0f, 10.0f, 0.0f); glEnd(); } } I am using glutTimerFunc to wait a small amount of time to display a collision sprite before I black out the sprite. unfortunately my code only blacks out the said sprite without drawing the collision sprite, I have done a great deal of research on the glutTimerFunc and  animation.
  • Advertisement
  • Popular Now

  • Forum Statistics

    • Total Topics
      631383
    • Total Posts
      2999687
×

Important Information

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

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!