THREE.js - Quaternion to lat, lon - three.js

I am trying to convert vrDisplays rotation (comes in quaternions) to latitude and longitude, since an API I use needs the current rotation of the head mounted display in lat and lon values.
lordofducts answer in unity3D forums (https://forum.unity3d.com/threads/quaternions-and-euler-angles-to-longitude-latitude.154392/ )
gave me good hope that this is actually possible, but I am kind of stuck, as THREE.Quaternion doesn't seem to have ToAxisAngle() method and I am not that good with 3D geometry.
so does anybody have an idea how I can achieve this so I can do sth like that?
var quat = THREE.Quaternion();
quat.fromArray(vrDisplay.getPose().orientation);
var lat = //do sth with quat
var lon = //do seth with quat
api.rotateCamera({
lat: lat,
lon: lon
});
// I noticed that in my code I already have a conversion from Euler angles to lat lon. So I might be just converting the Quaternion to Euler angles and then convert it to lat lon values. Still, there has to be a more sophisticated method...

var look = new THREE.Vector3();
quatToSpherical = function(quat){
look.set(0,0,1);
look.applyQuaternion(quat);
look.normalize();
if(Math.abs(look.x) < 0.001) look.x = 0.001;
var angles = {};
var radius = 1;
angles.lat = Math.acos(look.z/r);
angles.lon = Math.atan2(look.y , look.x);
return angles;
}
The solution applies only to a standard cartesian coordinate system.
a right handed coordinate system with XY ground plane like I used in my setup needs offsets:
angles.lat = Math.acos(look.z/r) - Math.PI/2;
angles.lon = Math.atan2(look.y , look.x) - Math.PI;
https://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates

Related

ThreeJS : How to get the angle between2 object

I have an Avatar at a given Position (v0) and Rotation (r0)
I have an Object at a givent Position (v1)
I looking for the angle to rotate the avatar toward v1. I need the angle I don't want to use lookAt() function
// Get the Avatar Position
let v0 = new THREE.Vector3();
avatar.getWorldPosition(v0)
// Get the Object Position
let v1 = new THREE.Vector3();
obj.getWorldPosition(v0)
// Get the direction v0 to v1
let dir0 = new THREE.Vector3();
dir0.subVectors( v0, v1 ).normalize();
// Get the direction of avatar (where it look at)
let dir2 = new THREE.Vector3();
avatar.getWorldDirection(dir2)
// Get the angle between the 2 direction
let radians = dir0.angleTo(dir2)
It doesn't work !
The this.mesh.lookAt(v1.setY(0)) works and rotate correctly the mesh
But the angle computation didn't work because of avatar.getWorldDirection
BTW, since everything is on the same plane I don't need 3D (only 2D)
BTW, The avatar (Mixamo) seems to face backward
I need that angle to trigger some animation (if angle > 90 then trigger 90, if angle > 180 then turnback animation...)
Your code has a few mistakes. obj.getWorldPosition(v0) is going to overwrite the v0 values retrieved with avatar.getWorldPosition(v0), so when you subtract v0 - v1 you'll get a vector with a magnitude of 0.
Looking at the documentation of Vector3.angleTo(), it says all you need to do is input the positions, without any subtraction necessary:
let posAvatar = new THREE.Vector3();
avatar.getWorldPosition(posAvatar);
let posObj = new THREE.Vector3();
obj.getWorldPosition(posObj);
const angleRadians = posAvatar.angleTo(posObj);
// convert from radians to degrees
const angleDeg = THREE.MathUtils.radToDeg(angleRadians);
Keep in mind, both objects will need to be on the same plane for this 2D angle to be accurate.
Update:
This approach uses the Javascript Math.atan2() method to calculate the absolute y-axis rotation from your avatar's vantage point towards the obj. This also only uses the x,z positions so any height variations are ignored.
let posAvatar = new THREE.Vector3();
avatar.getWorldPosition(posAvatar);
let posObj = new THREE.Vector3();
obj.getWorldPosition(posObj);
const xDist = posObj.x - posAvatar.x;
const zDist = posObj.z - posAvatar.z;
const angle = Math.atan2(zDist, xDist) * 180 / Math.PI;
avatar.rotation.y = angle;
Your avatar might be facing a different axis, so you can just add 90 or 180 degrees to the final angle value.

How calculate rotational increment in THREE.js

For drag function, I'm making objectB follow objectA like:
var positionDeltas = objectA.position.clone();
postitionDeltas.sub(objectAOldPosition);
var newPositon = objectB.position.clone();
objectB.position = newPosition.add(positionDeltas);
Can angle increments be done similarly? Can I subtract/add quaternions in a similar way?:
var rotationDeltas = objectA.quaternion.clone();
rotationDeltas.sub(objectAOldRotation);
var newRotation = objectB.quaternion.clone();
objectB.quaternion = newRotation.add(rotationDeltas);
Clarification: this is what I want to do; however, I do know that eulers can't be subtracted, and subtraction isn't defined for quaternions. So....how would one who knows what they're doing approach this three.js?
Try this:
const q = new THREE.Quaternion();
q.multiply( q2, q1.inverse() );
Quaternion q represents the rotation from quaternion q1 to q2. You can then apply this rotation to your 3D object via .applyQuaternion().
three.js R91

In three.js how to retrieve the position of an object?

I have created an object, a cone, and have located it, orientated it, and then translated it along its axis z. Well, now I want to retrieve its position in x, y and z and store the information in an array for later use.
var cone = new THREE.Mesh(coneGeometry, coneMaterial);
var φ = wup[iter].Latitude*Math.PI/180;
var λ = - wup[iter].Longitude*Math.PI/180;
//φ phi lat λ lambda lon
cone.position.set (
Math.cos(λ) * 90 * Math.cos(φ),
Math.sin(φ) * 90,
Math.sin(λ) * 90 * Math.cos(φ)
);
cone.lookAt( new THREE.Vector3(0,0,0) );
cone.translateZ( - earthRadius * réduc);
wup[iter].x = cone.x;
wup[iter].y = cone.y;
wup[iter].z = cone.z; /
The problem is that cone.x does not contain anything.
Based on philipp's indication, and on the reply to a neighboring question of mine, here is the code that worked:
wup[iter].x = cone.position.x;
wup[iter].y = cone.position.y;
wup[iter].z = cone.position.z;
cone, as a geometry, has a vector called position associated to it with coordinates. Consequently, retrieving the coordinates of the geometry implies calling the coordinates of its vector position.

Rotating a sphere to a specific point. Not the camera

i need some help on this one.
I have search and couldn't find solutions for this, because all the solutions were about rotating a camera around a sphere.
In my case, the camera is still. I have a webgl globe with points around using latitude an longitude. I just want to click a point and rotate the globe mesh so that it centers that point.
I have the point Vector3, it's latitude and longitude but i can't figure how to do this.
Is someone around that can help me? Or know any example like this?
Thank you in advance
To rotate a sphere to match a lat/lon the camera center, you can do this:
var verticalOffset = 0.1;
sphere.rotation.x = latitude * ( Math.PI / 180 ) - verticalOffset;
sphere.rotation.y = ( 270 - longitude ) * ( Math.PI / 180 );
So then you can call this with a tween:
var tween = new TWEEN.Tween(sphere.rotation)
.to({ x: latitude * ( Math.PI / 180 ) - verticalOffset, y: ( 270 - longitude ) * ( Math.PI / 180 ) }, 2000)
.start();
I have created a jsfiddle demonstrating this, where a marker is set at Lissabon:
http://jsfiddle.net/L0rdzbej/208/
Update
In case the sphere has been turned around a lot, the Y-rotation value climbs up. Then tweening the rotation as suggested above results in a lot of reverse spinning until the point is displayed at camera center.
To avoid this, it is possible to set the rotations via quaternions. The tweening must be slerp'ed using a temporal quaternion.
For demonstration purposes I have set the spheres initial Y rotation to PI * 12.1, then applying the quaternion.
http://jsfiddle.net/L0rdzbej/217/
var phi = latitude * Math.PI / 180;
var theta = ( 270 - longitude) * Math.PI / 180;
var euler = new THREE.Euler(phi, theta, 0, 'XYZ');
// rotation (using slerp)
var qstart = new THREE.Quaternion().copy(sphere.quaternion); // src quaternion
var qend = new THREE.Quaternion().setFromEuler(euler); //dst quaternion
var qtemp = new THREE.Quaternion();
var o = {t: 0};
new TWEEN.Tween(o).to({t: 1}, 2500)
.onUpdate(function () {
THREE.Quaternion.slerp(qstart, qend, qtemp, o.t);
sphere.quaternion.copy( qtemp );
})
.start();

three.js - Set the rotation of an object in relation to its own axes

I'm trying to make a static 3D prism out of point clouds with specific numbers of particles in each. I've got the the corner coordinates of each side of the prism based on the angle of turn, and tried spawning the particles in the area bound by these coordinates. Instead, the resulting point clouds have kept only the bottom left coordinate.
Screenshot: http://i.stack.imgur.com/uQ7Q8.png
I've tried to set the rotation of each cloud object such that their edges meet, but they will rotate only around the world centre. I gather this is something to do with rotation matrices and Euler angles, but, having been trying to work them out for 3 solid days, I've despaired. (I'm a sociologist, not a dev, and haven't touched graphics before this project.)
Please help? How do I set the rotation on each face of the prism? Or maybe there is a more sensible way to get the particles to spawn in the correct area in the first place?
The code:
// draw the particles
var n = 0;
do {
var geom = new THREE.Geometry();
var material = new THREE.PointCloudMaterial({size: 1, vertexColors: true, color: 0xffffff});
for (i = 0; i < group[n]; i++) {
if (geom.vertices.length < group[n]){
var particle = new THREE.Vector3(
Math.random() * screens[n].bottomrightback.x + screens[n].bottomleftfront.x,
Math.random() * screens[n].toprightback.y + screens[n].bottomleftfront.y,
Math.random() * screens[n].bottomrightfront.z + screens[n].bottomleftfront.z);
geom.vertices.push(particle);
geom.colors.push(new THREE.Color(Math.random() * 0x00ffff));
}
}
var system = new THREE.PointCloud(geom, material);
scene.add(system);
**// something something matrix Euler something?**
n++
}
while (n < numGroups);
I've tried to set the rotation of each cloud object such that their
edges meet, but they will rotate only around the world centre.
It is true they only rotate around 0,0,0. The simple solution then is to move the object to the center, rotate it, and then move it back to its original position.
For example (Code not tested so might take a bit of tweaking):
var m = new THREE.Matrix4();
var movetocenter = new THREE.Matrix4();
movetocenter.makeTranslation(-x, -y, -z);
var rotate = new THREE.Matrix4();
rotate.makeRotationFromEuler(); //Build your rotation here
var moveback = new THREE.Matrix4();
moveback .makeTranslation(x, y, z);
m.multiply(movetocenter);
m.multiply(rotate);
m.multiply(moveback);
//Now you can use geometry.applyMatrix(m)

Resources