Three.js rotating object around xyz world axis using quaternions - three.js

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

Related

threejs: How to perform rotation of object around it's local axes?

I am trying to rotate object on it's local axis using absolute rotation values. I am facing two issues
1. It looks like my object is rotating around world axes. For example set X, Y and Z to 45 degrees and try changing X.
2. If Y is set to 90 degrees, I get into gimbal lock issue.
I am using quaternion by setting rotation as follow
cube.quaternion.setFromEuler(new THREE.Euler(x, y , z));
A demo snippet is JSFiddle
I came across this article ThreeJS - rotation around object's own axis, but that didn't helped me.
I have been trying different solution using Euler and Matrix but still not able to make it work.
Looking for help to figure out the solution to this problem.

Program to convert points on 3D plane to 2D points

I have the normal vector of the plane . I want to convert the 3D points onto a 2D plane maintaining the same distances between them. Basically what I want to do is make the z coordinate of all the points on the plane equal.
How do I go about achieving this and writing a program for it (Preferably C#)? . Are there any good libraries that I can use .
Will this library be useful Point Cloud Library
My objective in doing this is I have several lines(on the same plane) in 3D space and I want to represent these lines in 2D along with their measurements
An example plane of my problem.
I am doing this for an application I am developing in unity using Google ARcore
Ok I have invested a fair amount of time in finding a solution to this problem . I figured out a simple solution to this problem using ARcore as I am doing this using ARCore(Augmented reality SDK provided by Google) . For those who want to achieve this without using ARcore refer these questions Question 1 Question 2 where a new orthonormal basis has to be created or the plane has to be rotated in order to align with the default planes.
For those who are using ARcore in unity , there is a simpler solution given in this issue on GitHub created by me . Basically we can easily create new axes on the 3D plane and record coordinates from this newly created coordinate system.
If you want to project 3d points on a plane, you need to have a 2d coordinate system in mind. A natural one is the one defined by the global axis, but that will work well with one kind of planes (say horizontal) but not another (say vertical).
Another choice of coordinates is the one defined by CenterPose, but it can change every frame. So if you need the 2d points only for 1 frame, this is can be written as:
x_local_axis = DetectedPlane.CenterPose.rotation * Vector3.forward;
z_local_axis = DetectedPlane.CenterPose.rotation * Vector3.right;
// loop over your points
x = Vector3.Dot(your_3d_point, x_local_axis);
z = Vector3.Dot(your_3d_point, z_local_axis);
If you need a 2d coordinate system that is consistent between frames, you probably would want to attach an anchor to any plane of interest, maybe at DetectedPlane.CenterPose, and do the same math as above, but with anchor rotation instead of plane rotation. The x and z axes of the anchor will provide a 2d frame of coordinates that is consistent between frames.
So here , a new local axes are created on the center of the plane and the points obtained would have only 2 coordinates .
I needed this in Unity C# so here's some code that I used.
First of, project the point onto the plane.
Then using the dot values for the targeted transforms right and forward I got the local 2D coordinates.
So if you want the standard coords replace right with (1,0) and forward with (0,1)
public static Vector3 GetClosestPointOnPlane(Vector3 point, Plane3D plane){
Vector3 dir = point - plane.position;//Direction between the plane / Point
plane.normal = plane.normal.normalized;
float dotVal = Vector3.Dot(dir.normalized, plane.normal);//Check if the tow are facing each other.
return point + plane.normal * dir.magnitude * (-dotVal);//Multiplying the angle(DotVal) with the magnitude gives the distance.
}
Intersection.Plane3D tempPlane = new Intersection.Plane3D(transform.position, transform.up);//Plane3D is just a point and a normal.
Vector3 closestPoint = Intersection.GetClosestPointOnPlane(testPoint.position, tempPlane);
float xPos = Vector3.Dot((closestPoint - transform.position).normalized, transform.right);
float yPos = Vector3.Dot((closestPoint - transform.position).normalized, transform.forward);
float dist = (closestPoint - transform.position).magnitude;
planePos = new Vector2(xPos * dist, yPos * dist);//This is the value that your looking for.
#William Martens
FYI: The GetClosestPointOnPlane function is part of some old stuff I made over a decade ago back in school made in C++ converted to C#. It might be based on something in my old school book but I cant say for sure. The rest I made my self after looking around for a while and not finding something that worked.

Issues with small rotation values (precision?)

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

Libgdx decal rotation around custom axis

I'm working app that uses Libgdx engine and decals in 3d space.
Now I need to rotate decals around X,Y,Z axis, but around custom pivot point that stands somewhere in the 3d space.
I found that decals have transformationOffset field, which might work with some calculations, but is Vector2 only. It means that I can move pivot point only over X and Y axis.
And when rotating decals over Y axis, wherever the pivot is, the result is the same.
decal.transformationOffset = new Vector2(0, -5);
decal.rotateX(newValues[0]);
decal.rotateY(newValues[1]);
decal.rotateZ(newValues[2]);
I need to move pivot over Z axis, too.
Is there some workaround for this issue?
Tnx!
EDIT:
I have succeded to rotate decal over pivot point in 3d space, but only if pivot's and decals's Z position is the same. If they are not I don't get what I've expected.
This is the code that works for pivot with same Z value:
decal.transformationOffset = new Vector2(pivotPosition.x - decal.getPosition().x, pivotPosition.y - decal.getPosition().y);
Tween.to(decal, DecalTween.XYZ_ROTATION, 5f).target(0, 360, 0).repeatYoyo(Tween.INFINITY, 0f).start(tweenManager);
And in tween I do this:
target.setRotationX(0);
target.setRotationY(0);
target.setRotationZ(0);
target.rotateX(newValues[0]);
target.rotateY(newValues[1]);
target.rotateZ(newValues[2]);
How to extend this to use and Z value for pivot. I'm trying to add and translation animation beside rotate to achive this, but the results is weird.
Tween.to(decal, DecalTween.MOVE_XYZ, 2.5f).target(decal.getPosition().x, decal.getPosition().y, pivotPosition.z - decal.getPosition().z).repeatYoyo(Tween.INFINITY, 0f).start(tweenManager);
decal.transformationOffset = new Vector2(pivotPosition.x - decal.getPosition().x, pivotPosition.y - decal.getPosition().y);
Tween.to(decal, DecalTween.XYZ_ROTATION, 5f).target(0, 360, 0).repeatYoyo(Tween.INFINITY, 0f).start(tweenManager);
Any idea how to combine translate and rotate animatio to get decal rotation in circle path over the pivot point?
I will answer my own question I guess.
I have extended Decal class, changed transformationOffset to Vector3.
Then in transformVertices I have added tz value, like there already was tx and ty. And add tz in calculation for vertex position.
Simple as that.
If anyone knows why is this left out from native libgdx support, please let me know.
Cheers.

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