The question change a bit, I figured out how to rotate around a single axis
I want to rotate a box around the Y axis using an angle.
The box has a size, and a Vector3f to signal the rotation.
To rotate the box correctly what I do is rotate the origin position then rotate the origin position plus the size, and use those two references to render the box.
However this rotation does not work correctly and causes rendering artifacts.
This is my code to rotate the positions:
Matrix4f matrix = new Matrix4f();
// Rotate the origin position
Vector3f pos = new Vector3f(new Vector3f(blockX, blockY, blockZ));
matrix.m03 = pos.x;
matrix.m13 = pos.y;
matrix.m23 = pos.z;
Vector3f rot = new Vector3f(new Vector3f(0, 1f, 0f));
Matrix4f.rotate((float) Math.toRadians(45f), rot, matrix, matrix);
Vector3f locationMin = new Vector3f(matrix.m03, matrix.m13, matrix.m23);
// Rotate the position with the size
// Top left back is the position of the block
Vector3f sizeRot = new Vector3f(new Vector3f(blockX + size, blockY + size, blockZ + size));
matrix = new Matrix4f();
matrix.m03 = sizeRot.x;
matrix.m13 = sizeRot.y;
matrix.m23 = sizeRot.z;
rot = new Vector3f(new Vector3f(0, 1f, 0f));
Matrix4f.rotate((float) Math.toRadians(45f), rot, matrix, matrix);
Vector3f locationMax = new Vector3f(matrix.m03, matrix.m13, matrix.m23);
// Then here I use the locationMax and the locationMin to render the cube
What could be wrong with this code? Is the logic I am using to rotate the box correct? as in rotate the origin position then rotate the origin position plus the size..
EDIT: I released that rotating after translating is stupid so instead I just rotated the locationMax which is not translated (it is only the size) then I translated and I still get the same result (Graphical Artifacts).
New Code:
float rx = blockX, ry = blockY, rz = blockZ;
Matrix4f matrix = new Matrix4f();
Vector3f rot = new Vector3f(0, 1f, 0f);
matrix = new Matrix4f();
matrix.m03 = size;
matrix.m13 = size;
matrix.m23 = size;
Matrix4f.rotate((float) Math.toRadians(45f), rot, matrix, matrix);
matrix.translate(new Vector3f(rx, ry, rz), matrix);
float mx = matrix.m03;
float my = matrix.m13;
float mz = matrix.m23;
// Here is use rx, ry, rz and mx, my, mz to render the box
============ * I figured it out (See below)* =============
EDIT:
This is what I ended up doing:
// Origin point
Vector4f a = new Vector4f(blockX, blockY, blockZ, 1);
// Rotate a matrix 45 degrees
Matrix4f mat = new Matrix4f();
mat.rotate((float) Math.toRandians(45f), new Vector3f(
0, 1f, 0), mat);
/* Transform the matrix to each point */
Vector4f c = new Vector4f(size.x, 0, size.z, 1);
Matrix4f.transform(mat, c, c);
Vector4f.add(c, a, c);
Vector4f b = new Vector4f(size.x, 0, 0, 1);
Matrix4f.transform(mat, b, b);
Vector4f.add(b, a, b);
Vector4f d = new Vector4f(0, 0, size.z, 1);
Matrix4f.transform(mat, d, d);
Vector4f.add(d, a, d);
// Here is use a, b, c, and d to render the box.
The problem with this is that I want to rotate around all axises and not only around the Y axis. This makes the code very long and unreadable and There are a lot of bugs when I try to rotate around all axises.
Update Question:
How do I take the above code and make it so I can rotate around all 3 axises. I want to do this so I can have a billboard that will always face the camera.
This is how I calculate the angle between the camera and the object:
Vector3f angle = new Vector3f();
// Calculate the distance between camera and object
Vector3f.sub(game.getCamera().getLocation(),
new Vector3f(blockX, blockY, blockZ), angle);
// Calculate the angle around the Y axis.
float vectorAngle = (float) ((float) Math.atan2(angle.z, angle.x) * -1 + (Math.PI / 2.0f));
Billboards are a very common application of computer graphics (as I'm sure you've noticed, since you're asking the question!)
Ultimately I think you are over complicating the problem, based on:
as in rotate the origin position then rotate the origin position plus the size..
For computer graphics, the most common transformations are Scaling, Translating, and Rotating, and you do these in an order to achieve a desired effect (traditionally you scale, then rotate about the origin, then translate the vertex's position).
Additionally, you will have three main matrices to render a model in 3d: World Matrix, View Matrix, and Projection Matrix. I believe you are having misunderstandings of transforming from Model Space to World Space.
Graphics TRS and Matrix info. If you are having conceptual problems, or this answer is insufficient, I highly recommend looking at this link. I have yet to find a better resource explaining the fundamentals of computer graphics.
So right at the moment, you have your three angles (in degrees, in a Vector3) corresponding to the angle difference in the X,Y, and Z coordinate spaces from your billboard and your camera. With this information, we generate the View matrix by first gathering all of our matrix transformations in one place.
I'm going to assume that you already have your Translation and Scaling matrices, and that they both work. This means that we only need to generate our Rotation matrix, and then transform that matrix with the scaling matrix, and then transforming that matrix by our translation matrix.
X Rotation Matrix
Y Rotation Matrix
Z Rotation Matrix
(Images taken from CodingLabs link above)
So you will generate these three matrices, using the X,Y, and Z angles you calculated earlier, and then transform them to consolidate them into a single matrix, transform that matrix by the scaling matrix, and then transform that matrix by the translation matrix. Now you have your awesome matrix that, when you multiply a a vertex by it, will transform that vertex into the desired size, rotation, and position.
So you transform every single vertex point by this generated matrix.
And then after that, you should be done! Using these techniques will hopefully simplify your code greatly, and set you on the right path :)
So now how about some code?
//I do not guarantee that this code compiles! I did not write it in an IDE nor did I compile it
float angleToRotX = 180f;
float angleToRotY = 90f;
float angleToRotZ = 0f;
// example vertex
Vector4f vertex = new Vector4f(0, 1, 0, 1);
// Rotate vertex's X coordinates by the desired degrees
Matrix4f rotationXMatrix = new Matrix4f();
rotationXMatrix.rotX(angleToRotX);
Matrix4f rotationYMatrix = new Matrix4f();
rotationYMatrix.rotY(angleToRotY);
Matrix4f rotationZMatrix = new Matrix4f();
rotationZMatrix.rotZ(angleToRotZ);
//now let's translate it by 1.5, 1, 1.5 in the X,Y,Z directions
Matrix4f translationMatrix = new Matrix4f();
translationMatrix.setTranslate(new Vector3f(1.5, 1, 1.5));
/*
Now we have our three rotational matrices. So we multiply them (transform them) to get a single matrix to transform all of the points in this model to the desired world coordinates
*/
Matrix4f rotationMatrix = new Matrix4f();
rotationMatrix.mul(rotationXMatrix);
rotationMatrix.mul(rotationYMatrix);
rotationMatrix.mul(rotationZMatrix);
Matrix4f worldMatrix = translationMatrix;
worldMatrix.mul(rotationMatrix);
//now worldMatrix, when applied to a vertex, will rotate it by X,Y,Z degrees about the origin of it's model space, and then translate it by the amount given in translationMatrix
worldMatrix.transform(vertex);
//now vertex should be (1.5, 0, 1.5, 1) with (x,y,z,1)
Now this code could really be simplified, and it is excessively verbose. Try it out! I don't have java downloaded on my machine, but I grabbed the methods from the java documentation Here
Here is an image of what is happening (again, taking from coding labs):
(Advanced Info: Quaternions. These are really cool way of orienting a model in 3d space, however I don't quite understand them to the degree I need to in order to explain it to someone else, and I also believe that your problem is more fundamental)
You could generate the matrix without much hassle. The OpenGL matrix looks like the following:
|lx,ux,vx,px| - lx,ly,lz = the left vector
|ly,uy,vy,py| - ux,uy,uz = the up vector
|lz,uz,vz,pz| - vx,vy,vz = the view vector
|0 ,0 ,0 ,1 | - px,py,pz = the translation
All you need to do, is set px,py,pz to the position of your box in the world,
your view vector to the normalized(camera position - box position), your up comes straight from your camera, and the left is calculated via normalized cross product. It's also good practice to reconstruct the up vector, after left one is derived (by another cross product). That's all there's to it.
My solution aims to save you some time coding, rather than explain everything in detail. Hope that is useful to someone.
I'm trying to rotate a rectangular Slick2d image with pixel size 666 x 333 using LWJGL. I was able to rotate a square image with pixel size 666 x 666 around its center, but the rectangular image does distort during the rotation and this is my problem.
Here is the image I use for testing purposes:
http://i.stack.imgur.com/0bjr5.jpg
The left window shows the image before the rotation, the right window shows the image how it looks when I rotate it 90 degrees, it's distorted:
http://i.stack.imgur.com/FGcNB.jpg
Here is my source code snippet for the rotation:
float x = 0.335f;
float y = 0.335f;
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(x, y, 0f);
glRotatef(angle, 0f, 0f, 1f);
glTranslatef(-x, -y, 0f);
glMatrixMode(GL_MODELVIEW);
You may wonder why I don't use the function “setRotation” or “rotate” of a Slick2d Image. The reason I don't use this does not matter here, but I simply can't use it in my real project and furthermore I want to do it with gl.
It's the first time ever I touch LWJGL and Slick2d and I need it only for a small part of my project. If you know how to rotate the image like above without the distortion, please help me. Thank you.
The problem could be because:
You are using Slick-2D. glRotatef and glTranslatef require a Z coordinate. This could confuse slick 2D. Also what is your angle variable? glTranslatef translates the position of a quad. With lwjgl 3D this would be used to translate the object. glRotatef uses vector rotation. Try researching vector rotation.
Here is a simple pseudocode formula:
Calculate the sine and cosine of the angle once. Dim cosTheta As Double, sinTheta As Single cosTheta = Cos(DegreesToRadians(Angle)) sinTheta = Sin(DegreesToRadians(Angle)) ' Get the disance between the center and the point. Dim dblDistanceX As Double, dblDistanceY As Double dblDistanceX = (PointX - CenterX) dblDistanceY = (PointY - CenterY) ' Set the default position. ReturnX = CenterX ReturnY = CenterY 'Update with the Y offset ReturnX = (ReturnX + dblDistanceY * sinTheta) ReturnY = (ReturnY + dblDistanceY * cosTheta) 'Update with the X offset ReturnX = (ReturnX + dblDistanceX * cosTheta) ReturnY = (ReturnY - dblDistanceX * sinTheta)
90 degree rotation is extremely simple. Just rotate the quad and rebind texture. If you can't do this, then make a 90 degree rotated texture. Just ask if you want another answer with my 90 degree rotation code. I tried to explain how you could use vectors for 360 degree rotation.
I need to rotate a triangle so that it lies on a plane given by a normal n and a constant d.
I have the normal n1 of the plane that the two triangles lie in. Now i need to rotate the right red triangle so that it results in the orange one.
The points of the triangles and the normals are stored as 3-dimensional vectors.
Until now, I did the following:
Get the normalized rotation quaternion (rotQuat) between n1 and n2.
Multiply every point of the triangle by the quaternion. Therefore I convert the point to a quaternion(point.x, point.y, point.z, 0) and do the multiplcation as follows: resultQuat = rotQuat * point * conjugate(rotQuat). I then apply x, y and z of the result to the point.
This is how i get the rotation between two vectors:
public static Quaternion getRotationBetweenTwoVector3f(Vector3f vec1, Vector3f vec2)
{
Vector3f cross = Vector3f.cross(vec1, vec2);
float w = (float) (java.lang.Math.sqrt(java.lang.Math.pow(vec1.getLength(), 2) * java.lang.Math.pow(vec2.getLength(), 2)) + Vector3f.dot(vec1, vec2));
Quaternion returnQuat = new Quaternion(cross.x, cross.y, cross.z, w);
returnQuat.normalize();
return returnQuat;
}
The problem is that the triangle has the correct orientation after the rotation, but the triangle also moves it's position. I need a rotation that rotates the triangle so that it's still connected to the two points of the left red triangle (like the orange one).
How is this possible?
Your problem is that rotation matrix/quaternions rotate points around an axis that passes through the origin. To rotate around different point than the origin, you need to translate the triangle points to the origin (just Substract the rotation point value from the triangle points), then multiply by the quaternion and then translate back.
So the algorithm becomes:
translatedPoints[i] = triPoints[i] - rotationPoint;
translatedPoints rotate using quaternion
translate translatedPoints back by adding the rotation point value.
I want to use the heading() function in the PVector class, but I am using P3D and have an x,y,and z for my PVector. How would I re-write this function to allow it to work for 3D space? My goal is to do something like:
size(100, 100, P3D);
PVector v = new PVector(.2, .11, .54);
rotate( v.heading() ); //set rotation from PVector named v
line(0, 0, 10, 0); //draw line that will be rotated in correct direction
The above code doesn't display the correct rotation in 3D space since v.heading() is only suited for 2D coordinate space. How can I achieve this using rotateX(), rotateY(), rotateZ()? I'd like to avoid using a quaternion if possible and use the rotate functions.
Thanks in advance!!
Using the heading() function in 2D is transforming 2D Cartesian coordinates (x,y) into 2D polar coordinates (radius, angle). A 3D version of polar coordinates is spherical coordinates:
The 3D point P can be represented as three linear coordinates (x,y,z) or one linear coordinate and two angles (rho, theta, phi). Rho is the length of the vector, theta is the angle in the x-y plane, and phi is the angle in the angle into the z plane. These equations describe the conversion:
rho = sqrt(x^2 + y^2 + z^2)
phi = arccos(z/rho)
theta = arctan(y/x)
You should be able to use the rotateX(), etc functions using these angles. Note that this uses the mathematics convention for the angle names theta and phi; in physics, these labels are reversed from what's shown above.
What kevinsa5 said, except use the inverse sine function to get the elevation. Use the atan2 function for the azimuth (or better, simply use the vector's 2D heading method). And use the vector's mag method for its magnitude.
rho = v.mag();
phi = asin(v.z/rho);
theta = atan2(v.y, v.x);
Working backwards, think "X - Y - Z" and try:
PVector p = new PVector(v.mag(), 0, 0); // X
rotateY3D(p, phi); // Y
rotateZ3D(p, theta); // Z
Then compare p with the original v.
it seems that there is a problem with my custom Quaternion implementation.
Download My quaternion implementation in Java.
When I lauch this snippet, in order to see quaternion angle evolutions, in a Main() method :
Quaternion currentRotation = Quaternion.buildIdentityQuaternion();
Quaternion constantRotation = Quaternion.buildFromAxisAngle(10, 0,1,0);
while(true){
float angle = currentRotation.toAxisAngle()[0];
System.out.println(angle);
currentRotation = constantRotation.mulInLeftOf(currentRotation);
}
I've got the following results :
0.0
9.99997
19.999975
29.999979
39.99998
49.999977
59.999977
69.99998
79.99997
89.99997
99.99997
109.99997
119.99997
129.99997
139.99997
149.99997
159.99997
169.99997
179.99997
189.99998
199.99998
209.99998
219.99998
230.0
240.0
250.00002
260.00003
270.00003
280.00003
290.00006
300.0001
310.00012
320.00015
330.00024
340.00037
350.00082
360.0
350.00012
340.0001
330.0001
320.0001
310.00006
300.00006
290.00006
So why does the angle value first goes to 360 degrees then decreases toward 0 ? Though I've computed the angle with the formula 2*Acos(Quaternion.w) in Quaternion#toAxisAngle() method ? Maybe the implementation is not bad, so how can I compute the angle so that it returns 0, 10, ...,350, 360, 0, 10, ..., 350, 360, 0, 10 and so on ?
And finally, is there a way to compute the real angle ? SO that angle goes across values : 0,10,20,30,...,360,0,10,20... ?
However I managed to use it in a JOGL program to make a Simple 6-color cube rotate regularly, simply by computing a quaternion multiplication each time and by calling toMatrix() method on the result quaternion. What worked (do not pay attention to JOGL specific implementation details) :
// The OpenGL functionnalities of my program
MyJOGLEventListener implements GLEventListener {
Quaternion myCurrentRotation = Quaternion.buildIdentityQuaternion() // w=1, x=0, y=0, z=0
Quaternion constantRotation = Quaternion.buildFromAxisAngle(0.02f, 0,1,0) // angle = 0.02 degrees, x=0, y=1, z=0
GLUgl2 glu = new GLUgl2();
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(/* OMITTED : color buffer and depth buffer*/);
gl.glLoadIdentiy();
glu.gluLookAt(/* OMITTED */);
/// the three most relevent lines ///////////////////////////////////
gl.glMultMatrix(myCurrentRotation.toMatrix(), 0);
MyCubeDrawer.drawCube(gl);
myCurrentRotation = constantRotation.mulInLeftOf(myCurrentRotation);
//////////////////////////////////////////////////////////////////////
}
// OMITED : in init(GLAutoDrawable) method, I set up depth buffer
// OMITED : the reshape(GLAutoDrawable drawable, int x, int y, int width, int height) sets the viewport and projection
}
Regards
I suspect that your quaternion implementation is fine. When you pass 360 degrees with a quaternion, it inverts the axis of rotation. So at first, your quaternion represents positive rotations around the positive y axis; however, once you cross 360 degrees, it begins to represent a positive rotation around the negative y axis.
So the angles you are getting are still correct. A rotation of zero is usually represented as [1 0 0 0]. A rotation of 180 degrees around the y axis will be represented as [0 0 1 0]. And then a rotation of 360 degrees (obviously equivalent to a rotation of 0) comes out to be [-1 0 0 0]. Rotating by another 180 degrees will give you [0 0 -1 0] This is a general property of quaternions. They're 2x redundant. If you negate all the components of the quaternion, it's equivalent to rotating the opposite direction around a flipped axis to get the same result.
To get what you wanted, you could just check the y component of your quaternion. If it's less-than-zero, then subtract your computed rotation from 360 in order to flip the axis back to positive.