Three.js - rotating an Object3D around an axis - javascript

I'm trying to rotate a mesh loaded into an Object3D using OBJMTLLoader.
var obj = new THREE.Object3D();
// loading and stuff
obj.rotation.y += 0.1; //inside the update function
This works as it should, but only for y and z axes. Using the same code, but for the x axis yields the same result as rotating it around the z axis, but clockwise instead of counterclockwise.
Unfortunately, I need to rotate it around the x axis.
var xAxis = new THREE.Vector3(1,0,0);
obj.rotateOnAxis( xAxis, 0.1 );
This does rotate the object around the x axis.
However, I want to tween the rotation of the object, so I need a way to explicitly change the angle an object is rotated by, instead of rotating it for a specific amount.
Any ideas why obj.rotation.y and obj.rotation.z work properly, but obj.rotation.x doesn't?

Upon loading the mesh (before trying to rotate it around the x axis), I rotated it by 90 degrees around the y axis. Because of the default Euler order (which is XYZ), the local axes no longer corresponded to the world axes.
obj.eulerOrder = 'YXZ';
Using the above line of code before rotating the mesh around the y axis solved the problem.
A pretty good explanation of Euler order can be found here.

Related

Updating an intrinsic rotation with an extrinsic rotation

I am trying to model a Rubik's Cube for a personal project, using Zdog for lightweight 3d graphics. Zdog uses a {x,y,z} vector to represent rotation - I believe this is essentially a Tait-Bryan angle.
To animate a rotation of the top, right, front, etc side, I attach the 9 blocks to an anchor in the center of the cube and rotate it 90 degrees in the desired direction. This works great, but when the animation is done I need to "save" the translation and rotation on the 9 blocks. Translation is relatively simple, but I'm stuck on rotation. I basically need a function like this:
function updateRotation(xyz, axis, angle) {
// xyz is a {x,y,z} vector
// axis is "x", "y", or "z"
// rotation is the angle of rotation in radians
}
that would apply the axis/angle rotation in world coordinates to the xyz vector in object coordinates. Originally I just had xyz[axis] += angle, but this only works when no other axis has any rotation. I then thought I could use a lookup table, and I think that's possible as I only use quarter turns, but constructing the table turns out to be harder than I thought.
I am starting to suspect I need to translate the xyz vector to some other representation (matrix? quaternion?) and apply the rotation there, but I'm not sure where to start. The frustrating thing is that my blocks are in the right position at the end of the animation - I'm just not sure how to apply the parent transform so that I can detach them from the parent without losing the rotation.
As far as I can tell, this can't be done with Euler angles alone (at least not in any easy way). My solution was to convert to quaternions, rotate, then convert back to Euler:
function updateRotation(obj, axis, rotation) {
const {x, y, z} = obj.rotate;
const q = new Quaternion()
.rotateZ(z)
.rotateY(y)
.rotateX(x);
const q2 = new Quaternion();
if (axis === 'x') {
q2.rotateX(rotation);
} else if (axis === 'y') {
q2.rotateY(rotation);
} else if (axis === 'z') {
q2.rotateZ(rotation);
}
q.multiply(q2, null);
const e = new Euler().fromQuaternion(q);
obj.rotate.x = e.x;
obj.rotate.y = e.y;
obj.rotate.z = e.z;
obj.normalizeRotate();
}
This uses the Euler and Quaternion classes from math.gl.
(It turned out Zdog actually uses ZYX Euler angles as far as I could tell, hence the order of rotations when creating the first quaternion.)

Get rotation from camera matrix of format x y z w

I have a 4x4 matrix within JS called world to obj. This matrix I assume from context must be the camera transformations matrix and thus I am trying to extract the rotation from it in radians on x y and z axis.
I have no clue where to start and have tried many things
for context this below image it the camera transformations with no rotation
This second one is with rotation of 1 radian is applied to each axis. it is important to note that this camera is orbiting as well in this example

Three JS Creating 3D block start position end position

