【问题标题】:Three.js line vector to cylinder?Three.js 线向量到圆柱体?
【发布时间】:2013-02-25 07:17:36
【问题描述】:

我有这个在两点之间创建一条线:

var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0, 0, 0));
geometry.vertices.push(new THREE.Vector3(20, 100, 55));
var line = new THREE.Line(geometry, material, parameters = { linewidth: 400 });
scene.add(line);

(线宽,没有任何影响。)

我的问题是如何将其转换为圆柱体?我想在两点之间创建一个圆柱体。

【问题讨论】:

标签: three.js


【解决方案1】:

截至 2020 年 12 月:

我已尝试完全实现之前回复中所说的内容,但没有任何效果。

我的解决方案:

cylinderMesh = function (pointX, pointY) {
   // edge from X to Y
   var direction = new THREE.Vector3().subVectors(pointY, pointX);
   const material = new THREE.MeshBasicMaterial({ color: 0x5B5B5B });
   // Make the geometry (of "direction" length)
   var geometry = new THREE.CylinderGeometry(0.04, 0.04, direction.length(), 6, 4, true);
   // shift it so one end rests on the origin
   geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, direction.length() / 2, 0));
   // rotate it the right way for lookAt to work
   geometry.applyMatrix(new THREE.Matrix4().makeRotationX(THREE.Math.degToRad(90)));
   // Make a mesh with the geometry
   var mesh = new THREE.Mesh(geometry, material);
   // Position it where we want
   mesh.position.copy(pointX);
   // And make it point to where we want
   mesh.lookAt(pointY);

   return mesh;
}

【讨论】:

  • 这个答案在 2022 年 1 月完美运行!
【解决方案2】:

老问题,但今天仍然适用。基于 Lee Stemkoski 的回答,这就是我最终开始工作的内容:

const cylinderMesh = function( pointX, pointY )
{
    // edge from X to Y
    const direction = new THREE.Vector3().subVectors( pointY, pointX );
    const arrow = new THREE.ArrowHelper( direction.clone().normalize(), pointY );

    // cylinder: radiusAtTop, radiusAtBottom, 
    //     height, radiusSegments, heightSegments
    const edgeGeometry = new THREE.CylinderGeometry( 2, 2, direction.length(), 6, 4 );

    const edge = new THREE.Mesh( edgeGeometry, 
        new THREE.MeshBasicMaterial( { color: 0x0000ff } ) );
    edge.rotation = arrow.rotation.clone();
    edge.position = new THREE.Vector3().addVectors( pointX, direction.multiplyScalar(0.5) );
    return edge;
}

注意主要区别:您必须对direction 向量进行规范化,并将原点设为pointY。规范化direction 向量需要.clone(),以便您稍后在position 计算中使用它

