CSS3 Matrix rotation - javascript

I have a CSS 3D cube that I'm trying to rotate left/right/up/down straight as it appears to user. If I use css rotation functions, then I rotate the axis, not the cube.
There are lots of articles on the web about X,Y,Z matrix rotation calculation, but I've spend days now trying to set this thing and none of this information really helps me.
The work around to my problem would be a WebKitCSSMatrix object, which has its own rotation functions that work as magic. An example on Fiddle: http://jsfiddle.net/joecritch/tZBDW/. But again, that relies only uppon Webkit, but I need to be crossbrowsy here.
Now, there are 3 steps on the way of success:
1) I need to get current matrix, set directional vector (1,0,0 for up/down and 0,1,0 for left/right rotations) and set the angle. DONE.
2) I need to calculate new rotation vector based on current matrix. DONE.
3) I need to actually rotate my current matrix by new vector and angle. PROBLEM.
var newMArray = deMatrix(".cube");//getting current matrix from CSS
var v = [vecX, vecY, vecZ, 0];//current vector (1,0,0) or (0,1,0)
var newV = newMVector(newMArray, v);//calculating new vector for current matrix
//getting the angle for each axis based on new vector
angleX = newV[0]*angle;
angleY = newV[1]*angle;
angleZ = newV[2]*angle;
this.rotateX -= angleX;
this.rotateY -= angleY;
this.rotateZ -= angleZ;
//calculating the rotation matrix
var rotationXMatrix, rotationYMatrix, rotationZMatrix, s, transformationMatrix;
rotationXMatrix = $M([[1, 0, 0, 0], [0, Math.cos(this.rotateX * deg2rad), Math.sin(-this.rotateX * deg2rad), 0], [0, Math.sin(this.rotateX * deg2rad), Math.cos(this.rotateX * deg2rad), 0], [0, 0, 0, 1]]);
rotationYMatrix = $M([[Math.cos(this.rotateY * deg2rad), 0, Math.sin(this.rotateY * deg2rad), 0], [0, 1, 0, 0], [Math.sin(-this.rotateY * deg2rad), 0, Math.cos(this.rotateY * deg2rad), 0], [0, 0, 0, 1]]);
rotationZMatrix = $M([[Math.cos(this.rotateZ * deg2rad), Math.sin(-this.rotateZ * deg2rad), 0, 0], [Math.sin(this.rotateZ * deg2rad), Math.cos(this.rotateZ * deg2rad), 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]);
transformationMatrix = rotationXMatrix.x(rotationYMatrix).x(rotationZMatrix);//getting all axis rotation into one matrix
Than I'm setting new transformation matrix to my CSS Cube. The problem is - it doesn't rotate as it should. Now I'm using Sylvester plugin to do all matrix calculation.
So, please help me on how to use my new vector for proper matrix rotation.

I am having a very hard time following your code. But if I understand it correctly you are going around a basic problem really backwards.
Your starting point is an object that has a matrix transform. You want to change that transform. At this point it is very tempting to just try things and see what sticks. No offense, but that is what your code looks like it is doing. What you really need is to understand how matrices work. There are lots of good tutorials. (first google hit: http://chortle.ccsu.edu/vectorlessons/vectorindex.html) It will take some time but help a lot in the long run.
The basic issue you are facing is that matrix multiplication is no commutative. A * B != B * A for matrices. Depending on what matrix you are setting it includes a lot of transformations where order matter: (A) Move the object to it's origin (B) Rotate the object around it's origin (C) Move the object to a position in the world (D) Move the object to where the camera is at the origin (E) Rotate around the camera. The matrix you see is just A * B * C * D * E. Now depending on what you want to do you better have a good plan. In most cases you either want to rotate the object or the camera and you can just multiply either on the left or right side. Your code looks a little bit like you are multiplying on the wrong side and trying to jump through hoops to compensate for that which somewhat works because a lot of the matrices are identity.
So even more practical: Get your cube matrix, make a rotation matrix independent of it (no -angle!), and set back rotation*cubematrix as your new transform.

Sylvester can generate rotation matrixes as well. Looking at the fiddle example - the webkit function that seems to do the rotation:
// Rotate the Matrix around the transformed vector
var newMatrix = m.rotateAxisAngle(vector.x, vector.y, vector.z, angle);
Looks like it's more along the lines of the Matrix.Rotation(angle [, axis]) function, I think you'd provide axis as a Sylvester Vector object, rather than the webkit x,y,z arguments - http://sylvester.jcoglan.com/api/matrix.html#rotation
Multiplying the x,y,z matrices doesn't work too well because the additional transforms will be applied on the new context. I've just fallen into this trap with this js/canvas page: http://benjaminbenben.com/projects/twittny_test/

Related

p5.Vector not respecting angleMode

I've noticed that when rotating vectors, the rotation is done in radians even after I have called angleMode with DEGREES. This behaviour only appears with vectors declared using the new p5.Vector syntax, while using createVector avoids it.
Minimal reproducible example: (paste into p5 web editor or OpenProcessing)
function setup() {
createCanvas(400, 400)
translate(100, 100) // To see the effect more clearly
angleMode(DEGREES)
let v = new p5.Vector(1, 0)
line(0, 0, v.x * 50, v.y * 50)
v.rotate(HALF_PI)
line(0, 0, v.x * 50, v.y * 50)
}
Notice that the rotation is still done in radians. If you replace new p5.Vector with createVector then the problem disappears. Why is this?
Since mathematically functions like sin() are effected, there is no good reason why p5.Vector.rotate should not be effected.
However it is not intended to construct a vector like you did. You should use createVector() to create a vector. This function not only creates the object, but sets all internal attributes so that the objects behave as intended.
This behavior is not explained directly for rotate(), however it is documented for heading():
Calculate the angle of rotation for this vector(only 2D vectors). p5.Vectors created using createVector() will take the current angleMode into consideration, and give the angle in radians or degree accordingly.

Does the order of indices matter?

this._vertices = new Float32Array([
-0.5, 0, 0, // left
0, 0.5, 0, // top
0.5, 0, 0 // right
]);
this._indicies = new Uint16Array([0, 1, 2]);
As you can see I have 3 points for a triangle. The problem with this is that my triangle doesn't end up getting rendered unless I change the indices to
this._indicies = new Uint16Array([0, 2, 1]);
do you know why that is? Why does the order of the indices matter? And how do I know the correct order to put the indices in?
Ps. It works when setting the draw type to LINE_LOOP but it doesn't work on triangles.
If culling is on gl.enable(gl.CULL_FACE) then triangles are culled if their vertex are counter clockwise in clip space (ie, after the vertex shader). You can choose which triangles, clockwise or counter-clockwise get culled with gl.cullFace(...)
0 0
/ \ / \
/ \ / \
2-----1 1-----2
clockwise counter-clockwise
Order of vertices does indeed matter if face culling is enabled. What's the front and what's the back of a triangle depends on the set winding order. If counterclock winding is enabled (the default) then faces which vertices appear in counterclock wise order on the screen are considered "front" side.
If culling is enabled then only triangle upon which you look from a selected side are drawn.

Threejs Transform Matrix ordering

I would like to know how threejs ordering multiple matrix?
For instance ,
......
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0, 20, 0 ); // T , transform matrix
mesh.rotation.set( 0, Math.PI, 0 );//R , rotation matrix
mesh.scale.set( 1, 1, 10 );//S , scale matrix
So , how threejs to combine three matrix? It will according my set value order(In my example , it is TRS , so final matrix should T*R*S ) or fixed order (For instance, it is always using SRT ordering , the finally matrix is S*R*T)?
You can specify the parameters as you have done so long as the mesh property 'matrixAutoUpdate' is true and you only want it in order by scale, rotation then translation (typical).
If you need something more complicated, such as a specific series of translations and rotations, then you should set matrixAutoUpdate to false and calculate the matrix yourself.
Important note: when using the matrix multiply function, you must do it in 'reverse' order. For example if you want to position a limb then logically you would:
1) do local rotation (such as arm up/down)
2) move limb with respect to its offset (put it at its joint)
3) rotate according to body rotation
4) move to body offset
The actual operations would be done in reverse:
arm_mesh.matrixAutoUpdate = false;
var mat4: THREE.Matrix4 = new THREE.Matrix4();
var arm_matrix = arm_mesh.matrix;
arm_matrix.identity(); // reset
arm_matrix.multiply(mat4.makeTranslation(body_pos.x, body_pos.y, body_pos.z));
arm_matrix.multiply(mat4.makeRotationFromQuaternion(body_rotation));
arm_matrix.multiply(mat4.makeTranslation(arm_offset.x, arm_offset.y, arm_offset.z));
arm_matrix.multiply(mat4.makeRotationFromEuler(new THREE.Euler(arm_angle, 0, 0)));
Of course this does not utilize or account for parent/child relationships.

