Issues with small rotation values (precision?) - three.js

Excuse me if this is an obvious question, I'm quite new to Three.js.
I'm trying to rotate some geometry along its Y axis, quite slowly and I'm using a rotation matrix for that.
In my machine, when setting a value smaller than 0.0076rad for the rotation, the geometry starts spinning, but when it reaches PI/2, it's not able to proceed, and stays flapping in values around PI/2.
Find an example here: http://jsfiddle.net/vn0m7h81/ , where the speed value can be set at...
// Speeds below 0.0076 cause the cube to stop spinning when reaching
// Pi/2 rotation in the Y axis. Values > 0.0075 work fine.
var rotationSpeed = 0.0075;
For incr. values bigger than 0.0075 the geometry keeps spinning forever.
What's the reason for this behavior?

Do not modify mesh.matrix directly in three.js unless you are an experienced user. Instead, update mesh.rotation or mesh.quaternion, and let the renderer update the matrix for you. You can also use mesh.rotateY( radians ).
three.js r.73

Related

How to animate multiple sprites in one direction using one geometry in Three.js?

I'm trying to do something similar to this example, except instead of having the snow flakes flutter about in all directions I'm trying to animate these sprites in only one direction, like having the snow flakes fall to the ground.
The example above was able to load multiple sprites into one geometry since it can vary the rotations of the points object:
particles.rotation.x = Math.random() * 6;
particles.rotation.y = Math.random() * 6;
particles.rotation.z = Math.random() * 6;
However, this won't work if you're animating all the points in one direction. In this case, would I have to create a new geometry for each sprite, or is there a more efficient way to do this using just one geometry?
There are several options. Instead of rotating randomly, you could:
Decrease the y position on each frame with particles.position.y -= 0.01;. When it crosses a certain threshold (For example: y <= -100), move them back up to the origin (y = 100). You'll have to stagger a few Sprite objects so you don't notice the jump.
Rotate along the x-axis, so the spinning motion makes them go down when in front of the camera.
Since the snowflakes will spin up on the opposite side, you could use some fog to hide the far side, and give it a more wintry feel.
Animating via custom shaders, although this is much more complex if you don't know GLSL shader code.

Three.js rotating object around xyz world axis using quaternions

I've been struggling with this for the past 3 days so here we go:
I am building a virtual photo-studio using Three.js. The rotation is set with three sliders, one for each axis. Rotation needs to happen around the world axis. So far, I can get the object to rotate around the world x axis, however, y and z rotation only happens locally. Here is the code for one of the rotation sliders using quaternions.
let rotationX = new THREE.Quaternion()
sliderX.oninput = function () {
let newVec = new THREE.Vector3(1,0,0)
let newRad = THREE.Math.degToRad(this.value)
rotationX.setFromAxisAngle(newVec, newRad)
pivot.quaternion.multiplyQuaternions(rotationX, rotationY).multiply(rotationZ)
}
This approach has gotten me the farthest. The problem is that the rotation always happens around the vector of the first quaternion in the multiplication chain. That would be the quaternion "rotationX" of the following line.
pivot.quaternion.multiplyQuaternions(rotationX, rotationY).multiply(rotationZ)
Because I am working with quaternions, switching around the order of multiplication is also not an option as it changes the outcome.
Any help would be greatly appreciated.
Here is a link to the dependency free repo in case you want to recreate the situation: https://github.com/maxibenner/exporter

Flipping (orthographic) camera axes

It seems possible to flip an axes of an orthographic camera in three, e.g. by the following code:
var tmp = camera.right;
camera.right = camera.left;
camera.left = tmp;
camera.updateProjectionMatrix();
However, this screws up the lighting, so it seems to not be supported (at least not with built in materials). Is this so? Is there another way to achieve this?
The use case I currently have is a scientific scene (loads of spheres and lines) that can be seen from either positive or negative Z direction. The requirement is that the X and Y axis point the same direction (e.g. right and up) no matter which Z-direction you are looking in. Is there an alternative solution if flipping left/right is not the way to go?
For an example of what I am talking about, see this fiddle: https://jsfiddle.net/mt0bpwcz/1/ Try double clicking the scene to switch the camera. Afterwards the lighting will be very strange (especially visible in the specular highlights).

How to rotate Decal over more then one axis at moment

