How setFromSphericalCoords in Three.js works? - three.js

I am creating a Three.js App. It is a 3D ISS Visualizer, and I am using this API to get the latitude, longitude and altitude of the ISS. My problem is that I want to rotate the ISS model around my Earth model. But the problem is that I don't know how .setFromSphericalCoords() works, because when I try to convert my latitude, longitude and altitude int (x, y, z) coordinates with this formulas:
x = Math.cos(lat) * Math.cos(lon) * alt
y = Math.cos(lat) * Math.sin(lon) * alt
z = Math.sin(lat) * alt
taken from here it doesn't work
And all I get are weird coordinates, for example the difference bewtween 2 consecutive xs will be big, and it shouldn't be like this. With this big defferences my space station just teleports from Africa to USA, or something like this, or even goes inside the Earth.
So can someone explain me how to convert these coordinates and how the .setFromSphericalCoords() method works? As you know, the Three.js documentation does not really explain much about each method. I am also aware of the .setFromCarthesian() method, but I still need the carthesian coordinates and an explanation about how it works.

The bottom of each Three.js documentation page has a link to the source code. So if you look for that method on the source code, you’ll find exactly what it’s doing:
setFromSphericalCoords( radius, phi, theta ) {
const sinPhiRadius = Math.sin( phi ) * radius;
this.x = sinPhiRadius * Math.sin( theta );
this.y = Math.cos( phi ) * radius;
this.z = sinPhiRadius * Math.cos( theta );
return this;
}

Related

using spherical coordinates in opengl

I am trying to plot points around a center point using spherical coordinates. I know this is by far not the most efficient way to plot a sphere in OpenGL but i want to do it as an excersive to understand spherical coordinates better.
I want to step through each point by a certain angle so for this i have a nested for loop itterating through theta 0 - 360 and phi 0-360 and i am attempting to get the Cartesian coordinates of each of these steps and display it as a single point.
so far i have this:
float r = 1.0;
for( float theta = 0.0; theta < 360.0; theta += 10.0){
for(float phi = 0.0; phi < 360.0; phi += 10.0){
float x = r * sin(theta) * cos(phi);
float y = r * sin(theta) * sin(phi);
float z = r * cos(theta);
}
}
i store these points a display them. the display function works fine as i have used it to display other point structure before but for some reason i can't get this to work.
I have also tried converting the angles from degrees to radians:
float rTheta = theta * M_PI * 180.0;
float rPhi = phi * M_PI * 18.0;
as sin() and cos() both use radians but it yields the same results.
Am i doing something wrong and badly misunderstanding something?
In the conversion from degrees to radians of angle x, the correct formula is x * M_PI / 180..

Formula of n-vector from latitude and longitude with three.js objects

I want the formula giving the n-vector (perpendicular to the globe) from latitude and longitude in a three.js scene.
My code is currently the following, based on a list of cities (in the table called "wup"):
var conegeometry = new THREE.CylinderGeometry(0, 10, 10, 500, false);
var earthRadius = 6371; // kilometres
var réduc = 0.02;
for (var iter=1;iter<1693;iter++){
var cone = new THREE.Mesh(conegeometry, conematerial);
var lat = wup[iter].Latitude*Math.PI/180;
var lon = wup[iter].Longitude*Math.PI/180;
cone.position.set (
earthRadius * réduc * Math.cos(lat) * Math.cos(lon),
earthRadius * réduc * Math.cos(lat) * Math.sin(lon),
earthRadius * réduc * Math.sin(lat));
cone.rotation.set (
Math.sin(lat),
Math.cos(lat) * Math.sin(lon),
-Math.cos(lat) * Math.cos(lon));
scene.add(cone);
}
Formulae come from this article, p 402.
My aim is to have all cities represented as cones with the top at lat/lon position and the rest below the surface of earth, and perpendicularly to the earth surface (simplified as a sphere).
Latitude and longitude come from UN cities dataset, seem very clean and classical in degrees.
Santiago Del Estero -27,79511 -64,26149
Yerevan 40,181998 44,514619
Adelaide -34,92866 138,59863
But something is wrong in the rotation formulae, and I can't find the right adjustment. Any idea?
You need to fix two things: calculation of position and calculation of rotation.
Position:
The geographical coordinate system is left-handed (longitude grows towards east). Three.js uses a right-handed coordinate system (longitude grows towards west). Therefore the longitude value needs to be inverted in your geometry. Also, the formulae you found work for coordinates with Z-axis pointing up. Three.js has the Y-axis pointing up. So you need to swap the z and y formulas. This is the correct code for position:
var lat = wup[iter].Latitude*Math.PI/180;
var lon = - wup[iter].Longitude*Math.PI/180;
cone.position.set (
earthRadius * réduc * Math.cos(lat) * Math.cos(lon),
earthRadius * réduc * Math.sin(lat),
earthRadius * réduc * Math.cos(lat) * Math.sin(lon));
Rotation:
You just need to rotate the cone by their longitude/latitude values (not sines and cosines)
cone.rotation.set ( 0, -lon, - Math.PI / 2 + lat);
I found a solution, much simpler than my initial idea. Based on this project and this example at using the instruction lookAt which avoids complicate trigonometric formulae.
I also found that my formulae for lat/lon to x, y, z where wrong, and not corresponding to the formulae used in the project shp.js which I also use.
Objects can be set at facing a given point, here the centre of the earth. But then cones are cylinders and must for a reason I do not fully understand be turned of PI/2. So this worked:
var lat = wup[iter].Latitude*Math.PI/180;
var lon = - wup[iter].Longitude*Math.PI/180;
cone.position.set (
Math.cos(lon) * 90 * Math.cos(lat),
Math.sin(lat) * 90,
Math.sin(lon) * 90 * Math.cos(lat)
);
cone.lookAt( new THREE.Vector3(0,0,0) ); //orientate the cone to the center of earth
cone.translateZ( - earthRadius * réduc); //to follow the genral contraction
cone.translateZ( coneHeight/2); //to put the top edge at lat/lon position
cone.rotateX(- Math.PI / 2 ); //because cylinders.cones are drawn horizontally

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.

