Advertisement

sine&cosine

Started by August 09, 2002 12:03 PM
14 comments, last by branhield 22 years, 6 months ago
umm, if i translate it back, wont it move back to the center of the screen?
quote:
Original post by branhield
umm, if i translate it back, wont it move back to the center of the screen?

Nope. Here are some quick diagrams I hacked up to show the process:






Notice from image 3 that we can rotate the object as much as we want . It will spin around a lot, but won't leave its position centred on the origin. We can then move the shape back to its original place, regardless of how much rotation we've done.

Here's an example snippet of how you'd do a rotating triangle in-place with OpenGL:

  struct Vertex{    float x,y,z;};Vertex Triangle[] = {{ 2.4f, 1.0f, -6.0f},{ 3.0f, 1.0f, -6.0f},{ 2.4f, 2.0f, -6.0f} };float angle = 0.0f; // how much to rotatebool DrawGLScene{    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glLoadIdentity();    // Calculate the centre of the triangle    float CentreX = (Triangle[0].x + Triangle[1].x + Triangle[2].x) / 3.0f;    float CentreY = (Triangle[0].y + Triangle[1].y + Triangle[2].y) / 3.0f;    float CentreZ = (Triangle[0].z + Triangle[1].z + Triangle[2].z) / 3.0f;/* use gluLookAt or see the www.gametutorials.com camera lessons! *//* g_Camera->LookAtPosition(); */    glTranslatef(CentreX, CentreY, CentreZ);     // step 3: translate back again    glRotatef(angle, 0.0f, 0.0f, 1.0f);          // step 2: rotate wanted angle    glTranslatef(-CentreX, -CentreY, -CentreZ);  // step 1: translate to origin    glBegin(GL_TRIANGLES);        glColor3f(1.0f, 0.0f, 0.0f);        glVertex3f( Triangle[0].x, Triangle[0].y, Triangle[0].z);        glColor3f(0.0f, 1.0f, 0.0f);        glVertex3f( Triangle[1].x, Triangle[1].y, Triangle[1].z);        glColor3f(0.0f, 0.0f, 1.0f);        glVertex3f( Triangle[2].x, Triangle[2].y, Triangle[2].z);    glEnd();    angle += 0.1f;    if (angle > 360.0f)        angle = 0;    return true;}  

The above should get you a triangle spinning in place, hopefully. I can't test it because VC++ has blown up on me and I need to reinstall it.

Note that we've got to specify the transformations in reverse order. This is just OpenGL being fruity. Read it from the bottom up the way (as numbered in the comments).

Also, glRotatef takes its parameter in degrees , not radians. That's another gotcha - it's always worth looking through the documentation for things like that.

Any help to you?

[edited by - Alimonster on August 10, 2002 8:49:38 AM]
Advertisement
thx, but how do i make the triangle follow its nose when u hit the up arrow? like a car.
Ah, this comes down to vectors. A vector respresents a direction . If you've seen the tank moveabout thing from my tutorial exes then you should have spotted the red line. This represents the direction that the tank is facing.

You can think of any three-space value "(1,2,3)" as a coordinate or as a vector. The vector version would be read as "move one unit to the right of the wanted position, two units up, three into the screen". A vector acts as a reference from some other point - you've got to say "move x units from here ". This could be something as simple as the origin (in which case, the vector would simply be the same as the coordinates).




The first diagram represents the 2D vector (1,1) from the origin. It points up and to the right. The second diagram represents that same vector moved elsewhere - it still points in the same direction. You can think of vectors as additions - I want to go from the reference point to where this vector is pointing, so I'll add its x onto the original positions x, y onto the original position's y, etc.

The idea here would be that you have a vector representing which way the car is pointing. It would simply be a struct/class with x,y, and z values. When the object rotates you've got to rotate the vector too (it's meant to be where it's pointing, you see, so you've got to keep it in synch).

When you move the object, you want to move it in the direction pointed to by the vector . If you imagine the 2D scenario then your vector would have 2 values (x and y), and would point somewhere in a circle from a position (preferably the object's centre position). As you turn the vector point in the correct position. When you want the unit to move forward you'd move it in the direction pointed to by the vector:

somePos.x = somePos.x + (yourVector.x);
somePos.y = somePos.y + (yourVector.y);
/* repeat for z value if wanted */

The above would move your object *in the direction that it's facing*, rather than some arbitrary value ("move 2 up, 4 left") always. Note that because the vector rotates, the exact position is affected directly by where the vector points.

However, we can improve upon this. The above would move us in the direction that the vector was facing, but not at any controllable speed. A vector represents a direction, so it doesn't matter about the scale: (1,1) points up-and-to-the-right, but so does (2,2), (10, 10), and so on. They'll all point in the same direction . This means we multiply by the speed to control how quickly we're moving in the wanted direction:

somePos.x = somePos.x + (yourVector.x * speed);
somePos.y = somePos.y + (yourVector.y * speed);
/* repeat for z value if wanted */

That's almost perfect for our needs. However, we want to make sure the speed is consistent - if we had the vector (1, 1) and multiplied by a speed (say, 5) then we'd move 5 along and 5 up. If we multiplied (2, 2) by 5 then we'd move 10 along and 10 up. That's no good! Both vectors are pointing in the same direction, but one will move us much further depending on where it is.

The solution is to normalize the vector. This means that we scale it so that it's of unit length. This means that only its direction, and not where it is, comes into play. We can normalize the vector with the following:

The length of a vector is sqrt(x*x + y*y + z*z)

If we take that length and divide each component of the vector by it then we'll scale it down so that it totals 1:

step 1: get the length of the vector
step 2:
x = x / vectorlength
y = y / vectorlength
z = z / vectorlength

If we normalize the vector then we're all set, because it can point anywhere and we can use it to move our object. Have a look through the tank example code (even though it's in Delphi). Hopefully you'll be able to see the connection between what I've been talking about and how the code implements it.

