13

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

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);

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

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

4

10 回答 10

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;
}
于 2013-03-09T21:51:24.577 回答
5

截至 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;
}
于 2020-12-28T21:55:00.883 回答
4

在版本 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;
        }
于 2015-02-11T16:42:39.223 回答
4

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

使用这个答案的一部分并查看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 作为参数,这样人们就可以重用相同的对象,而不是在每次调用中创建一个新对象

于 2014-02-16T06:10:49.753 回答
2

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;
    }
于 2013-05-02T22:14:52.783 回答
2

我想我会发布这个,因为答案没有让我 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;
}

希望这对某人有帮助!

于 2014-09-10T15:55:47.383 回答
2

使用 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;
}
于 2018-07-03T13:31:56.220 回答
1

要旋转方向,您可以使用

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));

将不需要。

于 2017-08-02T08:47:46.317 回答
0

老问题,但今天仍然相关。基于 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向量需要 a.clone()以允许您稍后在position计算中使用它

于 2020-07-17T17:35:32.017 回答
-1

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

edge.position = new
THREE.Vector3().addVectors(pointY,direction.multiplyScalar(0.5));
于 2016-10-24T07:40:58.537 回答