Three.js线向量到圆柱?

时间:2013-03-09 21:29:27

标签: three.js

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

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

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

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

10 个答案:

答案 0 :(得分:7)

我遇到了完全相同的问题 - 在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;
}

答案 1 :(得分:4)

实际上没有其他答案对我有用,但是为了给予信任,我使用了代码 调整边缘的位置,工作正常。

使用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添加为参数,以便有人可以重复使用相同的对象而不是在每次调用中创建一个新对象

答案 2 :(得分:3)

在版本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;
        }

答案 3 :(得分:2)

pull request #3307以来的ArrowHelper基于四元数。

这适用于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;
    }

答案 4 :(得分:1)

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

希望这有助于某人!

答案 5 :(得分: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));

不需要。

答案 6 :(得分:1)

使用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;
}

答案 7 :(得分: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;
}

答案 8 :(得分: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向量需要.clone(),以便以后在position计算中使用它

答案 9 :(得分:-1)

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

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