I am using a camera that has a yaw, a pitch, and a roll. When yaw == 0 the camera is looking down the -z axis(yaw == 90 is positive x), when pitch == 270 the camera is looking up(pitch == 0 is looking straight), and when roll == 180 the camera is upside down.
The camera's yaw, pitch, and roll values are never less than zero or greater than 360(when any value approaches 0 or 360 when it passes that amount it is automatically moved to the 'other side').
I have implemented 3DoF and it works quite nicely; however, when I implemented 6DoF, everything appears to work until the roll is around 90 or 270, then strange things occur to the up and right vectors(forward always seems to work because roll rotates around that axis?)
The scene I am rendering is just a bunch of blocks(in minecraft-style chunks) and I am always able to move forward/backward and use the forward vector to target a block so I know that the forward vector is done.
Here is my initGL:
public void initGL() {
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GL11.glClearDepth(1.0);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glDepthFunc(GL11.GL_LEQUAL);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GLU.gluPerspective(fov, ((float) Display.getWidth()) / ((float) Display.getHeight() != 0 ? Display.getHeight() : 1), 0.1f, 100.0f);//fov is 45.0f
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
}
Here is where I rotate and translate to my camera's view:
public final void lookThrough() {
GL11.glRotatef(this.roll, 0.0f, 0.0f, 1.0f);
GL11.glRotatef(this.pitch, 1.0f, 0.0f, 0.0f);
GL11.glRotatef(this.yaw, 0.0f, 1.0f, 0.0f);
GL11.glTranslatef(-this.position.x, -this.position.y, -this.position.z);
}
And here are my six degrees of freedom calculations:
public static final double zeroRad = Math.toRadians(0);
public static final double ninetyRad = Math.toRadians(90);
public static final double oneEightyRad = Math.toRadians(180);
public static final double twoSeventyRad = Math.toRadians(270);
public static final strictfp void updateLookVectorsIn6DoF(Vector3f yawPitchAndRoll, Vector3f forward, Vector3f up, Vector3f right) {
final double yaw = Math.toRadians(yawPitchAndRoll.getX());
final double pitch = Math.toRadians(yawPitchAndRoll.getY());
final double roll = Math.toRadians(yawPitchAndRoll.getZ());
final float sinYaw = ((float) Math.sin(yaw));
final float cosYaw = ((float) Math.cos(yaw));
final float sinYaw90 = ((float) Math.sin(yaw + ninetyRad));
//final float sinYaw180 = ((float) Math.sin(yaw + oneEightyRad));
final float cosYaw270 = ((float) Math.cos(yaw - ninetyRad));
final float sinRoll = ((float) Math.sin(roll));
final float cosRoll = ((float) Math.cos(roll));
//final float sinRoll180 = ((float) Math.sin(roll + oneEightyRad));
final float cosPitch90 = ((float) Math.cos(pitch + ninetyRad));
//final float cosPitch270 = ((float) Math.cos(pitch + twoSeventyRad));
final float sinPitch90 = ((float) Math.sin(pitch + ninetyRad));
final float sinPitch270 = ((float) Math.sin(pitch - ninetyRad));
//Forward:(No roll because roll goes around the Z axis and forward movement is in that axis.)
float x = sinYaw * ((float) Math.cos(pitch));
float y = -((float) Math.sin(pitch));
float z = cosYaw * ((float) Math.cos(pitch - oneEightyRad));
forward.set(x, y, z);
//cos(90) = 0, cos(180) = -1, cos(270) = 0, cos(0) = 1
//sin(90) = 1, sin(180) = 0, sin(270) = -1, sin(0) = 0
//Up: Strange things occur when roll is near 90 or 270 and yaw is near 0 or 180
x = -(sinYaw * cosPitch90) * cosRoll - (sinRoll * sinYaw90);
y = -sinPitch270 * cosRoll;
z = (cosYaw * cosPitch90) * cosRoll + (sinRoll * cosYaw270);
up.set(x, y, z);
//Right: Strange things occur when roll is near 90 or 270 and pitch is near 90 or 270
x = (cosRoll * sinYaw90) - (sinRoll * (sinYaw * cosPitch90));
y = 0 - (sinRoll * sinPitch90);//This axis works fine
z = (cosRoll * cosYaw270) + (sinRoll * (sinYaw * cosPitch90));
right.set(x, y, z);
}
I did find a very similar question here, but it uses matrices and quaternions and I don't want to have to do that unless I absolutely have to(and I was careful to try to multiply roll pitch and yaw in the correct order): LWJGL - Problems implementing 'roll' in a 6DOF Camera using quaternions and a translation matrix
So I finally got the hang of the meaning of cos and sin(but don't ask me to teach it) and was able to get this working!
Here is the new and improved code:
public static final double zeroRad = Math.toRadians(0);
public static final double ninetyRad = Math.toRadians(90);
public static final double oneEightyRad = Math.toRadians(180);
public static final double twoSeventyRad = Math.toRadians(270);
public static final strictfp void updateLookVectorsIn6DoF(Vector3f yawPitchAndRoll, Vector3f forward, Vector3f up, Vector3f right) {
final double yaw = Math.toRadians(yawPitchAndRoll.getX());
final double pitch = Math.toRadians(yawPitchAndRoll.getY());
final double roll = Math.toRadians(yawPitchAndRoll.getZ());
final float sinYaw = ((float) Math.sin(yaw));
final float cosYaw = ((float) Math.cos(yaw));
final float sinYaw90 = ((float) Math.sin(yaw + ninetyRad));
final float sinYaw270 = ((float) Math.sin(yaw - ninetyRad));//+ twoSeventyRad));
final float cosYaw90 = ((float) Math.cos(yaw + ninetyRad));
final float cosYaw180 = ((float) Math.cos(yaw + oneEightyRad));
final float cosYaw270 = ((float) Math.cos(yaw - ninetyRad));//+ twoSeventyRad));
final float sinRoll = ((float) Math.sin(roll));
final float cosRoll = ((float) Math.cos(roll));
final float cosRoll180 = ((float) Math.cos(roll + oneEightyRad));
final float cosPitch90 = ((float) Math.cos(pitch + ninetyRad));
final float sinPitch90 = ((float) Math.sin(pitch + ninetyRad));
final float sinPitch270 = ((float) Math.sin(pitch - ninetyRad));
//Forward:(No roll because roll goes around the Z axis and forward movement is in that axis.)
float x = sinYaw * ((float) Math.cos(pitch));
float y = -((float) Math.sin(pitch));
float z = cosYaw * ((float) Math.cos(pitch - oneEightyRad));
forward.set(x, y, z);
//Multiply in this order: roll, pitch, yaw
//cos(90) = 0, cos(180) = -1, cos(270) = 0, cos(0) = 1
//sin(90) = 1, sin(180) = 0, sin(270) = -1, sin(0) = 0
//hmm... gimbal lock, eh? No!
//Up://
x = (cosRoll180 * cosPitch90 * sinYaw) - (sinRoll * cosYaw180);
y = -sinPitch270 * cosRoll;
z = (cosRoll * cosPitch90 * cosYaw) + (sinRoll * sinYaw);
up.set(x, y, z);
//Right:
x = (cosRoll * sinYaw90) - (sinRoll * cosPitch90 * cosYaw90);
y = 0 - (sinRoll * sinPitch90);//This axis works fine
z = (cosRoll * cosYaw270) + (sinRoll * cosPitch90 * sinYaw270);
right.set(x, y, z);
}
Related
I am learning opengl but having problem rendering sphere. I can draw and bind the texture of polygon normally but when I try to use the same method to the sphere drew by triangle strip, it just didn't went well. Part of the texture is broken. (Pic on below)
May I know what did I do wrongly? Sorry if this is an obvious question.
Here are the code of sphere :
(before adding the texture part, the sphere can be displayed normally)
private void drawSphere(GL gl) {
Position spherePosition = state.getSpherePosition();
final float PI = 3.141592f;
gl.glPushMatrix();
if(spheretexture == null){
setSphereTexture();
}
gl.glTranslated(spherePosition.getX(), spherePosition.getY(), spherePosition.getZ());
float[] ambientDiffuse = new float[] {255.0f, 255.0f, 255.0f, 1.0f};
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE, ambientDiffuse, 0);
gl.glEnable(GL_BLEND);
gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
float x, y, z, alpha, beta; // Storage for coordinates and angles
float radius = 25f;
int gradation = 10;
for (alpha = 0.0f; alpha < PI; alpha += PI / gradation) {
spheretexture.enable();
spheretexture.bind();
gl.glBegin(GL_TRIANGLE_STRIP);
for (beta = 0.0f; beta < 2.01 * PI; beta += PI / gradation) {
x = (float) (radius * Math.cos(beta) * Math.sin(alpha));
y = (float) (radius * Math.sin(beta) * Math.sin(alpha));
z = (float) (radius * Math.cos(alpha));
gl.glTexCoord2f(beta / (2.0f * PI), alpha / PI);
gl.glVertex3f(x, y, z);
x = (float) (radius * Math.cos(beta) * Math.sin(alpha + PI / gradation));
y = (float) (radius * Math.sin(beta) * Math.sin(alpha + PI / gradation));
z = (float) (radius * Math.cos(alpha + PI / gradation));
gl.glTexCoord2f(beta / (2.0f * PI), alpha / PI + 1.0f / gradation);
gl.glVertex3f(x, y, z);
}
gl.glEnd();
spheretexture.disable();
gl.glDisable(GL_BLEND);
gl.glPopMatrix();
}
}
Output picture:
The major issue is that the top cap of the sphere is drawn twice. That causes Z-fighting. Note, first it is drawn buy the strip between PI-PI/gradation and PI and then it is drawn by the strip between PI and PI+PI/gradation. That is caused, because the outer loop does one an extra pass. Change it to:
for (alpha = 0.0f; alpha < PI-PI/gradation; alpha += PI / gradation) {
// [...]
}
or even better
for (int i = 0; i < gradation; ++ i ) {
float alpha = PI * (float)i / (float)(gradation);
// [...]
}
I'm trying to make a 3d game with java from scratch but a have a problem with rendering a triangle after I multiply each vertices with projection matrix
I already try to use the projected vertices x and y but the result is all the vertices the in the same X, so I try to rotate the triangle X or Y or Z axis but the result is the same.
The result of rendering (draw in paint):
I know that the triangle is align with the camera but I tried to move the vertex that is overlapping out by changing its X or Y or Z coordinate but It didn't work
import java.awt.Color;
import java.awt.Graphics;
import measurement.MatrixF;
import measurement.Vector3f;
import model.Mesh;
import model.Triangle;
import toolbox.GE;
import toolbox.Matrix;
import toolbox.Vector;
public class MeshRenderer {
private int width, height;
private float fNear, fFar;
private float fov;
private float fAspectRatio;
private float fovRad;
private float theta;
private MatrixF projectionMatrix;
private MatrixF rotXMatrix;
private MatrixF rotYMatrix;
private MatrixF rotZMatrix;
private Vector3f globalTranslation;
public MeshRenderer(float fNear, float fFar, float fov, int width, int height) {
this.fNear = fNear;
this.fFar = fFar;
this.fov = fov;
this.fAspectRatio = height / width;
this.width = width;
this.height = height;
this.fovRad = (float) (1.0f / Math.tan(Math.toRadians(fov / 2)));
projectionMatrix = new MatrixF(4, 4);
rotXMatrix = new MatrixF(4, 4);
rotYMatrix = new MatrixF(4, 4);
rotZMatrix = new MatrixF(4, 4);
projectionMatrix.m[0][0] = fAspectRatio * fovRad;
projectionMatrix.m[1][1] = fovRad;
projectionMatrix.m[2][2] = (-(fFar + fNear)) / (fFar - fNear);
projectionMatrix.m[3][2] = (-2 * fFar * fNear) / (fFar - fNear);
projectionMatrix.m[2][3] = -1.0f;
projectionMatrix.m[3][3] = 0.0f;
rotXMatrix.m[0][0] = 1;
rotXMatrix.m[1][1] = (float) Math.cos(theta);
rotXMatrix.m[2][1] = (float) -Math.sin(theta);
rotXMatrix.m[1][2] = (float) Math.sin(theta);
rotXMatrix.m[2][2] = (float) Math.cos(theta);
rotYMatrix.m[0][0] = (float) Math.cos(theta);
rotYMatrix.m[2][0] = (float) Math.sin(theta);
rotYMatrix.m[1][1] = (float) 1.0;
rotYMatrix.m[0][2] = (float) -Math.sin(theta);
rotYMatrix.m[2][2] = (float) Math.cos(theta);
rotXMatrix.m[2][2] = 1;
rotXMatrix.m[0][0] = (float) Math.cos(theta);
rotXMatrix.m[1][0] = (float) -Math.sin(theta);
rotXMatrix.m[0][1] = (float) Math.sin(theta);
rotXMatrix.m[1][1] = (float) Math.cos(theta);
//projectionMatrix = Matrix.transpose(projectionMatrix);
globalTranslation = new Vector3f(0.0f, 0.0f, 0.0f);
}
public void renderMesh(Mesh mesh, Graphics g) {
for(int i = 0; i < mesh.tris.length; i++) {
Triangle tri = new Triangle(mesh.tris[i].p[0], mesh.tris[i].p[1], mesh.tris[i].p[2]);
Triangle translatedTri = tri;
Triangle projectedTri = new Triangle();
theta += 0.0001;
this.calculateRotationMatrix(theta);
translatedTri.p[0] = Matrix.multiplyMatrixVector(tri.p[0], rotYMatrix);
translatedTri.p[1] = Matrix.multiplyMatrixVector(tri.p[1], rotYMatrix);
translatedTri.p[2] = Matrix.multiplyMatrixVector(tri.p[2], rotYMatrix);
translatedTri.p[0].z = tri.p[0].z + globalTranslation.z;
translatedTri.p[1].z = tri.p[1].z + globalTranslation.z;
translatedTri.p[2].z = tri.p[2].z + globalTranslation.z;
projectedTri.p[0] = Matrix.multiplyMatrixVector(translatedTri.p[0], projectionMatrix);
projectedTri.p[1] = Matrix.multiplyMatrixVector(translatedTri.p[1], projectionMatrix);
projectedTri.p[2] = Matrix.multiplyMatrixVector(translatedTri.p[2], projectionMatrix);
projectedTri.p[0].x += 1.0f; projectedTri.p[0].y += 1.0f;
projectedTri.p[1].x += 1.0f; projectedTri.p[1].y += 1.0f;
projectedTri.p[2].x += 1.0f; projectedTri.p[2].y += 1.0f;
float scale = 0.5f;
projectedTri.p[0].x *= scale * width;
projectedTri.p[0].y *= scale * height;
projectedTri.p[1].x *= scale * width;
projectedTri.p[1].y *= scale * height;
projectedTri.p[2].x *= scale * width;
projectedTri.p[2].y *= scale * height;
GE.drawTriangle(projectedTri.p[0].x, projectedTri.p[0].y, projectedTri.p[1].x, projectedTri.p[1].y, projectedTri.p[2].x, projectedTri.p[2].y, Color.WHITE, g);
for(int j = 0; j < projectedTri.p.length; j++) {
g.setColor(new Color(255, 0, (j * 50)));
g.fillRect((int)projectedTri.p[j].x - 8, (int)projectedTri.p[j].y - 8, 16 - j, 16 - j);
}
translatedTri.p[0].z = tri.p[0].z - globalTranslation.z;
translatedTri.p[1].z = tri.p[1].z - globalTranslation.z;
translatedTri.p[2].z = tri.p[2].z - globalTranslation.z;
}
}
private void calculateRotationMatrix(float theta) {
rotXMatrix.m[0][0] = 1;
rotXMatrix.m[1][1] = (float) Math.cos(theta);
rotXMatrix.m[2][1] = (float) -Math.sin(theta);
rotXMatrix.m[1][2] = (float) Math.sin(theta);
rotXMatrix.m[2][2] = (float) Math.cos(theta);
rotYMatrix.m[0][0] = (float) Math.cos(theta);
rotYMatrix.m[2][0] = (float) Math.sin(theta);
rotYMatrix.m[1][1] = (float) 1.0;
rotYMatrix.m[0][2] = (float) -Math.sin(theta);
rotYMatrix.m[2][2] = (float) Math.cos(theta);
rotXMatrix.m[2][2] = 1;
rotXMatrix.m[0][0] = (float) Math.cos(theta);
rotXMatrix.m[1][0] = (float) -Math.sin(theta);
rotXMatrix.m[0][1] = (float) Math.sin(theta);
rotXMatrix.m[1][1] = (float) Math.cos(theta);
}
public Vector3f getTranslation() {
return globalTranslation;
}
public float getfNear() {
return fNear;
}
public float getfFar() {
return fFar;
}
public float getFov() {
return fov;
}
public float getfAspectRatio() {
return fAspectRatio;
}
public float getFovRad() {
return fovRad;
}
}
The matrix (4x4) multiply with vector3 function just in case:
Vector3f o = new Vector3f(0, 0, 0);
o.x = (i.x * m.m[0][0]) + (i.y * m.m[1][0]) + (i.z * m.m[2][0]) + m.m[3][0];
o.y = (i.x * m.m[0][1]) + (i.y * m.m[1][1]) + (i.z * m.m[2][1]) + m.m[3][1];
o.z = (i.x * m.m[0][2]) + (i.y * m.m[1][2]) + (i.z * m.m[2][2]) + m.m[3][2];
float w = (i.x * m.m[0][3]) + (i.y * m.m[1][3]) + (i.z * m.m[2][3]) + m.m[3][3];
if (w != 0.0f)
{
o.x /= w; o.y /= w; o.z /= w;
}
return o;
}
Without seeing exactly how this class is being used, it's hard to say exactly what the problem is, but FWIW I'm not seeing too much wrong with the math:
There are a couple places where you probably intended to initialize rotZMatrix instead of reinitializing rotXMatrix, but the code is not actually using either.
When adding in globalTranslation, you are overwriting the rotated z coordinate with the pre-rotated z coordinate, when you probably just want to update the rotated coordinate.
It's not apparent whether MatrixF is initialized to the identity or to zeros -- but if the latter, you probably should be populating the m[3][3] element of the rotation matrices with 1.0.
Naturally, you probably want to lift the theta increment and rotation calculation outside of the triangle loop, once you have more than one triangle.
I'm guessing that the problem is that you are leaving globalTranslation at zero and that the mesh is near the origin -- hence the transformed geometry is on the wrong side of the near plane and outside of the view frustum. Most graphic engines would cull such geometry, since the post-transform results will lie outside of clip space and will look increasingly anomalous around and behind the eye point.
I'd recommend trying to adjust globalTranslation.z to ensure 0 < fNear < translatedTri.p[i].z < fFar, for all the translated points.
(You could also try temporarily swapping the perspective matrix with a orthographic projection matrix, to determine whether the problem is in the projection/homogenization math or elsewhere.)
When I create a Body and draw a Texture where that body is, if the angle is set to 0.0f, it appears exactly where expected. Upright and at the centre x and y of the Player (the black circle). When this angle changes, the x and y of the texture appear to be completely off. In fact they tend to be off the screen as I can only see them visibly sometimes as they fall with the gravity.
Here's the method where I create a new bullet:
private void shoot(final float delta) {
gameTime += delta;
final float timeSinceLastShot = gameTime - lastBulletShotTime;
//5 bullets a second, kerpow
if (timeSinceLastShot > 0.2f) {
lastBulletShotTime = gameTime;
shot.play();
final float shotX = player.getX() + ((player.getWidth() / 2) - (bulletTexture.getWidth() / 2));
final float shotY = player.getY() + ((player.getHeight() / 2) - (bulletTexture.getHeight() / 2));
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(shotX, shotY);
Body body = world.createBody(bodyDef);
float angle = player.getRotation() * MathUtils.degreesToRadians;
body.setTransform(body.getPosition().x, body.getPosition().y, angle);
System.out.println("angle rad: " + angle);
bullets.add(body);
PolygonShape shape = new PolygonShape();
shape.setAsBox(bulletTexture.getWidth() / 2, bulletTexture.getHeight() / 2);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 1f;
Fixture fixture = body.createFixture(fixtureDef);
shape.dispose();
}
}
And here's the part of the render method where I loop and draw the bullets:
for (Body bullet : bullets) {
final float x = bullet.getPosition().x;
final float y = bullet.getPosition().y;
final float originX = x + (bulletTexture.getWidth() / 2);
final float originY = y + (bulletTexture.getHeight() / 2);
final float width = bulletTexture.getWidth();
final float height = bulletTexture.getHeight();
final float scaleX = 1.0f;
final float scaleY = 1.0f;
final float rotation = bullet.getAngle() * MathUtils.radiansToDegrees;
final int sourceX = 0;
final int sourceY = 0;
final int sourceWidth = bulletTexture.getTextureData().getWidth();
final int sourceHeight = bulletTexture.getTextureData().getHeight();
final boolean flipX = false;
final boolean flipY = false;
batch.draw(bulletTexture,
x, y,
originX, originY,
width, height,
scaleX, scaleY,
rotation,
sourceX, sourceY,
sourceWidth, sourceHeight,
flipX, flipY);
}
Any tips for what I'm doing wrong? I want the bullets to always start at the centre of the Player Circle, but also at the correct angle. I then intend to add some velocity so they 'shoot'.
The full code can be found here on Github https://github.com/SamRuffleColes/PlayerCircle/blob/master/core/src/es/rufflecol/sam/playercircle/PlayerCircle.java
I've also attached a screenshot, everything has fallen a little with the gravity between shooting and taking this, but the bottom left bullets appeared in the right place initially, while all the others have fallen from off the screen (some others which I 'shot' were never visible).
My mistake was with the originX and originY. Corrected to the below, it now works:
final float originX = bulletTexture.getWidth() / 2;
final float originY = bulletTexture.getHeight() / 2;
this is a more math related question.
In my android app I have a canvas that draws a line from start to endpoint.
I also have an angle attribute to rotate the line.
I tried to apply the code bellow to my cocept, but it jumps around weirdly, not pointing in the direction it is supposed to. (0deg = horizontal line)
//Coordinates for P1 and P2
int startx = 0;
int starty = 66;
int endx = 420;
int endy = 66;
//Alpha
float angle = 0.000F;
final float radius = 209.500F;
final float extra_radius = 20.000F; //required later - don't mind it
private void reCal(float[] vals) {
float xAcc = vals[0]*(-1);
float yAcc = vals[1]*(-1);
angle = yAcc / 10.000F * 90.000F;
final float rRadius = radius + extra_radius;
startx = (int) (radius - Math.cos(angle) * rRadius); //left
endx = (int) (radius + Math.cos(angle) * rRadius); //right
starty = 66 + (int) (Math.sin(angle) * rRadius); //top
endy = 66 - (int) (Math.sin(angle) * rRadius); //bot
}
Are their any type conversions that might cause this, or is my math wrong?
UPDATE:
I looked at Math.cos(angle) and Math.sin(angle) at runtime.They jump around between 0 and 1, even if angle is only changed by a little amount.
Now I am wondering: DO THE METHODS TAKE RAD OR DEG AS PARAMETER? (I need deg, obviously)
if you want to rotate a line starting at [cx, cy] and length of dx, use that code snippet:
canvas.save();
canvas.rotate(angle, cx, cy);
canvas.drawLine(cx, cy, cx + dx, cy, paint);
canvas.restore();
Ok, we are not talking about OpenGL with this question, but this will be used with OpenGL ES 2.0.
Question: How do create and rotate a Quaternion with the following code?
I have been reading up and studying about this and still can't quite gasp the concepts. I thought I understood it, but once I started making some calculations to rotate the quaternion I realized I can't even get back to where I started.
So let us say that we have a cube, and the center of it is at (0, 0, 0). We want to rotate it on the x-axis by 45 degrees. What would I do? (Only the Quaternion)
Assuming success, how would you get the amount of rotation from 'W'? I know that '1' indicates that there is no rotation, but what if it was rotated 173 degrees?
Trying to rotate to a given direction, 45 degrees, and then get that value from W. I feel like I need to convert the angle to rads or something, but not exactly sure. Tutorials online vary from one to the next.
Here is my code:
import java.util.Scanner;
import Quaternion;
public class Main {
public static void main(String[] args) {
Quaternion q1 = new Quaternion(0, 0, 0, 1);
Quaternion q2 = new Quaternion(0, 0, 0, (float) Math.cos(toRAD(45.0f) / 2));
q1 = q2.mul(q1);
System.out.println("q1: " + q1.getX() + ", " + q1.getY() + ", " + q1.getZ() + " with " + toANGLE(2.0f * Math.acos(q1.getW())));
}
private static double toRAD(float angle) {
return angle * (Math.PI / 180.0f);
}
private static float toANGLE(double rad) {
return (float) (rad * (180.0f / Math.PI));
}
}
Here is the code for a Quaternion:
public class Quaternion // Credit goes to 'thebennybox' (http://www.youtube.com/user/thebennybox)
{
private float x;
private float y;
private float z;
private float w;
public Quaternion(float x, float y, float z, float w)
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
public float length()
{
return (float)Math.sqrt(x * x + y * y + z * z + w * w);
}
public Quaternion normalize()
{
float length = length();
return new Quaternion(x / length, y / length, z / length, w / length);
}
public Quaternion conjugate()
{
return new Quaternion(-x, -y, -z, w);
}
public Quaternion mul(Quaternion r)
{
float w_ = w * r.getW() - x * r.getX() - y * r.getY() - z * r.getZ();
float x_ = x * r.getW() + w * r.getX() + y * r.getZ() - z * r.getY();
float y_ = y * r.getW() + w * r.getY() + z * r.getX() - x * r.getZ();
float z_ = z * r.getW() + w * r.getZ() + x * r.getY() - y * r.getX();
return new Quaternion(x_, y_, z_, w_);
}
public Quaternion mul(Vector3f r)
{
float w_ = -x * r.getX() - y * r.getY() - z * r.getZ();
float x_ = w * r.getX() + y * r.getZ() - z * r.getY();
float y_ = w * r.getY() + z * r.getX() - x * r.getZ();
float z_ = w * r.getZ() + x * r.getY() - y * r.getX();
return new Quaternion(x_, y_, z_, w_);
}
public float getX()
{
return x;
}
public void setX(float x)
{
this.x = x;
}
public float getY()
{
return y;
}
public void setY(float y)
{
this.y = y;
}
public float getZ()
{
return z;
}
public void setZ(float z)
{
this.z = z;
}
public float getW()
{
return w;
}
public void setW(float w)
{
this.w = w;
}
}
I'm still not 100% sure what your question is asking, but I'll give it a shot.
Problem: Given a quaternion representing a 0 degree rotation about x, y, z, generate a new quaternion representing a 45 degree rotation about the x axis
Start with a quaternion representing no rotation, call it q1
q1 = (w1, x1, y1, z1)
q1.w1 = cos(0/2) = 1
q1.x1 = 0 * sin(0/2) = 0
q1.y1 = 0 * sin(0/2) = 0
q1.z1 = 0 * sin(0/2) = 0
So q1 = (1, 0, 0, 0)
Generate a new rotation that is 45 degrees (PI/4 radians) about the X axis
We need a temporary quaternion to modify q1. Let's call it q2.
q2 = (w2, x2, y2, z2)
q2.w2 = cos(PI/4 / 2) = cos(PI/8)
q2.x2 = 1.0 * sin(PI/4 / 2) = 1.0 * sin(PI/8) = sin(PI/8)
q2.y2 = 0.0 * sin(PI/4 / 2) = 0.0
q2.z2 = 0.0 * sin(PI/4 / 2) = 0.0
so q2 = (cos(PI/8), sin(PI/8), 0, 0)
Now this last step is important, you modify your original quaternion by a left-hand multiplication of the temporary quaternion
What I mean is this:
q1 = q2 * q1
Your multiplication function is written correctly, so the problem is not there. Remember that quaternion multiplications are not commutative. That is q2 * q1 is NOT the same as q1*q2!
At this point q1 is modified to represent a 45 degree rotation about the X axis.
To print out the angle in degrees, you need to compute 2.0 * acos(q1.w) / PI * 180
Your code is incorrectly computing q1.w/PI * 180 to get the angle in degrees.
More specifically, change
toANGLE(resQuat.getW())
to
toANGLE(2.0f * Math.acos(resQuat.getW()))
I haven't looked at your code beyond that, but try applying these concepts and see if that fixes your problem.