[SOLVED] Using Quaternions approach to rotate sphere from clicked point towards static point

quaternion
rotation
sphere
spherical

#1

Hi! :smiley:

I am trying to make an Earth sphere mesh to rotate towards a a clicked point in itself (change rotation but no position). I already have the clicked mesh point coords in this code:

 var pickerPoint = new THREE.Vector3()

 THREE.Mesh.prototype.raycast = (function () {
 var originalRaycast = THREE.Mesh.prototype.raycast;
 var localPoint = new THREE.Vector3 ()

 return function (raycaster, intersects) {
      originalRaycast.call (this, raycaster, intersects);
      for (var i = 0, n = intersects.length; i < n; i++) {
          if (this === intersects[i].object) {
              this.worldToLocal (localPoint.copy (intersects[i].point));       
          
              var face = intersects[i].face
                 // Get the vertices intersected
              let a = this.geometry.vertices[face.a];
              let b = this.geometry.vertices[face.b];
              let c = this.geometry.vertices[face.c];

              // Averge them together
              let vector = new THREE.Vector3( (a.x + b.x + c.x) / 3,
                                              (a.y + b.y + c.y) / 3,
                                              (a.z + b.z + c.z) / 3 )

              pickerPoint = vector
       }}}
})();

With this point I made a temporal mesh, set it with pickerPoint position and and looking towards to the World mesh position to copy its quaternion to the World mesh quaternion and make the rotation:

var world = new THREE.Mesh(new THREE.SphereGeometry(sphereRadius + 5 , sphereSegments, 
sphereSegments), worldMeshMaterial)

lookAtPoint = (e) => {           //called on dblclick event listener
    let vector = new THREE.Vector3();
    vector.set(  ((e.clientX  - 1) / window.innerWidth) * 2 - 1,
                -((e.clientY - 1) / window.innerHeight) * 2 + 1,
                 0.5 )
    raycaster.setFromCamera(vector, camera)
    let target = raycaster.intersectObject(wireframedMesh, false)

    if(target.length > 0){        
        var tempMaterial  = new THREE.MeshPhongMaterial({color: '#ffea05', transparent: false, wireframe: true });
        var worldPosition = new THREE.Vector3()
        var temp = new THREE.Mesh(new THREE.SphereGeometry(0.5, 40 ,40), tempMaterial);
        var qEnd = new THREE.Quaternion();
        temp.position.copy(pickerPoint);   
        temp.lookAt(world.position);  
        temp.getWorldQuaternion(qEnd)
        temp.quaternion.copy(qEnd)
        temp.updateMatrix()
       
        world.add(temp)  //just to watch the reference point
        
        this.makeTweenVector(world.rotation, { x: temp.rotation.x , y: temp.rotation.y, z: temp.rotation.z }, {
          duration: 2000,
          easing:  TWEEN.Easing.Sinusoidal.InOut,
          update: function(vector){
            world.updateMatrixWorld(true)
          },
        })}}

The thing is… the rotation is going to the exact opposed pickerPoint,I mean, it’s rotating 180 degrees of the picked point, kinda inversed! I dont know why is it happening. Is it required to make pickerPoint.localToWorld maybe? A flip? Anyone overthere to help please? :smiley: thanks!


#2

A live demo would be great :blush:


#3

Oh! I had a big deal putting my code on JsFiddle :S sorry. It’s in node and uses React so I found it tricky. My code is here [https://github.com/sebasz1000/geoSearch] if can help :slight_smile:

I am sure my lookAtPoint() isnt doing what I am looking for so its better to have an abstract explanation.

Maybe this draw can explain what I trying to do:

I need to make point A rotates to face point B. Point A will be picked by raycast over the Earth. Consider Earth will be rotating over its axis, so point A does too(rotation stops when gets B). Point B is over a spherical Static mesh, and will be the point where cam makes a closeup while Earth rotates towards it( so point A conveys with cam projection direction). For now, I just need to face point A towards B by rotating earth. I read about using quaternions for this, but I am not sure how to use apply it to the A vector rotation. Maybe a simple explanation could give me some idea to write in my lookAtPoint() method :slight_smile:

I think looking my code wont be useful, but If you still need it I would try to put it .

Hope you can help me :smiley: Thanks a lot!


#4

While reading your comment, I’ve remembered a similar topic some month ago. Please have a look at the following discussion. Maybe you can use the code presented in the respective fiddles:

In any event, providing a simplified and reduced test case as a fiddle is much better than sharing the whole repo. In this way it’s not necessary to study your entire app. Instead, we can focus on one particular problem/challenge. The advantage of this approach is that more community members will give you better and more usable feedback.


#5

That seems to be the solution I was asking for! let me write some of code and I will put a simplified fiddle code of the results when it get works :wink: Thanks!


#6

I already read the discussion and made a fiddle with some adjustments to do what I am looking for, but I couldnt :confused:

I put a static vector as point B(red dot) and point A(aqua box) goes that fixed point. Suppose A is a country selector so it’s set by mouse click. So, if A points to Africa, A and Africa should face directly fixedpoint B, so sphere mesh should be rotating looking at point A path. So, If I click at Brazil now as A, that point should face B while sphere rotates to face B too again (as if sphere mesh is sticked to point A) and so on…
Sphere will be always rotating, when click, stops rotation and takes sphere clicked point(A) to point B. In other worlds, clicked sphere vertex should face B.

I tried to use sphere.lookAt() to make sphere face interpolation point but it just doesnt work as expected specially due to sphere constant rotation.

How can I make an specific sphere clicked vertex points to a fixed point while sphere rotating

Please check my fiddle [https://jsfiddle.net/sebasz1000/cyb0253s/442/] Maybe would be an easier solution :smiley:

Hope you can help me :smiley:


#7

I tried using angle between both points and used rotateOnAxis() over the sphere to make it rotate that angle over its axis, maybe it would be an easier approach, but still not working. Maybe this code requires a small adjusment to get work [https://jsfiddle.net/sebasz1000/krLfa39o/162/]

Now I will try quaternian approach on another fiddle


#8

Okay! I already solve this: [https://jsfiddle.net/sebasz1000/35jodpyr/342/]

By using quaternions approach I finally did it! I made getQuaternionFromPoints that returns the quaternion value between given points A(clicked pickertPoint - aqua box) and B(fixed point- red plane).

function getQuaternionFromPoints(initPoint, endPoint) {
    var startVector = (initPoint === undefined ? new THREE.Vector3() : initPoint.normalize())
    var endVector = (endPoint === undefined ? new THREE.Vector3() : endPoint.normalize())
    var q = new THREE.Quaternion();

    q.setFromUnitVectors(startVector, endVector)

    return q 
}

So I got my target Quaternion to make the tweening:

 const euler = new THREE.Euler()
 const startQuaternion = new THREE.Quaternion()
 const endQuaternion = getQuaternionFromPoints(pickerPoint, staticPoint.position)
  
  startQuaternion.copy(sphere.quaternion).normalize()

  const worldRotation = new TWEEN.Tween(startQuaternion)
                                 .to( endQuaternion, 2000)
  				                 .delay(500)
                                 .easing(TWEEN.Easing.Exponential.InOut)
                                 .onUpdate( function() {
                                               euler.setFromQuaternion(startQuaternion)
                                               sphere.setRotationFromEuler(euler)
                                  });
  worldRotation.start()

Solved Issue!

ADDITIONAL THING: Yellow point trajectory is calculated using spherical point with getAngleFromSphericals() method. This point is expected to be the camera travel position( I am working on how to stick camera on it now), so this way Camera and clicked pickerPoint will meet just in the static redPoint.