You can also look at GameTutorials.com. They have a few relevant tutorials dealing with vectors, I'd guess (without having checked, mind you).

EDIT: I meant to say that the vector's length is sqrt, not sqr! Whoops!

[edited by - Alimonster on August 10, 2002 10:10:01 AM]
i have a triangle, and i want to rotate this triangle around the z axis using glTranslatef(0.0, 0.0, z);

z = cos(radians)
radians = ((angle*PI)/180)

now, my triangle starts rotating, but when it reaches 90 degrees, it flips 180 degrees so the triangle is facing the opposite direction...why is that?
quote:
i have a triangle, and i want to rotate this triangle around the z axis using glTranslatef(0.0, 0.0, z);

z = cos(radians)
radians = ((angle*PI)/180)

now, my triangle starts rotating, but when it reaches 90 degrees, it flips 180 degrees so the triangle is facing the opposite direction...why is that?

I''d have to see some more code to know for sure. However, note that you won''t be able to rotate around an axis using glTranslatef with one parameter - you have to use two or more to get a rotation. Think about it and you should see why. Imagine a 2D scenario. You might want to translate along the x axis. However, without changing the y axis then all you''d get would be an object that moved left and right, not up and down as well (and hence, not moving in a circle). It wouldn''t look like a rotation at all.

I''ll bung some more code your way now:

  struct Vertex2D{    float x,y;};Vertex2D triangle[] {{ 1.0f, 1.0f},{ 2.0f, 1.0f},{ 1.0f, 2.0f}};float angle = 0.0f;const float DEG_TO_RAD = 3.1415926536f / 180.0f;const float RADIUS = 2.0f;bool DrawGLScene(){    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();    float whereZ = RADIUS * cosf(angle * DEG_TO_RAD);    glTranslatef(0.0f, 0.0f, whereZ);    // draw the triangle now    glBegin(GL_TRIANGLES);        glColor3f(1.0f, 0.0f, 0.0f);        glVertex3f(triangle[0].x, triangle[0].y, 0.0f);        glColor3f(0.0f, 1.0f, 0.0f);        glVertex3f(triangle[1].x, triangle[1].y, 0.0f);        glColor3f(0.0f, 0.0f, 1.0f);        glVertex3f(triangle[2].x, triangle[2].y, 0.0f);    glEnd();    angle += 0.1f;    if (angle > 360.0f)        angle = 0.0f;    return true;}  

(Standard disclaimer: I haven''t compiled it, from the top of my head.)

You should see that the triangle only moves towards and away from you. The trouble here, as I said just above, is that you have to affect two or more axes. Let''s try the same but affecting *two* of the axes (in this case, y and z) instead of just one (z):

  struct Vertex2D{    float x,y;};Vertex2D triangle[] {{ 1.0f, 1.0f},{ 2.0f, 1.0f},{ 1.0f, 2.0f}};float angle = 0.0f;const float DEG_TO_RAD = 3.1415926536f / 180.0f;const float Y_RADIUS = 2.0f;const float Z_RADIUS = 3.0f;bool DrawGLScene(){    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();    float whereY = Y_RADIUS * sinf(angle * DEG_TO_RAD);    float whereZ = Z_RADIUS * cosf(angle * DEG_TO_RAD);    glTranslatef(0.0f, whereY, whereZ);    // draw the triangle now    glBegin(GL_TRIANGLES);        glColor3f(1.0f, 0.0f, 0.0f);        glVertex3f(triangle[0].x, 0.0f, 0.0f);        glColor3f(0.0f, 1.0f, 0.0f);        glVertex3f(triangle[1].x, 0.0f, 0.0f);        glColor3f(0.0f, 0.0f, 1.0f);        glVertex3f(triangle[2].x, 0.5f, 0.0f);    glEnd();    angle += 0.1f;    if (angle > 360.0f)        angle = 0.0f;    return true;}  

(Standard disclaimer: I haven''t compiled it, from the top of my head.)

This time we do get a rotation. However, it''s a "orbiting around" one and the triangle itself doesn''t spin, just get moved. That''s the trouble with glTranslatef for rotation here. We can only position the triangle, not alter its orientation. For that, you''d have to use glRotatef or manually change the formula.

The above code moves around the x axis (the easy way to tell which axis it''s rotating around is to simply find the one not used - we''re using y and z in the second code, so we''re moving around the x axis). If you replace the glTranslatef call with "glTranslatef(whereZ, whereY, 0.0f);" then it''ll move around the z axis (like a 2D rotation).

Notice how the triangle stays pointing in the same direction. To fix that you''d have to use the

[cos -sin]
[sin +cos]

formulae from the tutorial, plugging in the correct value. This is why we need the formula - we can reposition the triangle correctly, but without the formula we can''t get it to *spin*.

This topic is closed to new replies.

Advertisement