三个 JS 旋转组,与相机的方向相同,用于 View Cube/Orientation Cube
Three JS rotate group with same orientation as camera for View Cube/Orientation Cube
我正在尝试使用三个 JS 制作一个看起来像这样的 blender-esk 方向视图:
我的计划是采取相机旋转并旋转3个矢量点(代表图片中的X,Y和Z气泡)。然后,一旦我有了这些点,我就可以使用 X 和 Y 坐标在 canvas 上画圆,并画线将它们连接到中心。然后我可以使用 Z 方向来确定应该在什么之上绘制什么。
目前我正在使用第二个 three.js 场景来可视化这些 X、Y 和 Z 点的位置,因为我尝试了不同的方式来旋转顶点组以使其与相机的方向相匹配。我在这部分苦苦挣扎,我尝试了很多没有用的东西。
这是我目前所在位置的 JS Fiddle:
https://jsfiddle.net/j9mcL0x4/4/
(不在 Brave 中加载,但在 Chrome 中工作)
当你左右摇摄相机时,它会移动第二个场景中的 3 个立方体,但我无法让它正确旋转。
X、Y 和 Z 点由一组 Vector3 表示:
this.ref = [
[new THREE.Vector3(1,0,0), 0xFF0000],
[new THREE.Vector3(0,1,0), 0x00FF00],
[new THREE.Vector3(0,0,1), 0x0000FF],
]
然后我创建每个多维数据集并将其添加到一个组中:
this.group = new THREE.Group();
for(var pos of this.ref) {
var geometry = new THREE.BoxGeometry(.25,.25,.25);
var material = new THREE.MeshBasicMaterial({
color: pos[1]
});
var cube = new THREE.Mesh(geometry, material);
cube.position.copy(pos[0]);
this.group.add(cube);
}
this.scene.add(this.group);
然后在我的动画函数中,我尝试计算组的旋转以使其与主视图处于相同的方向:
var quaternion = new THREE.Quaternion();
camera.getWorldQuaternion( quaternion );
let rotation = new THREE.Euler();
rotation.setFromQuaternion(quaternion);
var dir = new THREE.Vector3();
dir.subVectors( camera.position, controls.target ).normalize();
orientationHelper.group.rotation.set(dir.x, dir.y, dir.z);
orientationHelper.animate();
我所拥有的是完全错误的,但这里是我尝试过的一些东西:
- 计算相机前面的一个点,然后使用 lookAt 函数使用它让小组朝那个方向看
- 我正在使用轨道控制,它有一个相机聚焦的目标。我已经尝试减去相机位置向量和目标向量以获得外观方向但是这不起作用(当前在 jsfiddle 中的内容)
- 我试过只使用相机局部旋转(并尝试否定它)
备注
我可以在第二个场景中旋转相机以匹配主视图中的相机,但我真的想旋转矢量本身。这样我就可以将这些点投影到基本的 canvas 上以绘制 6 个圆和 3 条线。我觉得这比尝试在 3d 中使用精灵要容易得多,而且三个 JS 不能在不为其创建矩形网格的情况下轻松绘制粗线。
以下是我希望输出的一些示例:
更新
这个问题已由 Rabbid76 解决,如果有人有兴趣在他们的项目中使用 Blender 风格的方位立方体,您可以在此处找到完整的源代码:
https://github.com/jrj2211/three-orientation-gizmo/
或者用npm下载:
首先在视图space中,X轴指向右侧,Y轴指向上方,Z轴指向外canvas.
因此,您必须为正 Z 轴上的 OrientationHelper
相机选择一个初始位置:
class OrientationHelper {
constructor(canvas) {
// [...]
this.camera = new THREE.PerspectiveCamera(75, size / size, 0.1, 1000);
this.camera.position.set(0, 0, 2);
// [...]
下面我推荐在OrientationHelper
场景中通过矩阵设置组的方向:
class OrientationHelper {
// [...]
setCameraRotation(rotation) {
this.group.setRotationFromMatrix(rotation);
}
// [...]
视图矩阵是该矩阵的逆矩阵,它定义了相机的位置和方向。您想要可视化相机的方向。您想可视化视图矩阵的方向。
从 camera.rotation
创建一个旋转矩阵。计算 Inverse matrix 并通过计算矩阵设置 OrientationHelper
的方向:
let rotMat = new THREE.Matrix4().makeRotationFromEuler(camera.rotation);
let invRotMat = new THREE.Matrix4().getInverse(rotMat);
orientationHelper.setCameraRotation(invRotMat);
orientationHelper.update();
看例子:
class OrientationHelper {
constructor(canvas) {
this.canvas = canvas;
this.ref = [
[new THREE.Vector3(1,0,0), 0xFF0000],
[new THREE.Vector3(0,1,0), 0x00FF00],
[new THREE.Vector3(0,0,1), 0x0000FF],
]
var size = 200;
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(75, size / size, 0.1, 1000);
this.camera.position.set(0, 0, 2);
this.renderer = new THREE.WebGLRenderer({alpha: true});
this.renderer.setSize(size, size);
canvas.appendChild(this.renderer.domElement);
var controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
var geometry = new THREE.SphereGeometry( .1, 32, 32 );
var material = new THREE.MeshBasicMaterial( {color: 0xffffff} );
var sphere = new THREE.Mesh( geometry, material );
this.scene.add( sphere );
this.group = new THREE.Group();
for(var pos of this.ref) {
var geometry = new THREE.BoxGeometry(.25,.25,.25);
var material = new THREE.MeshBasicMaterial({
color: pos[1]
});
var cube = new THREE.Mesh(geometry, material);
cube.position.copy(pos[0]);
this.group.add(cube);
}
this.scene.add(this.group);
}
setCameraRotation(rotation) {
this.group.setRotationFromMatrix(rotation);
}
update() {
this.renderer.render(this.scene, this.camera);
}
}
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
camera.position.set(0, 3, 3);
controls.update();
//controls.autoRotate = true;
var size = 10;
var divisions = 10;
var gridHelper = new THREE.GridHelper(size, divisions);
scene.add(gridHelper);
var axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// material
var material = new THREE.MeshBasicMaterial({
color: 0xffffff,
vertexColors: THREE.FaceColors
});
var geometry = new THREE.BoxGeometry();
// colors
red = new THREE.Color(1, 0, 0);
green = new THREE.Color(0, 1, 0);
blue = new THREE.Color(0, 0, 1);
var colors = [red, green, blue];
for (var i = 0; i < 3; i++) {
geometry.faces[4 * i].color = colors[i];
geometry.faces[4 * i + 1].color = colors[i];
geometry.faces[4 * i + 2].color = colors[i];
geometry.faces[4 * i + 3].color = colors[i];
}
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Orientation
var orientationHelper = new OrientationHelper(document.getElementById("orientation-helper"));
function animate() {
requestAnimationFrame(animate);
controls.update();
let rotMat = new THREE.Matrix4().makeRotationFromEuler(camera.rotation);
let invRotMat = new THREE.Matrix4().getInverse(rotMat);
orientationHelper.setCameraRotation(invRotMat);
orientationHelper.update();
renderer.render(scene, camera);
}
animate();
body { margin: 0; }
canvas { display: block; }
#orientation-helper { position: absolute; top: 10px; left: 10px; background: #505050; }
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/examples/js/controls/OrbitControls.js"></script>
<div id='orientation-helper'></div>
我正在尝试使用三个 JS 制作一个看起来像这样的 blender-esk 方向视图:
我的计划是采取相机旋转并旋转3个矢量点(代表图片中的X,Y和Z气泡)。然后,一旦我有了这些点,我就可以使用 X 和 Y 坐标在 canvas 上画圆,并画线将它们连接到中心。然后我可以使用 Z 方向来确定应该在什么之上绘制什么。
目前我正在使用第二个 three.js 场景来可视化这些 X、Y 和 Z 点的位置,因为我尝试了不同的方式来旋转顶点组以使其与相机的方向相匹配。我在这部分苦苦挣扎,我尝试了很多没有用的东西。
这是我目前所在位置的 JS Fiddle:
https://jsfiddle.net/j9mcL0x4/4/ (不在 Brave 中加载,但在 Chrome 中工作)
当你左右摇摄相机时,它会移动第二个场景中的 3 个立方体,但我无法让它正确旋转。
X、Y 和 Z 点由一组 Vector3 表示:
this.ref = [
[new THREE.Vector3(1,0,0), 0xFF0000],
[new THREE.Vector3(0,1,0), 0x00FF00],
[new THREE.Vector3(0,0,1), 0x0000FF],
]
然后我创建每个多维数据集并将其添加到一个组中:
this.group = new THREE.Group();
for(var pos of this.ref) {
var geometry = new THREE.BoxGeometry(.25,.25,.25);
var material = new THREE.MeshBasicMaterial({
color: pos[1]
});
var cube = new THREE.Mesh(geometry, material);
cube.position.copy(pos[0]);
this.group.add(cube);
}
this.scene.add(this.group);
然后在我的动画函数中,我尝试计算组的旋转以使其与主视图处于相同的方向:
var quaternion = new THREE.Quaternion();
camera.getWorldQuaternion( quaternion );
let rotation = new THREE.Euler();
rotation.setFromQuaternion(quaternion);
var dir = new THREE.Vector3();
dir.subVectors( camera.position, controls.target ).normalize();
orientationHelper.group.rotation.set(dir.x, dir.y, dir.z);
orientationHelper.animate();
我所拥有的是完全错误的,但这里是我尝试过的一些东西:
- 计算相机前面的一个点,然后使用 lookAt 函数使用它让小组朝那个方向看
- 我正在使用轨道控制,它有一个相机聚焦的目标。我已经尝试减去相机位置向量和目标向量以获得外观方向但是这不起作用(当前在 jsfiddle 中的内容)
- 我试过只使用相机局部旋转(并尝试否定它)
备注 我可以在第二个场景中旋转相机以匹配主视图中的相机,但我真的想旋转矢量本身。这样我就可以将这些点投影到基本的 canvas 上以绘制 6 个圆和 3 条线。我觉得这比尝试在 3d 中使用精灵要容易得多,而且三个 JS 不能在不为其创建矩形网格的情况下轻松绘制粗线。
以下是我希望输出的一些示例:
更新
这个问题已由 Rabbid76 解决,如果有人有兴趣在他们的项目中使用 Blender 风格的方位立方体,您可以在此处找到完整的源代码:
https://github.com/jrj2211/three-orientation-gizmo/
或者用npm下载:
首先在视图space中,X轴指向右侧,Y轴指向上方,Z轴指向外canvas.
因此,您必须为正 Z 轴上的 OrientationHelper
相机选择一个初始位置:
class OrientationHelper {
constructor(canvas) {
// [...]
this.camera = new THREE.PerspectiveCamera(75, size / size, 0.1, 1000);
this.camera.position.set(0, 0, 2);
// [...]
下面我推荐在OrientationHelper
场景中通过矩阵设置组的方向:
class OrientationHelper {
// [...]
setCameraRotation(rotation) {
this.group.setRotationFromMatrix(rotation);
}
// [...]
视图矩阵是该矩阵的逆矩阵,它定义了相机的位置和方向。您想要可视化相机的方向。您想可视化视图矩阵的方向。
从 camera.rotation
创建一个旋转矩阵。计算 Inverse matrix 并通过计算矩阵设置 OrientationHelper
的方向:
let rotMat = new THREE.Matrix4().makeRotationFromEuler(camera.rotation);
let invRotMat = new THREE.Matrix4().getInverse(rotMat);
orientationHelper.setCameraRotation(invRotMat);
orientationHelper.update();
看例子:
class OrientationHelper {
constructor(canvas) {
this.canvas = canvas;
this.ref = [
[new THREE.Vector3(1,0,0), 0xFF0000],
[new THREE.Vector3(0,1,0), 0x00FF00],
[new THREE.Vector3(0,0,1), 0x0000FF],
]
var size = 200;
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(75, size / size, 0.1, 1000);
this.camera.position.set(0, 0, 2);
this.renderer = new THREE.WebGLRenderer({alpha: true});
this.renderer.setSize(size, size);
canvas.appendChild(this.renderer.domElement);
var controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
var geometry = new THREE.SphereGeometry( .1, 32, 32 );
var material = new THREE.MeshBasicMaterial( {color: 0xffffff} );
var sphere = new THREE.Mesh( geometry, material );
this.scene.add( sphere );
this.group = new THREE.Group();
for(var pos of this.ref) {
var geometry = new THREE.BoxGeometry(.25,.25,.25);
var material = new THREE.MeshBasicMaterial({
color: pos[1]
});
var cube = new THREE.Mesh(geometry, material);
cube.position.copy(pos[0]);
this.group.add(cube);
}
this.scene.add(this.group);
}
setCameraRotation(rotation) {
this.group.setRotationFromMatrix(rotation);
}
update() {
this.renderer.render(this.scene, this.camera);
}
}
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
camera.position.set(0, 3, 3);
controls.update();
//controls.autoRotate = true;
var size = 10;
var divisions = 10;
var gridHelper = new THREE.GridHelper(size, divisions);
scene.add(gridHelper);
var axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// material
var material = new THREE.MeshBasicMaterial({
color: 0xffffff,
vertexColors: THREE.FaceColors
});
var geometry = new THREE.BoxGeometry();
// colors
red = new THREE.Color(1, 0, 0);
green = new THREE.Color(0, 1, 0);
blue = new THREE.Color(0, 0, 1);
var colors = [red, green, blue];
for (var i = 0; i < 3; i++) {
geometry.faces[4 * i].color = colors[i];
geometry.faces[4 * i + 1].color = colors[i];
geometry.faces[4 * i + 2].color = colors[i];
geometry.faces[4 * i + 3].color = colors[i];
}
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Orientation
var orientationHelper = new OrientationHelper(document.getElementById("orientation-helper"));
function animate() {
requestAnimationFrame(animate);
controls.update();
let rotMat = new THREE.Matrix4().makeRotationFromEuler(camera.rotation);
let invRotMat = new THREE.Matrix4().getInverse(rotMat);
orientationHelper.setCameraRotation(invRotMat);
orientationHelper.update();
renderer.render(scene, camera);
}
animate();
body { margin: 0; }
canvas { display: block; }
#orientation-helper { position: absolute; top: 10px; left: 10px; background: #505050; }
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/examples/js/controls/OrbitControls.js"></script>
<div id='orientation-helper'></div>