Rotate scene about Up vector in jsc3d

I'm using jsc3d to load and display some 3d objects on a canvas. The viewer has already a built-in feature that allows to rotate the "view coordinates" (correct me if i'm wrong) about the Y axis by dragging the mouse.
The rotation is performed through a classic rotation matrix, and finally the trasformation matrix is multiplied by this rotation matrix.
The totation about the Y axis is calculated in a way that resembles a circular movement around the whole scene of loaded objects:
JSC3D.Matrix3x4.prototype.rotateAboutYAxis = function(angle) {
if(angle != 0) {
angle *= Math.PI / 180;
var c = Math.cos(angle);
var s = Math.sin(angle);
var m00 = c * this.m00 + s * this.m20;
var m01 = c * this.m01 + s * this.m21;
var m02 = c * this.m02 + s * this.m22;
var m03 = c * this.m03 + s * this.m23;
var m20 = c * this.m20 - s * this.m00;
var m21 = c * this.m21 - s * this.m01;
var m22 = c * this.m22 - s * this.m02;
var m23 = c * this.m23 - s * this.m03;
this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03;
this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23;
}
};
Now, dragging the mouse will apply this rotation about the Y axis on the whole world, like on the left side in the picture below. Is there a way, to apply a rotation about the Up vector to keep it in the initial position, like it appear on the right side?
I tried something like that:
var rotY = (x - viewer.mouseX) * 360 / viewer.canvas.height;
var rotMat = new JSC3D.Matrix3x4; // identity
rotMat.rotateAboutYAxis(rotY);
viewer.rotMatrix.multiply(rotMat);
but it has no effect.
What operations shall be applied to my rotation matrix to achieve a rotation about the Up vector?
Sample: https://jsfiddle.net/4xzjnnar/1/
This 3D library has already some built-in functions to allow scene rotation about X,Y,and Z axis, so there is no need to implement new matrix operations for that, we can use the existing functions rotateAboutXAyis, rotateAboutYAxis and rotateAboutZAxis, which apply an in-place matrix multiplication of the desired rotation angle in degrees.
The scene in JSC3D is transformed by a 3x4 matrix where the rotation is stored in the first 3 values of each row.
After applying a scene rotation and/or translation, applying a subsequent rotation about the Up vector, is a problem of calculate a rotation about an arbitrary axis.
A very clean and didactic explanation how to solve this problem is described here: http://ami.ektf.hu/uploads/papers/finalpdf/AMI_40_from175to186.pdf
Translate the P 0 (x 0 ,y 0 ,z 0 ) axis point to the origin of the coordinate system.
Perform appropriate rotations to make the axis of rotation coincident with
z-coordinate axis.
Rotate about the z-axis by the angle θ.
Perform the inverse of the combined rotation transformation.
Perform the inverse of the translation.
Now, its easy to write a function for that, because we use the functions already available in JSC3D (translation part is omitted here).
JSC3D.Viewer.prototype.rotateAboutUpVector = function(angle) {
angle %= 360;
/* pitch, counter-clockwise rotation about the Y axis */
var degX = this.rpy[0], degZ = this.rpy[2];
this.rotMatrix.rotateAboutXAxis(-degX);
this.rotMatrix.rotateAboutZAxis(-degZ);
this.rotMatrix.rotateAboutYAxis(angle);
this.rotMatrix.rotateAboutZAxis(degZ);
this.rotMatrix.rotateAboutXAxis(degX);
}
Because all above mentioned functions are using degrees, we need to get back the actual Euler angles from the rotation matrix (simplified):
JSC3D.Viewer.prototype.calcRollPitchYaw = function() {
var m = this.rotMatrix;
var radians = 180 / Math.PI;
var angleX = Math.atan2(-m.m12, m.m22) * radians;
var angleY = Math.asin(m.m01) * radians;
var angleZ = Math.atan2(-m.m01, m.m00) * radians;
this.rpy[0] = angleX;
this.rpy[1] = angleY;
this.rpy[2] = angleZ;
}
The tricky part here, is that we need always to get back the current rotation angles, as they results from the applied rotations, so a separate function must be used to store the current Euler angles every time that a rotation is applied to the scene.
For that, we can use a very simple structure:
JSC3D.Viewer.prototype.rpy = [0, 0, 0];
This will be the final result:

