admin管理员组

文章数量:1026956

Hi all, I am developing a project in Three.js where the user can hover a tessellated face, and each mesh should be pushed away whenever it intersects and invisible sphere and, go back to its original position when its outside from its area. I am using this and this example as reference, but I got stuck since I don't know how to make it work in Three.js.

In my code, I am able to hover each face of a mesh, make it red and restore its original colour after that the mouse is gone. But I can't do something similar with the position. This is the part of the code where I think the issue is:

if (intersects.length > 0) {

    // if the closest object intersected is not the currently stored intersection object
    if (intersects[0].object != INTERSECTED) {

        // Restore previous intersection objects (if they exist) to their original color
        if (INTERSECTED) {
            INTERSECTED.face.color.setHex(INTERSECTED.currentHex);
        }

        // Intersected elements
        INTERSECTED = intersects[0];
        var intGeometry = INTERSECTED.object.geometry;
        var intFace     = INTERSECTED.face;

        // Difference between intersected faces and geometry
        INTERSECTED.currentHex = intFace.color.getHex();
        intFace.color.setHex(0xc0392b);
        intGeometry.colorsNeedUpdate = true;

        // Identify the vertices of each face
        var intVertices = intGeometry.vertices;
        var v1 = intVertices[intFace.a],
            v2 = intVertices[intFace.a],
            v3 = intVertices[intFace.a];

        // Calculate the centroid of the selected face
        var intPosition = new THREE.Vector3();
        intPosition.x = (v1.x + v2.x + v3.x) / 3;
        intPosition.y = (v1.y + v2.y + v3.y) / 3;
        intPosition.z = (v1.z + v2.z + v3.z) / 3;
        console.log(intPosition);
    }

}

Via console.log() I can see that the faces are correctly recognised together with also their position, but the sphere is not tracking the mouse properly and I need help with the position. This is a JSFiddle with the full code.

Hi all, I am developing a project in Three.js where the user can hover a tessellated face, and each mesh should be pushed away whenever it intersects and invisible sphere and, go back to its original position when its outside from its area. I am using this and this example as reference, but I got stuck since I don't know how to make it work in Three.js.

In my code, I am able to hover each face of a mesh, make it red and restore its original colour after that the mouse is gone. But I can't do something similar with the position. This is the part of the code where I think the issue is:

if (intersects.length > 0) {

    // if the closest object intersected is not the currently stored intersection object
    if (intersects[0].object != INTERSECTED) {

        // Restore previous intersection objects (if they exist) to their original color
        if (INTERSECTED) {
            INTERSECTED.face.color.setHex(INTERSECTED.currentHex);
        }

        // Intersected elements
        INTERSECTED = intersects[0];
        var intGeometry = INTERSECTED.object.geometry;
        var intFace     = INTERSECTED.face;

        // Difference between intersected faces and geometry
        INTERSECTED.currentHex = intFace.color.getHex();
        intFace.color.setHex(0xc0392b);
        intGeometry.colorsNeedUpdate = true;

        // Identify the vertices of each face
        var intVertices = intGeometry.vertices;
        var v1 = intVertices[intFace.a],
            v2 = intVertices[intFace.a],
            v3 = intVertices[intFace.a];

        // Calculate the centroid of the selected face
        var intPosition = new THREE.Vector3();
        intPosition.x = (v1.x + v2.x + v3.x) / 3;
        intPosition.y = (v1.y + v2.y + v3.y) / 3;
        intPosition.z = (v1.z + v2.z + v3.z) / 3;
        console.log(intPosition);
    }

}

Via console.log() I can see that the faces are correctly recognised together with also their position, but the sphere is not tracking the mouse properly and I need help with the position. This is a JSFiddle with the full code.

Share Improve this question edited Mar 18, 2016 at 10:18 Nakilon 35.1k16 gold badges112 silver badges148 bronze badges asked Mar 14, 2016 at 13:24 d_z90d_z90 1,2632 gold badges20 silver badges49 bronze badges 2
  • 1 For sphere to follow mouse, you need to convert screen coordinates to threejs world position. Check this link . And updated fiddle here, changed code starts at line 375. – uhura Commented Mar 16, 2016 at 21:29
  • Thanks man! This was part of an issue of another question I have asked, if you want you can post the answer there and get rewarded. – d_z90 Commented Mar 17, 2016 at 8:10
Add a ment  | 

3 Answers 3

Reset to default 4 +150

Here is a small test about the subject: https://jsfiddle/77xvepp7/

It does not work properly yet, I moved the camera a bit further so the idea can be seen.

The basic idea is to pick one vertex from the surface as the "base point", it could be the center of the surface as you did in your example, and keep that point as the reference point to move all other points in the triangle by same amount. If you do not save the original value, then the next round may have invalid values and the triangles will move a bit randomly.

Then you calculate the distance of the mouse to the "base point", go through all the vertices and move them to the direction of the base point some amount. If the distance is greater than some defined amount, restore the original value from the vertex.