Three.js camera controls for space game

In a three.js project, I'm using a modified version of PointerLockControls.js for the camera control. I want to modify the rotation functionality so that there is no absolute "up" axis by which the camera rotates, but rather moving the mouse up or down will pitch indefinitely, same for left and right for yawing (and keys for rolling).
I can't seem to get the yawing component working, as it seems to rotate around the same axis regardless of pitch. (ie moving left or right when face facing straight upwards will just rotate the camera)
Any help in the right direction would be great!
I had the same problem recently, so I had a look at some of the THREE.*Controls files, similar to you.
Using those as a basis, I made this:
https://github.com/squarefeet/THREE.ObjectControls
The important bits are the following (see here for context):
var updateTarget = function( dt ) {
var velX = positionVector.x * dt,
velY = positionVector.y * dt,
velZ = positionVector.z * dt;
rotationQuaternion.set(
rotationVector.x * dt,
rotationVector.y * dt,
rotationVector.z * dt,
1
).normalize();
targetObject.quaternion.multiply( rotationQuaternion );
targetObject.translateX( velX );
targetObject.translateY( velY );
targetObject.translateZ( velZ );
};
The rotationVector is probably of most interest to you, so here's what it's doing:
It's using a THREE.Vector3 to describe the rotation, the rotationVector variable in this example.
Each component of the rotationVector (x, y, z) is relative to pitch, yaw, and roll respectively.
Set a quaternion's x, y, and z values to the of the rotation vector, making sure the w component is always 1 (to learn what the w component does, see here, it's a great answer.
Normalizing this quaternion will get us a quaternion of length 1, which is very handy when we come to the next step...
targetObject in this case is an instance of THREE.Object3D (a THREE.Mesh, which inherits from THREE.Object3D), so it has a quaternion we can play with.
So now, it's just a matter of multiplying your targetObject's quaternion by your shiny new rotationQuaternion.
Since our object is now rotated to where we want, we can move it along it's new axis angles by using translateX/Y/Z.
The important thing to note here is that quaternions don't act like Euler vectors. Rather than adding two quaternions together to get a new angle, you multiply them.
Anyway, I hope that helps you somewhat!

Why is the sequence important for matrix transitions like rotate and translate transform at the same time

I want to animate a matrix3d with rotation and translation at the same time. The strange thing is i get completely different results putting the rotation first or the translation first.
i have two fiddles to show the difference. i dont understand that.
http://jsfiddle.net/wetlip/2nuQu/ rotate before translation
http://jsfiddle.net/wetlip/Z3MTX/ translation before rotate
var el = document.getElementById("aa2");
var matrix = new MSCSSMatrix(el.style.transform);
matrix = matrix.rotateAxisAngle(0, 1, 0, 85);
matrix = matrix.translate(300, 0, 0);
el.style.transform = matrix;
gives a quite different result as
var el = document.getElementById("aa2");
var matrix = new MSCSSMatrix(el.style.transform);
matrix = matrix.translate(300, 0, 0);
matrix = matrix.rotateAxisAngle(0, 1, 0, 85);
el.style.transform = matrix;
These operations are applied via matrix multiplication which isn't commutative.
http://en.wikipedia.org/wiki/Matrix_multiplication
Rotation occurs about the origin.
If you want to rotate an object that is not at the origin you have to first translate it to the origin, rotate it, and then translate it back.
If you rotate an object that is not at the origin you effectively move and rotate it in an unexpected way.

Categories