I'm working on Libdx app using Decals.
Decals are 2d sprites in 3d world.
I have problem that when I say:
decal.setRotationX(angle)
everything works fine, but when I say:
decal.setRotationX(angle);
decal.setRotationY(angle2);
The decal rotates over Y axis only.
How to manage that problem?
I have found that Decal in source code uses Quaternion for rotation, but currently I don't know how to customize that to face my requirements.
Tnx in advance!
EDIT:
I have managed to rotate decal around multiple axis with:
decal.getRotation().setEulerAngles(yaw,pitch,roll);
Now my question is how to animate this with TweenEngine?
In get values method I have:
returnValues[0] = target.getRotation().getYaw();
returnValues[1] = target.getRotation().getPitch();
returnValues[2] = target.getRotation().getRoll();
In set values method I have:
target.getRotation().setEulerAngles(newValues[0], newValues[1],
newValues[2]);
But decal is not moving or animating, it's stucked in one position (slightly rotated over XYZ axis).
Any idea, values in TweenEngine are correct but somehow decal is not refreshing and rotating.
If you want to do it only once, you can do it like this:
decal.rotateX(angleX);
decal.rotateY(angleY);
decal.rotateZ(angleZ);
This will "add" the given angle to the current one though.
An alternative way would be to use the rotation Quaternion of the Decal:
decal.getRotation().setEulerAngles(yaw, pitch, roll);
The following image shows what "yaw", "pitch" and "roll" means:
Roll, pitch, yaw http://i.msdn.microsoft.com/dynimg/IC79189.gif
EDIT: I've just seen the JavaDoc of Decal.getRotation() and it says that the returned quaternion should not be modified! I've also checked the code and every other method of Decal sets an internal update flag which will cause the decal to change the next time it's rendered. Decal.getRotation() does not set this flag and thus the changes to it won't get recognized.
It seems like currently there is no really clean and easy way to set the rotation on all three axes at the same time. A workaround might look like this:
decal.setRotationX(0);
decal.setRotationY(0);
decal.setRotationZ(0);
decal.rotateX(angleX);
decal.rotateY(angleY);
decal.rotateZ(angleZ);
It first resets all angles to 0 and then rotates on each axis while not overwriting any other axis.

Java3D: rotating object in world coordinates?

I've been searching all evening but can't find the information I'm looking for, or even if it's possible, which is quite distressing ;)
I'm using Java3D and can't figure out how to rotate the camera in world space.
My left/right, and up/down rotation both happen on local space.
Meaning that if I move left and right, everything looks fine.
However if I look 90 degrees down, then look 90 degrees right, everything appears to be on its side.
Currently, I'm doing the following. This will result in the above effects:
TransformGroup cam = universe.getViewingPlatform().getViewPlatformTransform();
Transform3D trfcam = new Transform3D();
cam.getTransform(trfcam);
trfcam.mul(Camera.GetT3D()); //Gets a Transform3D containing how far to rotate left/right and how far to move left/right/forward/back
trfcam.mul(Camera.GetRot()); //Gets a t3d containing how far to rotate up/down
cam.setTransform(trfcam);
Alternatively, one thing I tried was rotating the root, but that rotates around 0, so if I ever move the camera away from 0, it goes bad.
Is there something available on the web that would talk me through how to achieve this kind of thing?
I've tried a lot of different things but just can't seem to get my head around it at all.
I'm familiar with the concept, as I've achieved it in Ogre3D, just not familiar with the law of the land in J3D.
Thanks in advance for replies :)
Store the ammound you have rotated around each axis (x and y), and when you try to rotate around the x axis for example, reverse the the rotation around y, do the rotate around x, then redo the rotation around y.
I'm not sure I understand your second question correctly. Since viewer and model transformations are dual, you can simulate camera moves by transforming the world itself. If you dont want to translate the x and y axis you are rotating around, just add another TransformGroup to the main TransformGroup you are using, and do the transforms in the new one.
Edit: The first solution is quite slow, so you can make a Transform3D out of the 3 transform you have to do:
Say you have rotated around the x axis (Translate3D xrot), and now you need to rotate around y:
Translate3D yrot = new Translate3D();
yrot.rotY(angle);
Translate3D temp = xot;
xrot.mul(yrot); // Dont forget the reverse order. xrot is the previous translate
xrot.mul(yrot); // xrot = xrot * yrot * xrot^-1
temp.transpose(); // Get the reverse transform of the old transform
xrot.mul(temp);
yrot = xrot; // Store it for future rotation around x axis
cam.setTransform(yrot);
It works similar for many transformations you make: reverse the previous done, do the transform, redo the old one. I hope it helps.

Resources