【讨论】:

    【解决方案3】:

    使用 r94 的解决方案:

    function cylindricalSegment(A, B, radius, material) {
      var vec = B.clone(); vec.sub(A);
      var h = vec.length();
      vec.normalize();
      var quaternion = new THREE.Quaternion();
      quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), vec);
      var geometry = new THREE.CylinderGeometry(radius, radius, h, 32);
      geometry.translate(0, h / 2, 0);
      var cylinder = new THREE.Mesh(geometry, material);
      cylinder.applyQuaternion(quaternion);
      cylinder.position.set(A.x, A.y, A.z);
      return cylinder;
    }
    

    【讨论】:

      【解决方案4】:

      要旋转方向,可以使用

      edge.rotateX(Math.PI / 2);
      

      或者

      edge.rotateY(Math.PI / 2);
      

      或者

      edge.rotateZ(Math.PI / 2);
      

      根据您要旋转的坐标。因此,上面发布的代码是:

      var orientation = new THREE.Matrix4();
      /* THREE.Object3D().up (=Y) default orientation for all objects */
      orientation.lookAt(pointX, pointY, new THREE.Object3D().up);
      /* rotation around axis X by -90 degrees 
       * matches the default orientation Y 
       * with the orientation of looking Z */
      orientation.multiply(new THREE.Matrix4(1,0,0,0,
                                             0,0,1,0, 
                                             0,-1,0,0,
                                             0,0,0,1));
      

      不需要。

      【讨论】:

        【解决方案5】:

        我发现只能匹配一个点,所以我编辑它(将pointX更改为pointY)如下所示,它可以工作

        edge.position = new
        THREE.Vector3().addVectors(pointY,direction.multiplyScalar(0.5));
        

        【讨论】:

          【解决方案6】:

          在版本 70 中停止为我工作,但在这次更新中它确实如此:)

          function cylinderMesh(pointX, pointY, material) {
                      var direction = new THREE.Vector3().subVectors(pointY, pointX);
                      var orientation = new THREE.Matrix4();
                      orientation.lookAt(pointX, pointY, new THREE.Object3D().up);
                      orientation.multiply(new THREE.Matrix4().set(1, 0, 0, 0,
                          0, 0, 1, 0,
                          0, -1, 0, 0,
                          0, 0, 0, 1));
                      var edgeGeometry = new THREE.CylinderGeometry(2, 2, direction.length(), 8, 1);
                      var edge = new THREE.Mesh(edgeGeometry, material);
                      edge.applyMatrix(orientation);
                      // position based on midpoints - there may be a better solution than this
                      edge.position.x = (pointY.x + pointX.x) / 2;
                      edge.position.y = (pointY.y + pointX.y) / 2;
                      edge.position.z = (pointY.z + pointX.z) / 2;
                      return edge;
                  }
          

          【讨论】:

          • 这与肯尼的回答有何不同?
          • 非常感谢。使用 r91。你知道如何为 2 个移动点设置动画吗?您需要重新创建圆柱体,还是有其他方法?谢谢(我是菜鸟)
          【解决方案7】:

          我想我会发布这个,因为答案并没有让我 100% 到达那里。我注意到圆柱体的方向正确,但它们的位置是参考原点的。以下代码(基于此问题的其他答案)对我有用:

          function cylinderMesh(pointX, pointY, material) {
              var direction = new THREE.Vector3().subVectors(pointY, pointX);
              var orientation = new THREE.Matrix4();
              orientation.lookAt(pointX, pointY, new THREE.Object3D().up);
              orientation.multiply(new THREE.Matrix4(1, 0, 0, 0,
                                                     0, 0, 1, 0,
                                                     0, -1, 0, 0,
                                                     0, 0, 0, 1));
              var edgeGeometry = new THREE.CylinderGeometry(2, 2, direction.length(), 8, 1);
              var edge = new THREE.Mesh(edgeGeometry, material);
              edge.applyMatrix(orientation);
              // position based on midpoints - there may be a better solution than this
              edge.position.x = (pointY.x + pointX.x) / 2;
              edge.position.y = (pointY.y + pointX.y) / 2;
              edge.position.z = (pointY.z + pointX.z) / 2;
              return edge;
          }
          

          希望这对某人有所帮助!

          【讨论】:

            【解决方案8】:

            实际上没有其他答案对我有用,但为了表扬我使用的代码 调整边缘的位置并且工作正常。

            使用this answer的部分内容并查看threejs的来源,我最终得到以下结果

            var cylinderMesh = function( pointX, pointY )
            {
                /* edge from X to Y */
                var direction = new THREE.Vector3().subVectors( pointY, pointX );
                var orientation = new THREE.Matrix4();
                /* THREE.Object3D().up (=Y) default orientation for all objects */
                orientation.lookAt(pointX, pointY, new THREE.Object3D().up);
                /* rotation around axis X by -90 degrees 
                 * matches the default orientation Y 
                 * with the orientation of looking Z */
                orientation.multiply(new THREE.Matrix4(1,0,0,0,
                                                        0,0,1,0, 
                                                        0,-1,0,0,
                                                        0,0,0,1));
            
                /* cylinder: radiusAtTop, radiusAtBottom, 
                    height, radiusSegments, heightSegments */
                var edgeGeometry = new THREE.CylinderGeometry( 2, 2, direction.length(), 8, 1);
                var edge = new THREE.Mesh( edgeGeometry, 
                        new THREE.MeshBasicMaterial( { color: 0x0000ff } ) );
            
                edge.applyMatrix(orientation)
                edge.position = new THREE.Vector3().addVectors( pointX, direction.multiplyScalar(0.5) );
                return edge;
            }
            

            一个可能的改进是添加 edgeGeometry 和 material 作为参数,这样人们就可以重用相同的对象,而不是在每次调用时都创建一个新对象

            【讨论】:

            • 工作于 2017 年 10 月 - 此页面上的其他解决方案已过时。
            • 这在 r84 上对我不起作用。我不得不先创建一个 Matrix4,然后在其上设置参数。像这样: var m = new THREE.Matrix4(); m.set(1,0,0,0,0,0,1,0,0,-1,0,0,0,0,0,1);方向.multiply(m);
            【解决方案9】:

            ArrowHelper 因为pull request #3307 是基于四元数的。

            这适用于three.js r58:

                var cylinderMesh = function(point1, point2, material)
                {
                    var direction = new THREE.Vector3().subVectors(point2, point1);
                    var arrow = new THREE.ArrowHelper(direction.clone().normalize(), point1);
            
                    var rotation = new THREE.Vector3().setEulerFromQuaternion(arrow.quaternion);
            
                    var edgeGeometry = new THREE.CylinderGeometry( 2, 2, direction.length(), 10, 4 );
            
                    var edge = new THREE.Mesh(edgeGeometry, material);
                    edge.rotation = rotation.clone();
                    edge.position = new THREE.Vector3().addVectors(point1, direction.multiplyScalar(0.5));
            
                    return edge;
                }
            

            【讨论】:

              【解决方案10】:

              我也遇到了完全相同的问题——在 WebGL 中,线宽始终为 1。所以这是我编写的一个函数,它将采用两个 Vector3 对象并生成一个圆柱体网格:

              var cylinderMesh = function( pointX, pointY )
              {
                  // edge from X to Y
                  var direction = new THREE.Vector3().subVectors( pointY, pointX );
                  var arrow = new THREE.ArrowHelper( direction, pointX );
              
                  // cylinder: radiusAtTop, radiusAtBottom, 
                  //     height, radiusSegments, heightSegments
                  var edgeGeometry = new THREE.CylinderGeometry( 2, 2, direction.length(), 6, 4 );
              
                  var edge = new THREE.Mesh( edgeGeometry, 
                      new THREE.MeshBasicMaterial( { color: 0x0000ff } ) );
                  edge.rotation = arrow.rotation.clone();
                  edge.position = new THREE.Vector3().addVectors( pointX, direction.multiplyScalar(0.5) );
                  return edge;
              }
              

              【讨论】:

              • 应该是.subVectors( pointY, pointX ).addVectors( pointX, direction.multiplyScalar(0.5) )
              • 似乎没有任何效果。认为我犯了一个错误。矢量线出现了,但没有圆柱体,也没有错误。这是我使用的代码:pastie.org/private/znr7wa4d4delrjifxbegq
              • 我认为错误会出现在这里edge.rotation = arrow.rotation.clone(),但我没有费心检查并最终手动旋转
              猜你喜欢
              • 1970-01-01
              • 2012-02-20
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-05-30
              相关资源
              最近更新 更多