【问题标题】:Three.js Object3d cylinder rotation to align to a vectorThree.js Object3d 圆柱体旋转以对齐向量
【发布时间】:2012-02-20 17:56:19
【问题描述】:

我进行了广泛的搜索,但似乎无法弄清楚这个非常基本的事情。一两年前,我在 stackoverflow 和其他地方看到过其他示例,但它们无法与最新版本的 Three.js 一起使用。

这是我正在研究的一个版本:http://medschoolgunners.com/sandbox/3d/

我试图让灰色圆锥与未标记的红色矢量完全对齐。 IE。我希望圆锥的尖端与向量完全对齐,并从原点指向该方向。

这是我现在拥有的代码:

    //FUNCTION TO CREATE A CYLINDER
function create_cylinder(radiusTop,radiusBottom, height, segmentsRadius, segmentsHeight, openEnded, color)
{
var material = new THREE.MeshLambertMaterial({
    color: color, //0x0000ff
    opacity: 0.2
});
var cylinder = new THREE.Mesh(new THREE.CylinderGeometry(radiusTop,radiusBottom, height, segmentsRadius, segmentsHeight, openEnded), material);

cylinder.overdraw = true;

return cylinder;
}

//ALIGN THE CYLINDER TO A GIVEN VECTOR
var alignVector=new THREE.Vector3(-50,50,50); //the vector to be aligned with

var newcylinder = create_cylinder(0.1, 10, 40, 50, 50, false, "0x0ff0f0");  // the object to be aligned with the vector above

var cylinderQuaternion = new THREE.Quaternion();
cylinderQuaternion.setFromEuler(alignVector);
newcylinder.useQuaternion = true;
newcylinder.quaternion=cylinderQuaternion;

scatterPlot.add(newcylinder);