Im trying to simulate laser shooting from moving object to another moving object.
If I have two Vector3 coordinates (x,y) in move and i need to render 3D Object start from X Finnish in Y (laser).
Something like this.
I have fixed height and depth of object, i dont know a length, i can get it by x.distanceTo(y). Length will be variable (objects are moving).
It is possible to draw object form X to Y?
What is the best practice?
You can just use a cube and compute it's position, rotation and scale like this:
cube.position.addVectors( x, y ).divideScalar( 2 ); // place cube in the middle
cube.lookAt( y ); // rotate cube so it faces the end position
cube.scale.z = x.distanceTo( y ); // stretch cube

Three.js - Rotating a sphere around a certain axis

I have a problem. In Three.js, I want to rotate a sphere (Earth) around axis tilted by 23.5 degs. I found sphere.rotation.x, sphere.rotation.y and sphere.rotation.z, but when I combine them in the correct ratio, the sphere's rotation is quite weird - it has no permanent rotation axis. I think I need a function like sphere.rotation.vector(1,0,-1). Does anyone know how this function is called and how the correct syntax is?
Many thanks for answers!
You do not have to understand how Euler angles or quaternions work to do what you want. You can use
Object3D.rotateOnAxis( axis, angle );
Object3D.rotateOnWorldAxis( axis, angle );
Make sure axis is a unit vector (has length 1), and angle is in radians.
Object3D.rotateOnAxis( axis, angle ) rotates on an axis in object space.
Object3D.rotateOnWorldAxis( axis, angle ) rotates on an axis in world space.
three.js r.104
You need to use quaternions for this. This video explains what quaternions are and how they are used in 3D graphics.
You can construct a quaternion like this:
quaternion = new THREE.Quaternion().setFromAxisAngle( axisOfRotation, angleOfRotation );
Then you apply it to your object by:
object.rotation.set( new THREE.Euler().setFromQuaternion( quaternion ) );
You can also achieve this by using object hierarchies. For example, you can make an Object3D() instance and tilt it by 23.5 degs, then create a sphere (Earth) and add it to the tilted object. The sphere will then rotate around the tilted Y axis. Quaternions however, are the best tool for solving this.
var quaternion = new THREE.Quaternion();
var object = scene.getObjectByName('xxx');
function render(){
quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0).normalize(), 0.005);
object.position.applyQuaternion(quaternion);
}
three.js version is 86, see full example on codepen.
You can rotate your sphere using th 'ObjectControls' module for ThreeJS that allows you to rotate a single OBJECT (or a Group), and not the SCENE.
Include the libary:
then
var controls = new THREE.ObjectControls(camera, renderer.domElement, yourMesh);
You can find here a live demo here: https://albertopiras.github.io/threeJS-object-controls/
Here is the repo: https://github.com/albertopiras/threeJS-object-controls.
Hope this helps

How do I calculate the rotation along the y-axis given a 2D direction vector?

I'm making a 3D game, and I need the player mesh always facing the back of the camera. I already figured out how to get a 2D speed vector (direction along the x-z plane), but now I need to rotate the mesh in the speed vector's direction...
Basically, every mesh has a .rotation property, and that property is a 3D vector. I am only interested in rotation over the y-axis, that's the one that is perpendicular to the surface (x-z) plane.
The rotation doesn't use degrees, but radians, so I thought it would be something like this:
mesh.rotation.y = (mesh.direction.x - mesh.direction.z)*Math.PI*2;
But this doesn't seem to cut it...
The direction/speed is a, as a said, 2D vector, and it consist of real numbers between -1 and 1. At all times sqrt(x*x + y*y) == 1, so it forms a "circle", this is because speed needs to be equal in all directions, obviously.
The speed vector changes only when I drag the mouse over the screen, and so should the rotation, and it is calculated like this:
var c = Math.sqrt(cameraPos.x*cameraPos.x + cameraPos.z*cameraPos.z); //This is the distance from the camera to the mesh, which is at (0, 0) for simplicity of this presentation.
var rat = 1/c;
mesh.direction.x = cameraPos.x*rat; //Direction vector = the speed vector
mesh.direction.z = cameraPos.z*rat;
If I understand correctly, atan2 will do the trick:
mesh.rotation.y = Math.atan2(mesh.direction.z, mesh.direction.x)
Result is in radians. It basically calculates the angle between the vector and X axis. You might need to switch parameters or use minus operator here or there.

Categories