问题
Like this site http://www.gsmlondon.ac.uk/global-oil-map/
I would like to click on this marker, let this marker turn to the center of the screen. Now know the mark latitude and longitude, how to turn after the click? I do not understand.
回答1:
Interesting question, I tried Matrix to get right orientation, but the result is a little bit strange. I choose another way using spherical coordinates system, and it works now.
we need to get two points coordinates, one is the point on the sphere surface which is closest to the camera we note it as P(the line from camera to center of sphere intersect with the sphere). another point is where we click on the sphere surface, we note it as Q .
we use raycaster
to get P and Q Cartesian Coordinates. and convert the Cartesian Coordinates to Spherical Coordinates(always described like (r,θ,φ)).
then, we calculate the angular displacement from Q to P. and make the displacement as an addition to sphere rotation.
Here is my snippet:
//get the point coordinates which a line from camera to sphere center intersect with the sphere
var vector = new THREE.Vector3().copy(sphere.position);
vector = vector.unproject(camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects([sphere],true);
var intersected_point = new THREE.Vector3().copy(intersects[0].point);
//calculate the intersected point spherical coordinates
var radius = sphere.children[0].geometry.parameters.radius;
var heading = Math.atan2(intersects[0].point.x,intersects[0].point.z);
var pitch = Math.asin(-(intersects[0].point.y)/radius);
document.addEventListener("click",OnDocumentClick,false);
function OnDocumentClick(event)
{
//get the point coordinates which you click on the sphere surface
var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
vector = vector.unproject(camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects([sphere],true);
if(intersects.length > 0)
{
//get click point spherical coordinates
var heading1 = Math.atan2(intersects[0].point.x,intersects[0].point.z);
var pitch1 = Math.asin(-(intersects[0].point.y)/radius);
//calculate displacement of click point to intersected point
var delta_heading = heading - heading1;
var delta_pitch = pitch - pitch1;
var target_pitch = parseFloat(sphere.rotation.x) +delta_pitch;
var target_heading = parseFloat(sphere.rotation.y) + delta_heading;
//using an animation to rotate the sphere
anime({
targets:sphere.rotation,
x:target_pitch,
y:target_heading,
elasticity: 0
});
}
}
At the end, I use an animation lib to make the rotation smooth.
Here is my demo:rotate the earth.
I made a little progress, the previous version has a little bit off. when I turn up and down the earth, I got a bad result. I think the code sphere.rotation.x += delta_pitch
make sphere rotate on object axises. but what we need is making the sphere rotate on the world space axises. we know world axises coordinates are always x_axis = (1,0,0) ; y_axis = (0,1,0) ; z_axis = (0,0,1)
; then, I convert the world coordinates to object coordinates, Sphere matrix interpret sphere rotate from indentity rotation to current rotation. and the inverse matrix interpret the backword. so we can apply the inverse matrix to basic axises to get object space coordinates. make sphere rotate on new axises. I just make a little change in OnDcoumentClick function:
var heading1 = Math.atan2(intersects[0].point.x,intersects[0].point.z);
var pitch1 = Math.asin(-(intersects[0].point.y)/radius);
//get the sphere inverse matrix;
var sphere_matrix = new THREE.Matrix4().copy(sphere.matrix);
var inverse_sphere_matrix = new THREE.Matrix4();
inverse_sphere_matrix.getInverse(sphere_matrix);
//convert world space x and y axises to sphere object space coordinates.
var x_axis = new THREE.Vector3(1,0,0);
var y_axis = new THREE.Vector3(0,1,0);
x_axis.applyMatrix4(inverse_sphere_matrix);
y_axis.applyMatrix4(inverse_sphere_matrix);
//calculate displacement of click point to intersected point
var delta_heading = heading - heading1;
var delta_pitch = pitch - pitch1;
//make sphere rotate around whith world x and y axises.
sphere.rotateOnAxis(x_axis,delta_pitch);
sphere.rotateOnAxis(y_axis,delta_heading);
Here is my new demo: rotate earth new version.
来源:https://stackoverflow.com/questions/42663593/three-js-earth-and-camera-turning-problems