1
\$\begingroup\$

I'm trying to get the basics of 3d with opengl 2.0(I know, I know, it's deprecated etc, etc. It's just for the sake of prototyping). I'm trying to get a cube on the screen which you can move around. I have rendered the cube, and I can navigate the "world"(black background with the colored cube). However, when I try to rotate the camera, and then move, the camera moves independently of the camera's direction. For example, I rotate 90 degrees to the left, then I press "w" and it looks like I'm strafing to the right. I use sdl2 to get keyboard input, and when the user presses a key, I increase deltaX, deltaY, deltaZ, rotationX and rotationY accordingly(that's right, no rotation around the z axis).

And the rendering occurs as follows:

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // Apply transformations
    glRotatef(rx, 1, 0, 0);
    glRotatef(ry, 0, 1, 0);
    glTranslatef(dx, dy, dz);

    // Draw each face with a different color
    glColor3f(1.0, 1.0, 0.0);
    glDrawArrays(GL_QUADS, 0, 4);
    glColor3f(1.0, 0.3, 0.4);
    glDrawArrays(GL_QUADS, 4, 4);
    glColor3f(0.0, 1.0, 0.5);
    glDrawArrays(GL_QUADS, 8, 4);
    glColor3f(1.0, 1.0, 1.0);
    glDrawArrays(GL_QUADS, 12, 4);
    glColor3f(0.3, 0.8, 0.0);
    glDrawArrays(GL_QUADS, 16, 4);
    glColor3f(0.0, 0.0, 1.0);
    glDrawArrays(GL_QUADS, 20, 4);

How can I do this?

EDIT: forgot to add, I would like to do this without glu. I don't like linking against a lot of libraries, especially when it's only to get a few functions.

EDIT2: I got forward movement to work using trigonometry like this:

case SDLK_w:
    posZ += (float)cos(rotY * M_PI / 180); // I use rotY * PI/180 to convert rotY to radians
    posX -= (float)sin(rotY * M_PI / 180);
    break;
case SDLK_s:
    posZ -= (float)cos(rotY * M_PI / 180);
    posX += (float)sin(rotY * M_PI / 180);

And now the only thing to add is strafing, which I thought would be something like this

case SDLK_a:
    posX += (float)sin(rotY * M_PI / 180) + (float)cos(rotY * M_PI / 180);
    posZ += (float)sin(rotY * M_PI / 180);
    break;
case SDLK_d:
    posX -= (float)sin(rotY * M_PI / 180) + (float)cos(rotY * M_PI / 180);
    posZ -= (float)sin(rotY * M_PI /180);
    break;

But it doesn't work, if you strafe when looking down the x axis, you move backwards in the z axis(wtf?)

Thanks!

EDIT3: Never mind, solved it by doing

case SDLK_a:
    posX += (float)cos(rotY * M_PI / 180);
    posZ += (float)sin(rotY * M_PI / 180);
    break;
case SDLK_d:
    posX -= (float)cos(rotY * M_PI / 180);
    posZ -= (float)sin(rotY * M_PI /180);
    break;

I don't know if this is the best way to do it, but it works. Thanks everyone for helping me!

\$\endgroup\$
  • \$\begingroup\$ Check out this question. It explains how the gluLookAt() function works. \$\endgroup\$ – user1118321 Jun 2 '15 at 2:50
  • \$\begingroup\$ I updated the question, I don't want to use glu, I would be linking against an extra library to get a few utilities \$\endgroup\$ – twkmz Jun 2 '15 at 2:58
  • \$\begingroup\$ Sorry if I wasn't clear. I wasn't suggesting using glu. The question above has the implementation of the gluLookAt() function in it. I was suggesting you can look at the implementation to get an idea of how to do what you're trying to do, if it would help. \$\endgroup\$ – user1118321 Jun 2 '15 at 3:00
  • \$\begingroup\$ How about you translate before rotating? \$\endgroup\$ – Panda Pajama Jun 2 '15 at 4:59
  • 1
    \$\begingroup\$ Unrelated comment: You should stop using deprecated opengl. \$\endgroup\$ – Gustavo Maciel Jun 2 '15 at 12:03
2
\$\begingroup\$

Now I would first suggest you use GLM, but you're using C (according to your tag) so probably not. The best math I suggest in that case is continual use of the sine and cosine functions.

My examples will require math.h

You will want to first store your camera's position (if you haven't already)

float horizontal = cos(pitch) * GetCameraForwardSpeed();
float x += cos(yaw) * horizontal;
float z -= sin(yaw) * horizontal;
float y += sin(pitch) * GetCameraYSpeed();
//if you wanted strafing, you need this
x -= sin(yaw) * GetCameraStrafeSpeed();
z += cos(yaw) * GetCameraStrafeSpeed();

If you are storing degree, you should use a function like this:

float ToRadians(float degree)
{
 const double PI_CONST = 3.14159265358979323846;
 return degree * PI_CONST/180;
}

and replace yaw and pitch with that.

You will probably want to apply a View and Projection matrix to the position of the other objects, but that is way too much to put as an answer, so I suggest reverse engineering the math in GLM's perspective and translate functions and searching through the examples on the use of these functions.

Note: I have stated a few advanced methods of getting the answer

\$\endgroup\$
  • \$\begingroup\$ that's just what I needed. I read a bi about trigonometry and got it to work, I'm still struggling with strafing. And about glm, I'm now using the programable pipeline and implemented all of the projection and modelview transformations on my own, as well as lookAt and a few others. check them out here \$\endgroup\$ – twkmz Jun 7 '15 at 18:31
1
\$\begingroup\$

You typically need to keep track of at least three vectors to be able to easily move a camera around a scene. You need a vector representing the direction you are facing (0,0,-1), one representing upwards (0,1,0) and one vector representing camera position.

After rotating the lookat vector you can then translate your position in the direction of the vector.

Afterwards you can easily construct the ModelView matrix using the three vectors.

See this tutorial to learn more. It may be slightly out of date in some regards but it is still very useful for beginners

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.