You might try to do that using vertex shader, but the problem is that when the mouse is over the surface each vertex would go to opposite direction and the triangle which is under the mouse would scale to fill the void. Selecting one point as the "base point" removes this problem.

  // Modify the geometry
  var geometry = backgroundMesh.geometry;
    for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {

        var face = geometry.faces[ i ];

        if ( face instanceof THREE.Face3 ) {

            var a = geometry.vertices[face.a];
            var b = geometry.vertices[face.b];
            var c = geometry.vertices[face.c];
            var vList = [a,b,c];

            // The trick is to save the original face positions
            if(!a.origXSet) {
               a.origX = a.x;
               a.origY = a.y;
               a.origZ = a.z;
               a.origXSet = true;
            }

            var vect = a;
            var dx = (vect.origX - pos.x), 
                dy = (vect.origY - pos.y), 
                dz = (vect.origZ - pos.z);

            // distance to the mouse
            var dist = Math.sqrt( dx*dx + dy*dy);

            // magic constant, react if distance smaller than 4
            if(dist < 4) {
              vList.forEach(function(v) {
              if(!v.origXSet) {
                   v.origX = v.x;
                   v.origY = v.y;
                   v.origZ = v.z;
                   v.origXSet = true;
               }
               var len = Math.sqrt(dx*dx + dy*dy + dz*dz);
               if(len==0) return;
               var ndx = dx / len,
                   ndy = dy / len,
                   ndz = dz / len;
               v.x = v.origX + ndx * 2; // move 2 pixels
               v.y = v.origY + ndy * 2; 
               v.z = v.origZ + ndz * 2;
      });

      } else {
          // otherwise, reset coordinates
          vList.forEach(function(v) {
            if(v.origXSet) {
             v.x = v.origX;
             v.y = v.origY;   
             v.z = v.origZ;
             }
           });
      }

       geometry.verticesNeedUpdate = true;
       geometry.normalsNeedUpdate = true;    

    }
 }

The main problems are: the position of the mouse pointer in the World Coordinates is not correctly calculated. Right now I don't have the energy to think about how to correct that, but decided to post this answer so that you can continue from that.

You are not assigning something back to your geometry. Something to the effect:

intVertices[intFace.a].copy( intPosition );
intVertices[intFace.b].copy( intPosition );
intVertices[intFace.c].copy( intPosition );

intGeometry.verticesNeedUpdate = true;
intGeometry.normalsNeedUpdate = true;

the problem you having it that the targetList that you try ray.intersectObjects is not a THREE.Mesh instance. because of that when you try to access to intersectedFace.acc it's throw an error

Hi all, I am developing a project in Three.js where the user can hover a tessellated face, and each mesh should be pushed away whenever it intersects and invisible sphere and, go back to its original position when its outside from its area. I am using this and this example as reference, but I got stuck since I don't know how to make it work in Three.js.

In my code, I am able to hover each face of a mesh, make it red and restore its original colour after that the mouse is gone. But I can't do something similar with the position. This is the part of the code where I think the issue is:

if (intersects.length > 0) {

    // if the closest object intersected is not the currently stored intersection object
    if (intersects[0].object != INTERSECTED) {

        // Restore previous intersection objects (if they exist) to their original color
        if (INTERSECTED) {
            INTERSECTED.face.color.setHex(INTERSECTED.currentHex);
        }

        // Intersected elements
        INTERSECTED = intersects[0];
        var intGeometry = INTERSECTED.object.geometry;
        var intFace     = INTERSECTED.face;

        // Difference between intersected faces and geometry
        INTERSECTED.currentHex = intFace.color.getHex();
        intFace.color.setHex(0xc0392b);
        intGeometry.colorsNeedUpdate = true;

        // Identify the vertices of each face
        var intVertices = intGeometry.vertices;
        var v1 = intVertices[intFace.a],
            v2 = intVertices[intFace.a],
            v3 = intVertices[intFace.a];

        // Calculate the centroid of the selected face
        var intPosition = new THREE.Vector3();
        intPosition.x = (v1.x + v2.x + v3.x) / 3;
        intPosition.y = (v1.y + v2.y + v3.y) / 3;
        intPosition.z = (v1.z + v2.z + v3.z) / 3;
        console.log(intPosition);
    }

}

Via console.log() I can see that the faces are correctly recognised together with also their position, but the sphere is not tracking the mouse properly and I need help with the position. This is a JSFiddle with the full code.

Hi all, I am developing a project in Three.js where the user can hover a tessellated face, and each mesh should be pushed away whenever it intersects and invisible sphere and, go back to its original position when its outside from its area. I am using this and this example as reference, but I got stuck since I don't know how to make it work in Three.js.

In my code, I am able to hover each face of a mesh, make it red and restore its original colour after that the mouse is gone. But I can't do something similar with the position. This is the part of the code where I think the issue is:

