three.js:沿新轴放置 THREE.group 的旋转矩阵

three.js: rotational matrix to place THREE.group along new axis

(也请参考我对问题的说明: http://i.stack.imgur.com/SfwwP.png)

问题描述及思路

我正在标准 XYZ 坐标系中创建多个 objects。 这些被添加到 THREE.group.

请将该组想象成墙上挂着几个框架和图像。 我想用例如创建我的框架 objects。 (40, 20, 0.5) 的维度。所以我得到一个相当平坦的景观格式 frame/artwork。我创建并放置了其中的几个。然后我将它们添加到组中,我想沿着两个向量 startend.

在世界中自由旋转

我正在努力解决的问题是如何将 group 从给定向量 start 旋转和定位到给定向量 end

到目前为止,我试图用 THREE.Matrix4().lookAt 解决它:

var group = new THREE.Group();
startVec = new THREE.Vector3( 100, 0, -100 );
endVec = new THREE.Vector3( -200, 0, 200 );
matrix = new THREE.Matrix4().lookAt(startVec, endVec, new THREE.Vector3( 0, 1, 0 ));
group.matrixAutoUpdate = false;

var object1 = new THREE.Mesh(new THREE.BoxGeometry(0.5, 20, 40), mat);
// etc. -> notice the swapping of X and Z coordinates I have to do.
group.add(object1);

group.applyMatrix(matrix);

你可以在jsfiddle上看到例子: http://jsfiddle.net/y6b9Lumw/1/

如果你打开 jsfiddle,你可以看到 objects 没有沿着从 startend 的线放置,尽管我将它们放置在组内部 X-Axis喜欢:addBox(new THREE.Vector3( i * 30, 0 , 0 ));

完整代码:

<html>
<head>
<title>testing a rotation matrix</title>
 <style>body { margin: 0; } canvas { width: 100%; height: 100% } </style>
</head> <body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js"></script>
<script>

var scene, camera, renderer, light, matrix;
var startVec, endVec;
var boxes;


function addBox(v) {
    var boxmesh;
    var boxgeom = new THREE.BoxGeometry( 15, 5, 1 );
    var boxmaterial = new THREE.MeshLambertMaterial( {color: 0xdd2222} );
    boxmesh = new THREE.Mesh( boxgeom, boxmaterial );

    //boxmesh.matrix.makeRotationY(Math.PI / 2);
    boxmesh.matrix.setPosition(v);

    boxmesh.matrixAutoUpdate = false;

    boxes.add(boxmesh);
}
function init() {
    renderer = new THREE.WebGLRenderer();
                    renderer.setClearColor( 0x222222 );
                    renderer.setPixelRatio( window.devicePixelRatio );
                    renderer.setSize( window.innerWidth, window.innerHeight );
                    document.body.appendChild( renderer.domElement );

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
    camera.position.set( -20, 30, 300 );

    var light = new THREE.PointLight (0xCCCCCC, 0.5 );
    scene.add(light);

    startVec = new THREE.Vector3( 100, 0, -100 );
    endVec = new THREE.Vector3( -200, 0, 200 );
    matrix = new THREE.Matrix4().lookAt(startVec, endVec, new THREE.Vector3( 0, 1, 0 ));

    boxes   = new THREE.Group();


    for (var i = -100; i <  100; i++) {
        addBox(new THREE.Vector3( i * 30, 0 , 0 ));
    }

    boxes.matrixAutoUpdate = false;
    boxes.applyMatrix(matrix);
    scene.add(boxes);



    var linegeometry = new THREE.Geometry();
    linegeometry.vertices.push( startVec, endVec);
    var line = new THREE.Line(linegeometry, new THREE.LineBasicMaterial({color: 0x33eeef}));
    scene.add(line);


    render();
}

function render(){

  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
init();



</script>
</body> </html>

这在一定程度上效果很好。由于外观矢量通常沿 Z-Axis 方向(我认为它是 (0,0,1))。所以不幸的是,组内的 objects 也像那样旋转。 这实际上是您对 lookAt() 旋转变换的期望。这不是我想要的,因为这会将组中的所有 children 放在 他们的 Z-Axis 上,而不是他们的 X-Axis .

为了让事情看起来正常,我不得不用 XZ 交换来初始化我的组 children。 而不是:

var object1 = new THREE.BoxGeometry( 40, 20, 0.5 );

我必须做的:

var object1 = new THREE.BoxGeometry( 0.5, 20, 40 );

同样,如果我想在X-Axis组中翻译objects,我必须使用Z-Axis,因为那是look-vector整面墙由矩阵变换定向

我的问题是: 我的矩阵必须如何 constructed/look 才能完成我想要的:通常创建 objects,然后将它们的 X-Axis 沿向量 start 和向量 [=17= 放置],比如把艺术品放在墙上,可以四处移动? 我想创建一个矩阵,其 X-Axis 是 end.sub(start),所以从开始到结束的向量,这可能是我需要做的吗?如果是这样,我将如何构建它?

用图片说明问题

我试图用两张图片来说明我的情况。一个是 wall,一个是 world 内部的墙,wall 附有相同的 objects (见顶post)。

在第一个图中,您可以看到 的局部坐标系,添加了两个 children,一个沿 X 平移。 在第二张图中,您可以看到世界内部的同一个本地系统,我希望它是这样的。绿色轴是世界轴。还显示了 startend 向量。您可以看到,两个盒子都沿着那条线正确放置。

我想通过忽略自己操作矩阵的想法来回答我自己的问题。谢谢@WestLangley 我通过 .setFromUnitVectors 设置组 quaternion 将我的想法调整为以下内容。 所以旋转是从x轴startend[=24=的方向向量的旋转得出的],如 three.js 文档中所述:

"Sets this quaternion to the rotation required to rotate direction vector vFrom to direction vector vTo." (http://threejs.org/docs/#Reference/Math/Quaternion.setFromUnitVectors)

以下是我的解决方案的相关部分:

// define the starting and ending vector of the wall
start = new THREE.Vector3( -130, -40, 300 );
end = new THREE.Vector3( 60, 20, -100 );

// dir is the direction from start to end, normalized
var dir = new THREE.Vector3().copy(end).sub(start).normalize();

// position wall in the middle of start and end
var middle = new THREE.Vector3().copy(start).lerp(end, 0.5);
wall.position.copy(middle);

// rotate wall by applying rotation from X-Axis to dir
wall.quaternion.setFromUnitVectors( new THREE.Vector3(1, 0, 0), dir );

结果可以在这里看到:http://jsfiddle.net/L9dmqqvy/1/