interpolate between rotation matrices

i have two rotation matrices that describe arbitrary rotations. (4x4 opengl compatible)
now i want to interpolate between them, so that it follows a radial path from one rotation to the other. think of a camera on a tripod looking one way and then rotating.
if i interpolate every component i get a squeezing result, so i think i need to interpolate only certain components of the matrix. but which ones?
You have to use SLERP for the rotational parts of the matrices, and linear for the other parts. The best way is to turn your matrices into quaternions and use the (simpler) quaternion SLERP: http://en.wikipedia.org/wiki/Slerp.
I suggest reading Graphic Gems II or III,specifically the sections about decomposing matrices into simpler transformations. Here's Spencer W. Thomas' source for this chapter:
http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c
Of course, I suggest you learn how to do this yourself. It's really not that hard, just a lot of annoying algebra. And finally, here's a great paper on how to turn a matrix into a quaternion, and back, by Id software: http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf
Edit: This is the formula pretty much everyone cites, it's from a 1985 SIGGRAPH paper.
Where:
- qm = interpolated quaternion
- qa = quaternion a (first quaternion to be interpolated between)
- qb = quaternion b (second quaternion to be interpolated between)
- t = a scalar between 0.0 (at qa) and 1.0 (at qb)
- θ is half the angle between qa and qb
Code:
quat slerp(quat qa, quat qb, double t) {
// quaternion to return
quat qm = new quat();
// Calculate angle between them.
double cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
// if qa=qb or qa=-qb then theta = 0 and we can return qa
if (abs(cosHalfTheta) >= 1.0){
qm.w = qa.w;qm.x = qa.x;qm.y = qa.y;qm.z = qa.z;
return qm;
}
// Calculate temporary values.
double halfTheta = acos(cosHalfTheta);
double sinHalfTheta = sqrt(1.0 - cosHalfTheta*cosHalfTheta);
// if theta = 180 degrees then result is not fully defined
// we could rotate around any axis normal to qa or qb
if (fabs(sinHalfTheta) < 0.001){ // fabs is floating point absolute
qm.w = (qa.w * 0.5 + qb.w * 0.5);
qm.x = (qa.x * 0.5 + qb.x * 0.5);
qm.y = (qa.y * 0.5 + qb.y * 0.5);
qm.z = (qa.z * 0.5 + qb.z * 0.5);
return qm;
}
double ratioA = sin((1 - t) * halfTheta) / sinHalfTheta;
double ratioB = sin(t * halfTheta) / sinHalfTheta;
//calculate Quaternion.
qm.w = (qa.w * ratioA + qb.w * ratioB);
qm.x = (qa.x * ratioA + qb.x * ratioB);
qm.y = (qa.y * ratioA + qb.y * ratioB);
qm.z = (qa.z * ratioA + qb.z * ratioB);
return qm;
}
From: http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
You need to convert the matrix into a different representation - quaternions work well for this, and interpolating quaternions is a well-defined operation.

Resources