if (intersects.length > 0) {

    // if the closest object intersected is not the currently stored intersection object
    if (intersects[0].object != INTERSECTED) {

        // Restore previous intersection objects (if they exist) to their original color
        if (INTERSECTED) {
            INTERSECTED.face.color.setHex(INTERSECTED.currentHex);
        }

        // Intersected elements
        INTERSECTED = intersects[0];
        var intGeometry = INTERSECTED.object.geometry;
        var intFace     = INTERSECTED.face;

        // Difference between intersected faces and geometry
        INTERSECTED.currentHex = intFace.color.getHex();
        intFace.color.setHex(0xc0392b);
        intGeometry.colorsNeedUpdate = true;

        // Identify the vertices of each face
        var intVertices = intGeometry.vertices;
        var v1 = intVertices[intFace.a],
            v2 = intVertices[intFace.a],
            v3 = intVertices[intFace.a];

        // Calculate the centroid of the selected face
        var intPosition = new THREE.Vector3();
        intPosition.x = (v1.x + v2.x + v3.x) / 3;
        intPosition.y = (v1.y + v2.y + v3.y) / 3;
        intPosition.z = (v1.z + v2.z + v3.z) / 3;
        console.log(intPosition);
    }

}

Via console.log() I can see that the faces are correctly recognised together with also their position, but the sphere is not tracking the mouse properly and I need help with the position. This is a JSFiddle with the full code.

Share Improve this question edited Mar 18, 2016 at 10:18 Nakilon 35.1k16 gold badges112 silver badges148 bronze badges asked Mar 14, 2016 at 13:24 d_z90d_z90 1,2632 gold badges20 silver badges49 bronze badges 2
  • 1 For sphere to follow mouse, you need to convert screen coordinates to threejs world position. Check this link . And updated fiddle here, changed code starts at line 375. – uhura Commented Mar 16, 2016 at 21:29
  • Thanks man! This was part of an issue of another question I have asked, if you want you can post the answer there and get rewarded. – d_z90 Commented Mar 17, 2016 at 8:10
Add a ment  | 

3 Answers 3

Reset to default 4 +150

Here is a small test about the subject: https://jsfiddle/77xvepp7/

It does not work properly yet, I moved the camera a bit further so the idea can be seen.

The basic idea is to pick one vertex from the surface as the "base point", it could be the center of the surface as you did in your example, and keep that point as the reference point to move all other points in the triangle by same amount. If you do not save the original value, then the next round may have invalid values and the triangles will move a bit randomly.

Then you calculate the distance of the mouse to the "base point", go through all the vertices and move them to the direction of the base point some amount. If the distance is greater than some defined amount, restore the original value from the vertex.

You might try to do that using vertex shader, but the problem is that when the mouse is over the surface each vertex would go to opposite direction and the triangle which is under the mouse would scale to fill the void. Selecting one point as the "base point" removes this problem.

  // Modify the geometry
  var geometry = backgroundMesh.geometry;
    for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {

        var face = geometry.faces[ i ];

        if ( face instanceof THREE.Face3 ) {

            var a = geometry.vertices[face.a];
            var b = geometry.vertices[face.b];
            var c = geometry.vertices[face.c];
            var vList = [a,b,c];

            // The trick is to save the original face positions
            if(!a.origXSet) {
               a.origX = a.x;
               a.origY = a.y;
               a.origZ = a.z;
               a.origXSet = true;
            }

            var vect = a;
            var dx = (vect.origX - pos.x), 
                dy = (vect.origY - pos.y), 
                dz = (vect.origZ - pos.z);

            // distance to the mouse
            var dist = Math.sqrt( dx*dx + dy*dy);

            // magic constant, react if distance smaller than 4
            if(dist < 4) {
              vList.forEach(function(v) {
              if(!v.origXSet) {
                   v.origX = v.x;
                   v.origY = v.y;
                   v.origZ = v.z;
                   v.origXSet = true;
               }
               var len = Math.sqrt(dx*dx + dy*dy + dz*dz);
               if(len==0) return;
               var ndx = dx / len,
                   ndy = dy / len,
                   ndz = dz / len;
               v.x = v.origX + ndx * 2; // move 2 pixels
               v.y = v.origY + ndy * 2; 
               v.z = v.origZ + ndz * 2;
      });

      } else {
          // otherwise, reset coordinates
          vList.forEach(function(v) {
            if(v.origXSet) {
             v.x = v.origX;
             v.y = v.origY;   
             v.z = v.origZ;
             }
           });
      }

       geometry.verticesNeedUpdate = true;
       geometry.normalsNeedUpdate = true;    

    }
 }

The main problems are: the position of the mouse pointer in the World Coordinates is not correctly calculated. Right now I don't have the energy to think about how to correct that, but decided to post this answer so that you can continue from that.

You are not assigning something back to your geometry. Something to the effect:

intVertices[intFace.a].copy( intPosition );
intVertices[intFace.b].copy( intPosition );
intVertices[intFace.c].copy( intPosition );

intGeometry.verticesNeedUpdate = true;
intGeometry.normalsNeedUpdate = true;

the problem you having it that the targetList that you try ray.intersectObjects is not a THREE.Mesh instance. because of that when you try to access to intersectedFace.acc it's throw an error

本文标签: javascriptThreejsPush away and then restore elements position on quotmouse movequotStack Overflow