# 3D Thrust velocity

How do I create 3D velocity with a 3D angle and 1D thrust like the 2D algorithm below?

angle.z += angularVelocity.z * timeStep;

velocity.x = thrust * cosf(angle.z);
velocity.y = thrust * sinf(angle.z);

position.x += velocity.x * timeStep;
position.y += velocity.y * timeStep;


I want to simplify my 3D OpenGL motion by having the final angle and position correct no matter where the spaceship's thrust is.

My spaceship uses the OpenGL motion functions below:

glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glRotatef(rad2deg(angle.x), 1.0, 0.0, 0.0);
glRotatef(rad2deg(angle.y), 0.0, 1.0, 0.0);
glRotatef(rad2deg(angle.z), 0.0, 0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glVertex3f(-1.0,-1.0, 0.0);
glVertex3f( 1.0,-1.0, 0.0);
glVertex3f( 1.0, 1.0, 0.0);

glEnd();
glPopMatrix();


The problem is that the 3D spaceship rotates but the thrust always goes off toward the positive x axis. The angles are Euler in degrees and radians.

• There are a lot more ways to represent a direction/angle in 3D than there are in 2D, so you'll need to pick one first in order for this question to be well-specified. Does your game use (some specific variant of) Euler/Tait-Bryan angles, quaternions, rotation matrices, direction vectors, etc...? Jul 24, 2017 at 20:05
• @DMGregory I just updated my question with the OpenGL shape and motion. Jul 25, 2017 at 0:38

# Trigonometry

As stated in this article, 3D rotations (rX, rY, rZ; for their respective axes) transform a point P (xi,yi,zi) into another point P' (xf, yf, zf) in the following way. Note: the rotations can be ordered in any way, but I'm going to do XYZ.

### X-Axis rotation

yf = yi*cos(rotX) - zi*sin(rotX)
zf = yi*sin(rotX) + zi*cos(rotX)
xf = xi


### Y-Axis rotation

zf = zi*cos(rotY) - xi*sin(rotY)
xf = zi*sin(rotY) + xi*cos(rotY)
yf = yi


### Z-Axis rotation

xf = xi*cos(rotZ) - yi*sin(rotZ)
yf = xi*sin(rotZ) + yi*cos(rotZ)
zf = zi


# Application

With this knowledge, we can construct a unit vector that represents the direction that your spaceship is moving in. Let's start by having it point forward, since opengl's view matrix point's forward (-Z) by default.

dir_init = vec3( 0, 0, -1 )
dir = vec3()


Now, we can plug dir_init.x in for xi and dir.x in for xf, and the same for the other two dimensions, and do the math above. After that, all we have to do is add each component to its respective component in the spaceships coordinates.

spaceship.x += dir.x * speed
spaceship.y += dir.y * speed
spaceship.z += dir.z * speed


Disclaimer: I started working with this concept today, and if I'm missing anything, feel free to comment.

• Are the X and Y axes supposed to be rotX and rotY instead of rotZ? Also how do you add all three rotation axes together? I seem to be getting acceleration when I add them. Jul 29, 2017 at 22:00
• Ah! I'll fix that!! Jul 29, 2017 at 22:34
• By 'add'ing the three rotation axes together, do you mean applying all three rotations to the direction of the ship? You apply all three by simply using/updating the same variables with each rotation. Jul 29, 2017 at 22:36

Looking again at the code again gave me a great idea! Since velocity is just the change of position use OpenGL to do the grunt work. I was able to get the code below working, although, the answer above is better optimized. The code below is updated inside the drawing function and thrustSpeed and angularVelocity are changed in the keyboard function.

angle.x += angularVelocity.x * timeStep;
angle.y += angularVelocity.y * timeStep;
angle.z += angularVelocity.z * timeStep;
float matrix[16];

glPushMatrix();

glRotatef(degreesFromRadians(angle.z), 0.0, 0.0, 1.0);
glRotatef(degreesFromRadians(angle.y), 0.0, 1.0, 0.0);
glRotatef(degreesFromRadians(angle.x), 1.0, 0.0, 0.0);
glTranslatef( 0.0, thrustSpeed, 0.0);

glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
glPopMatrix();

position.x += matrix[12] * timeStep;
position.y += matrix[13] * timeStep;
position.z += matrix[14] * timeStep;

glPushMatrix();
glTranslatef( position.x, position.y, position.z);
glRotatef(degreesFromRadians(angle.z), 0.0, 0.0, 1.0);
glRotatef(degreesFromRadians(angle.y), 0.0, 1.0, 0.0);
glRotatef(degreesFromRadians(angle.x), 1.0, 0.0, 0.0);