I'm implementing a space fps game (there is no up or down in space!) using LWJGL3 and JOML (math library).
Entities in my game have a rotation based on the Forward, Up and Right vectors. I use pitch, yaw and roll methods to rotate my entities. The methods can be seen in the pseudo code further down.
When I construct the model matrix for an entity I calculate a rotation matrix based on the 3 vectors described above and apply it. It can be seen in the pseudo code further down.
I also use angular and linear acceleration and velocity to rotate and move an entity. It can be seen in the pseudo code further down.
Entity:
Vector3f position
Vector3f scale
Vector3f forward
Vector3f up
Vector3f right
private Vector3f linearAcc
private Vector3f linearVel
private Vector3f angularAcc
private Vector3f angularVel
public void pitch(double angle) {
forward.mul((float) Math.cos(angle), tempVector1).add(up.mul((float) Math.sin(angle), tempVector2)).normalize(forward);
right.cross(forward, up);
}
public void roll(double angle) {
right.mul((float) Math.cos(angle), tempVector1).add(up.mul((float) Math.sin(angle), tempVector2)).normalize(right);
right.cross(forward, up);
}
public void yaw(double angle) {
right.mul((float) Math.cos(angle), tempVector1).add(forward.mul((float) Math.sin(angle), tempVector2), right);
up.cross(right, forward);
}
public Matrix4f getRotationMatrix(Matrix4f dest) {
dest.set(
right.x, right.y, right.z, 0,
forward.x, forward.y, forward.z, 0,
up.x, up.y, up.z, 0,
0, 0, 0, 1);
return dest;
}
Model matrix:
public static Matrix4f createModelMatrix(Vector3f position, Matrix4f rotationMatrix, Vector3f scale) {
Matrix4f modelMatrix = new Matrix4f();
modelMatrix.translate(position);
modelMatrix.mul(rotationMatrix);
modelMatrix.scale(scale);
return modelMatrix;
}
Basic logic for rotating and moving an entity:
// Angular acceleration:
// Angular acceleration is reset every update
entity.getAngularAcc().zero();
// Components may rotate an entity by applying angular acceleration
Vector3f someAngularThrust = new Vector3f(0, 0, 0.025f);
entity.getAngularAcc().add(someAngularThrust );
// The accumulated angular acceleration is added to the angular velocity
entity.getAngularVel().fma(dt, movement.getAngularAcc());
// Finally, the entity is rotated by the angular velocity
entity.pitch(dt * entity.getAngularVel().x);
entity.yaw(dt * entity.getAngularVel().y);
entity.roll(dt * entity.getAngularVel().z);
// The basic logic applies for linear movement:
// Linear acceleration is reset every update
entity.getLinearAcc().zero();
// Components may move an entity by applying linear acceleration
Vector3f someLinearThrust = entity.getForward().mul(5);
entity.getLinearAcc().add(someLinearThrust );
// The accumulated linear acceleration is added to the linear velocity
entity.getLinearVel().fma(dt, entity.getLinearAcc());
// Finally, the entity is moved by the linear velocity
entity.getPosition().fma(dt, entity.getLinearVel());
So far it seems that this setup works, but it does not give me all the functionality I need in my game:
I want an alternative way of setting/modifying the rotation of an entity - right now it can only be done by setting the Forward, Up and Right vectors or using the pitch, yaw and roll methods.
I want to be able to represent the rotation of an entity with a smaller unit (a rotation vector / axis?). It is a multiplayer game where I need to send the orientation of entities. Sending 2 or more 3d vectors to represent the orientation is not optimal.
From what I understand quaternions can do all that I want. I tried to use it in my game (Quaternionf in JOML), but couldn't get it to work properly:
- I couldn't get the pitch, yaw and roll methods to work.
- The model matrix didn't work. The facing direction of the entities did not match the direction they were moving - they were supposed to move in the direction they were facing.
- The movement logic didn't seem to work either (even when not using pitch, yaw and roll). Could have got something to do with the above point.
Any ideas how I should go on about to use quaternions in my code?