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。我创建并放置了其中的几个。然后我将它们添加到组中,我想沿着两个向量 start
和 end
.
在世界中自由旋转
我正在努力解决的问题是如何将 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 没有沿着从 start
到 end
的线放置,尽管我将它们放置在组内部 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 .
为了让事情看起来正常,我不得不用 X 和 Z 交换来初始化我的组 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 平移。
在第二张图中,您可以看到世界内部的同一个本地系统,我希望它是这样的。绿色轴是世界轴。还显示了 start
和 end
向量。您可以看到,两个盒子都沿着那条线正确放置。
我想通过忽略自己操作矩阵的想法来回答我自己的问题。谢谢@WestLangley 我通过 .setFromUnitVectors
设置组 quaternion
将我的想法调整为以下内容。
所以旋转是从x轴到start和end[=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/
(也请参考我对问题的说明: http://i.stack.imgur.com/SfwwP.png)
问题描述及思路
我正在标准 XYZ 坐标系中创建多个 objects。 这些被添加到 THREE.group.
请将该组想象成墙上挂着几个框架和图像。
我想用例如创建我的框架 objects。 (40, 20, 0.5) 的维度。所以我得到一个相当平坦的景观格式 frame/artwork。我创建并放置了其中的几个。然后我将它们添加到组中,我想沿着两个向量 start
和 end
.
我正在努力解决的问题是如何将 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 没有沿着从 start
到 end
的线放置,尽管我将它们放置在组内部 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 .
为了让事情看起来正常,我不得不用 X 和 Z 交换来初始化我的组 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 平移。
在第二张图中,您可以看到世界内部的同一个本地系统,我希望它是这样的。绿色轴是世界轴。还显示了 start
和 end
向量。您可以看到,两个盒子都沿着那条线正确放置。
我想通过忽略自己操作矩阵的想法来回答我自己的问题。谢谢@WestLangley 我通过 .setFromUnitVectors
设置组 quaternion
将我的想法调整为以下内容。
所以旋转是从x轴到start和end[=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/