I would like to get the rotation values form an Object3D according to world axises such as
roation.x, rotation.y, rotation.z
currently when I call
object.rotation.x
I get the rotation value according to the objects local axises.
Thanks.
Sorry for the thread necro.
I had the same problematic, and couldn't find a solution until I read some ThreeJS doc about Euler angles. It became clear all of a sudden.
Three.js uses intrinsic (Tait-Bryan) ordering, also known as yaw, pitch and roll. This means that rotations are performed with respect to the local coordinate system. That is, for order 'XYZ', the rotation is first around world-X, then around local-Y (which may now be different from the world Y-axis), then local-Z (which may be different from the world Z-axis).
Some implementations may use extrinsic (proper) ordering, in which case rotations are performed with respect to the world coordinate system, so that for order 'XYZ', the rotations are around world-X, world-Y, and world-Z.
Converting between the two types is relatively straightforward, you just need to reverse the order and the rotation, so that an intrinsic (three.js) Euler rotation of angles a, b, c about XYZ will be equivalent to to an extrinsic Euler rotation of angles c, b, a about ZYX.
If you need to get the world rotations in XYZ order I suppose you can do the following :
var worldRot = new THREE.Euler();
obj.getWorldRotation().copy(worldRot);
worldRot.reorder("ZYX");
// use worldRot.x, worldRot.y, worldRot.z
To rotate an object in world axis, you can use below function
var rtWorldMatrix;
function rotateAroundWorldAxis(object, axis, radians)
{
rtWorldMatrix= new THREE.Matrix4();
rtWorldMatrix.makeRotationAxis(axis.normalize(), radians);
rtWorldMatrix.multiplySelf(object.matrix);
object.matrix = rtWorldMatrix;
object.rotation.getRotationFromMatrix(object.matrix, object.scale);
}
And call
rotateAroundWorldAxis(objectToRotate, new THREE.Vector3(1,0,0), 90 * Math.PI/180);
Related
I need help in deep understanding of matrix in SVG. I already know about matrix, I want to rotate and scale without using scale or rotate word. I want to use transform='matrix(a,b,c,d,e,f)'. I know 'a/d' value determine the scale, 'e/f' determines the position. tan(b),tan(c) determines the skew. cos(a),sin(b),-sin(c),cos(d) determines the angle.But I want to know how this work, I need thoroughly help in understanding matrix in SVG.
Matrix operations are composed of individual, "local" transformations (i.e. translate, rotate, scale, skew) by matrix concatenation (i.e. multiplication).
For example, if you want to rotate an object by r degrees around a point (x, y), you would translate to (x, y), rotate r degrees, then translate back to the original position (-x, -y).
By what is often referred to as "chaining" (as described above) each successive "local" transformation is combined to produce a result. Therefore, at any location in a chain of transformations, the "local" transformation space (at that location) is composed of all operations that came before.
What this implies is that when transforming some parameter of an SVG element (i.e. translate) the transform is applied to it's current transformation space. So, for example if the element is already rotated 30 degrees, then a translation of (8, 5) would not go 8 to the right and 5 down, but it would go the rotation of (8, 5) by 30 degrees - relative to the current position.
So this is a bit of a gotcha.
One way to help deal with this complication is to decompose transformation matrices into their individual, total transformations (i.e. total translation, total rotation/skew, total scale), but decomposition says nothing about what individual basic transformations went into the combined totals, nor of the order in which they occurred. This is a problem because 2D transformations are not commutative, e.g. translate(x, y)->rotate(r) is not the same as rotate(r)->translate(x, y).
The best way that I've found is to only compose transformations in a certain order and keep track of the totals in that order, then when a new transformation is introduced, used the totals that have been tracked, update the one that is being modified and recompose the entire transformation.
Like so: (pseudo-code)
// EDIT: initialize components (new SVGMatrix returns the identity matrix)
var transX=0, transY=0, rot=0, scaX=0, scaY=0, skwX=0, skwY=0, matrix = new SVGmatrix();
// example rotate
function rotate(svgEl, angle){
rot = rot + angle;
updateTransform();
applyTransform(svgEl);
};
function updateTransform(){
// the order that I've found most convenient
// (others may do it differently)
matrix.translate(transX, transY);
matrix.rotate(rot);
matrix.scale(scaX, scaY);
matrix.skewX(skwX);
matrix.skewY(skwY);
};
function applyTransform(el){
el.transform = matrix;
};
To be clear, this is not suggesting that matrices are not a good way of representing transformations, nor is it suggesting a better way - far from it.
Transformation matrices are a powerful tool, and when used appropriately, they are very effective at handling complex animations, but they are not trivial to use in all cases.
This may be a bit advanced, but for more information about animations using matrix transformations, this short code example provides a wealth of information and references to start from.
http://www.w3.org/TR/2011/WD-css3-2d-transforms-20111215/#matrix-decomposition
Update:
Just a note about the decomposed skew factor proposed at the above link.
Only a single skew factor ( in x ) is computed because skewing in both x and y is equivalent to a skew in x and a combined ( offset ) rotation.
Combining x skew and y skew ( with or without a rotation or translation, as in my above preferred composition order ) will result in a different x skew, rotation ( e.g. non-zero rotation if none was originally composed ), and translation ( e.g. an offset by some amount relative to the decomposed rotation in lieu of the original y skew ), but no recoverable y skew - using the linked decomposition method.
This is a limitation of composed affine matrices. So producing a final result matrix should generally be considered a one-way computation.
i'm writing a server for a game me and my friends are making. I want to keep the direction a certain player is looking at in a 3D plane in a variable. I was considering having it an object with two variables of radians, i.e vertical angle and horizontal angle. But my friend told me to store it the way Three.js stores it because it would make his life easier. Could anybody help me out here?
You should brush up on Math for Game Developers series: https://www.youtube.com/watch?v=sKCF8A3XGxQ&list=PLW3Zl3wyJwWOpdhYedlD-yCB7WQoHf-My&index=1
Specifically, using vectors. You should store the orientation / facing angle of your characters or entities as a Vector3, or a 3 dimensional vector. In THREE.js, that's new THREE.Vector3( x, y, z )
To get the direction of object A to object B, relative to A you would do:
var direction = posB.clone().sub( posA )
This clones position B so we don't mess it up by subtraction, and then immediately subtract it by A.
However you'll notice how the vector now has some length. This is often undesirable in calculations, for example if you wanted to multiply this direction by something else say, a thrust force. In this case, we need to normalize the vector:
direction.normalize()
Now you can do fun stuff like:
posA.add( direction.clone().multiplyScalar( 10.0 ) );
This will move posA in the direction towards posB, 10 units of space.
I'm using a large array of objects built around a center point in a scene, and need to manipulate them all around their local axis. They are all facing the origin using a blank object and lookAt(), then I used this method to align the other axes correctly. Getting the initial rotation this way worked great, unfortunately when I try to rotate these objects on the fly with object.rotation.x = <amount>, it does not respect the local axis of the object.
The confusing part is, it's not even using the global axis, the axis it's using almost seems entirely arbitrary. I set up a JSFiddle to demonstrate this here. As you can see on line 129, looker.rotation.z works correctly, it rotates along the Z axis properly, but if it's changed to X or Y, it doesn't rotate along local or global axes. If anyone could demystify what is happening to cause this, that would be great.
What is happening is that you want to add some rotation to the current orientation, and setting the variable looker.rotation.z means other thing.
At the end, to calculate the rotation matrix of the looker, there will be something like (pseudocode: the functions are not these, but you get the idea):
this.matrix.multiply( makeXRotationMatrix(this.rotation.x) )
this.matrix.multiply( makeYRotationMatrix(this.rotation.y) )
this.matrix.multiply( makeZRotationMatrix(this.rotation.z) )
DrawGeometry(this.geom, this.matrix)
and composition of rotations are not intuitive. This is why it doesn't seem to follow any axis system.
If you want to apply a rotation in some axis to the existing matrix, it can be made with the functions rotateX (angle), rotateY (angle), rotateZ (angle), and rotateOnAxis (axis, angle). axis can be a THREE.Vector3.
Changing directly looker.rotation.z works because it is the nearest rotation to the geometry, and it will not be affected by the other rotations (remember that transformation matrices apply in inverse order, e.g. T*R*G is Rotating the Geometry, and then, Translating it).
Summary
In this case I suggest not to use the line:
looker.rotation.z += 0.05;
Use
looker.rotateZ (0.05);
or
looker.rotateX (0.05);
instead. Hope this helps :)
i'm using Three.js (without shaders, only with existing objects methods) in order to realize animations, but my question is very simple : i'm sure it's possible, but can you tell me (or help me) how should i combine several animations on a shape ? For example, rotating and translating a sphere.
When i'm doing :
three.sphere.rotation.y += 0.1;
three.sphere.translateZ += 1;
the sphere rotates but the translation vector is also rotating, so the translation has no effect.
I know a bit openGL and i already have used glPushMatrix and glPopMatrix functions, so do them exist in this framework ?
Cheers
Each three.js object3D has a position, rotation and scale; the rotation (always relative to its origin or "center") defines its own local axis coordinates (say, what the object sees as its own "front,up, right" directions) and when you call translateZ, the object is moved according to those local directions (not along the world -or parent- Z axis). If you want the later, do three.sphere.position.z += 1 instead.
The order of transformation is important. You get a different result if you translate first and then rotate than if you rotate first and then translate. Of course with a sphere it will be hard to see the rotation.
I'm new to three.js and 3d programming in general, so this may seem like a very simple question. Ideally, I hope the answer can help me understand the underlying principles.
I have an object that needs to "point" at another point (the origin, in this case, for simplicity), which can be done easily with the Object3D.lookAt(point) function. This points the Z axis of the object at the point nicely.
I also want to rotate my object, called looker, around its Z axis such that its X axis points generally towards another object, refObj. I know that the X axis can't point directly at the refObj unless that object happens form a right angle with the origin. I want the X axis of looker to lie on the plane created by origin, refObj and looker, as diagramed below:
The simplest way of doing the rotation would seem to be to modify looker.rotation.z, but I don't know how to calculate what the value should be.
In general, I would like an extended version of the lookAt function which takes a second coordinate to which the X axis would be oriented. Something like this:
function lookAtAndOrient(objectToAdjust, pointToLookAt, pointToOrientXTowards)
{
// First we look at the pointToLookAt
objectToAdjust.lookAt(pointToLookAt);
// Then we rotate the object
objectToAdjust.rotation.z = ??;
}
I have created a jsFiddle with the example diagramed above
What you are really saying is you want the y-axis of the object (the object's up-vector) to be orthogonal to the plane.
All you have to do is set the object's up-vector before you call lookAt( origin ).
You compute the desired up vector by taking a cross-product of two vectors you know lie in the plane.
three.js r.143