【问题讨论】:

    标签: javascript rotation three.js quaternions


    【解决方案1】:

    如果你有一个任意向量:

    var vector = new THREE.Vector3(100, 60, 20);
    

    您可以将对象(例如圆柱体)与矢量对齐,如下所示:

    var geometry = new THREE.CylinderGeometry(2, 2, vector.length(), 4, 4);
    var mesh = new THREE.Mesh(geometry, someMaterial);
    var axis = new THREE.Vector3(0, 1, 0);
    mesh.quaternion.setFromUnitVectors(axis, vector.clone().normalize());
    

    其中axis 是圆柱体的原始方向(向上)。

    您也可以像这样移动圆柱体以匹配矢量的位置:

    mesh.position.copy(vector.clone().multiplyScalar(0.5));
    

    这会将圆柱体的一端放在0, 0, 0,另一端放在100, 60, 20,因为我将圆柱体长度设置为vector.length()

    【讨论】:

    • 非常有用且解释清楚:-)。顺便说一句,最后一行代码中有一个太多的结束括号:mesh.position.copy(vector.clone().multiplyScalar(0.5)));
    【解决方案2】:

    我知道这是一个老问题,但如果有人仍然想知道,对我有用的是将矢量添加到网格位置并使用 lookAt 将其与矢量对齐:

    //Mesh to align
    var material = new THREE.MeshLambertMaterial({color: 0x0000ff});
    var cylinder = new THREE.Mesh(new THREE.CylinderGeometry(10, 10, 15), material);
    
    //vector to align to
    var vector = new THREE.Vector3(
        5,//x
        10,//y
        15 //z
    );
    
    //create a point to lookAt
    var focalPoint = new THREE.Vector3(
        cylinder.position.x + vector.x,
        cylinder.position.y + vector.y,
        cylinder.position.z + vector.z
    );
    
    //all that remains is setting the up vector (if needed) and use lookAt
    cylinder.up = new THREE.Vector3(0,0,1);//Z axis up
    cylinder.lookAt(focalPoint); 
    

    【讨论】:

      【解决方案3】:

      很遗憾,我没有使用过四元数,所以帮不上什么忙。在我看来,需要进行一些偏移,因为圆柱体的枢轴位于网格的中心,而不是一端。

      如果稍微玩一下矩阵,我会得到不错的结果。

      这是一种方法,使用 Mesh 的 lookAt() 方法:

      var HALF_PI = -Math.PI * .5;
      var p1 = new THREE.Vector3(Math.random()-.5,Math.random()-.5,Math.random()-.5).multiplyScalar(30);
      var p2 = new THREE.Vector3(Math.random(),Math.random(),Math.random()).multiplyScalar(300);
      var halfLength = diff.length() * .5;
      
      var c = new THREE.CylinderGeometry(10, 10, halfLength * 2, 12, 1, false );
      var orientation = new THREE.Matrix4();
      orientation.setRotationFromEuler(new THREE.Vector3(HALF_PI,0,0));//rotate on X 90 degrees
      orientation.setPosition(new THREE.Vector3(0,0,halfLength));//move half way on Z, since default pivot is at centre
      c.applyMatrix(orientation);//apply transformation for geometry
      
      var m = new THREE.Mesh( c, new THREE.MeshLambertMaterial( { color: 0x009900, wireframe: true, shading: THREE.FlatShading } ) );
      scene.add(m);
      m.lookAt(p2);//tell mesh to orient itself towards p2
      //just for debugging - to illustrate orientation
      m.add(new THREE.Axes());
      
      //visualize p1,p2 vectors
      var PI2 = Math.PI * 2;
      var program = function ( context ) {
      
          context.beginPath();
          context.arc( 0, 0, 1, 0, PI2, true );
          context.closePath();
          context.fill();
      
      }
      
      particleMaterial = new THREE.ParticleCanvasMaterial( { color: 0x990000, program: program } );
      var pp1 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0x990000, program: program } ) );
      pp1.scale.multiplyScalar(10);
      pp1.position.copy(p1);
      scene.add( pp1 );   
      var pp2 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0x009900, program: program } ) );
      pp2.scale.multiplyScalar(10);
      pp2.position.copy(p2);
      scene.add( pp2 );
      

      这应该绘制一个从 p1 开始,在 p2 结束并朝向它的圆柱体。 偏移可能需要一些调整,但几何图形非常接近矢量方向。

      还有更长版本的手动计算矩阵,而不是依赖于lookAt() 功能:

      plane.add(getCylinderBetweenPoints(p1,p2,new THREE.MeshLambertMaterial( { color: 0x009900, wireframe: true, shading: THREE.FlatShading } )));
      
      function getCylinderBetweenPoints(point1,point2,material){
          var HALF_PI = -Math.PI * .5;
          var diff = new THREE.Vector3().sub(point1,point2);//delta vector
          var halfLength = diff.length() * .5;
          var c = new THREE.CylinderGeometry(10, 10, halfLength * 2, 12, 1, false );
          var orientation = new THREE.Matrix4();//a new orientation matrix to offset pivot
          var offsetRotation = new THREE.Matrix4();//a matrix to fix pivot rotation
          var offsetPosition = new THREE.Matrix4();//a matrix to fix pivot position
          orientation.lookAt(point1,point2,new THREE.Vector3(0,1,0));//look at destination
          offsetRotation.setRotationX(HALF_PI);//rotate 90 degs on X
          offsetPosition.setPosition(new THREE.Vector3(-point1.x,diff.length()*.5+point1.z,point1.y*.5));//move by pivot offset on Y
          orientation.multiplySelf(offsetRotation);//combine orientation with rotation transformations
          orientation.multiplySelf(offsetPosition);//combine orientation with position transformations
          c.applyMatrix(orientation);//apply the final matrix
          var m = new THREE.Mesh( c, material );
          m.add(new THREE.Axes());
          return m;
      }
      
      var PI2 = Math.PI * 2;
      var program = function ( context ) {
      
          context.beginPath();
          context.arc( 0, 0, 1, 0, PI2, true );
          context.closePath();
          context.fill();
      
      }
      
      //visualize p1,p2 vectors
      particleMaterial = new THREE.ParticleCanvasMaterial( { color: 0x990000, program: program } );
      var pp1 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0x990000, program: program } ) );
      pp1.scale.multiplyScalar(10);
      pp1.position.copy(p1);
      plane.add( pp1 );   
      var pp2 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0x009900, program: program } ) );
      pp2.scale.multiplyScalar(10);
      pp2.position.copy(p2);
      plane.add( pp2 );
      

      从我在您的代码中看到的情况来看,这看起来比使用四元数更多。如果 setFromEuler 对方向有魔力,那么网格的几何图形仍然可能需要移动(从一端而不是中心旋转)

      HTH

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-25
      • 2018-03-07
      • 2012-09-26
      • 2013-02-14
      • 2015-06-15
      • 2013-07-29
      • 2017-02-01
      相关资源
      最近更新 更多