在 Three.js 中复制旋转父对象内的对象旋转
Replicate object rotation inside rotated parent in Three.js
我构建了我的 3D 地球仪并将其放入父边界框/枢轴,如下所示:
var globe = new THREE.Group();
if (earthmesh) {globe.add(earthmesh);};
if (linesmesh) {globe.add(linesmesh);};
if (cloudmesh) {globe.add(cloudmesh);};
if (atmosmesh) {globe.add(atmosmesh);};
pivot = new THREE.Group();
if (globe) {pivot.add(globe);};
if (pivot) {scene.add(pivot);};
因此,例如,在父对象上绕 Z(远到近)轴旋转 23 度时:
pivot.rotation.set(THREE.Math.degToRad(0), THREE.Math.degToRad(0), THREE.Math.degToRad(23));
在动画函数中,地球将相对于其父项围绕 Y(从下到上)轴旋转(如果您想知道,v
只是一个保存 [=16 值的对象=]即360度,.rate
即旋转速度,还有.roll
、.spin
、.tilt
变量分别对应球体的X、Y、Z旋转,以度为单位):
function animate()
{
delta = clock.getDelta();
resize();
v.spin = (v.loop + v.spin + v.rate * delta) % v.loop;
globe.rotation.set(THREE.Math.degToRad(v.roll), THREE.Math.degToRad(v.spin), THREE.Math.degToRad(v.tilt));
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
就像下面的绿色箭头指示的那样,而不是红色箭头指示地球是否没有旋转父对象的方式:
这很简单,而且效果很好,如果我这样做:
pivot.rotation.set(THREE.Math.degToRad(v.roll), THREE.Math.degToRad(0), THREE.Math.degToRad(v.tilt));
globe.rotation.set(THREE.Math.degToRad(0), THREE.Math.degToRad(v.spin), THREE.Math.degToRad(0));
在上面的动画功能和我的按需/手动旋转系统中,没有改变相机位置/方向,因为这是由 Three.js 的 ArcballControls 库按需要处理的,也在上面可见。
但是,我想通过使用 Three.js 中可用的其他工具(如矩阵、向量、四元数或其他内置函数)在其父对象内部实现此对象旋转,为地球设置父级并在父级和子级之间分配旋转。这个想法是像上面的原始动画功能一样正常地进行地球旋转,并应用一些其他工具(甚至公式)来改变旋转并产生所需的效果。我该怎么做?
为了清楚起见,这种方法相对于为地球创建父级的好处是:
- 我可以在
if (...) {...}
条件下轻松地在“正常”(红色箭头)和“改变的”(绿色箭头)旋转系统之间切换,而无需销毁、重新创建或重置父级- 子结构
- 我将能够为地球和改变方法自由地使用围绕所有 3 个轴的旋转,而不是在父级上应用一些旋转,在子级上应用一些旋转
此外,如果其他方法太复杂,以防万一我最终选择上面的父子方法,我将如何将旋转系统“重置”为“原始”(即红色箭头)方式在那种情况下,不改变对象的视觉方向?我的意思是,将 pivot
旋转重置为 (0, 0, 0)
很清楚,但是应用于地球子项的旋转是什么,以便即使其父项现在未旋转,它也保持不变?
注意:为简单起见,假定父组/子组/对象都位于 (0, 0, 0) 位置,并且父旋转在单个图上说明轴,但理想情况下,替代方案应该允许对枢轴和对象进行不同的假设定位,而地球仪改变旋转应该可以在所有 3 个轴上进行。
P.S. 随时提出改进问题的建议,以使其更清晰或更紧凑(抱歉,我不是专家在技术术语中,如世界或局部旋转等),但在你完全确定之前不要急于将其标记为重复或关闭它。
你的问题很长,但我认为你要找的是“轮换顺序”。旋转通常应用于 x,然后是 y,最后是 z 轴。
您可能希望将地球的倾斜度 (z) 放在第一位,然后将日自转 (y) 放在最后,因此您可以更改为:globe.rotation.order = "ZXY"
我构建了我的 3D 地球仪并将其放入父边界框/枢轴,如下所示:
var globe = new THREE.Group();
if (earthmesh) {globe.add(earthmesh);};
if (linesmesh) {globe.add(linesmesh);};
if (cloudmesh) {globe.add(cloudmesh);};
if (atmosmesh) {globe.add(atmosmesh);};
pivot = new THREE.Group();
if (globe) {pivot.add(globe);};
if (pivot) {scene.add(pivot);};
因此,例如,在父对象上绕 Z(远到近)轴旋转 23 度时:
pivot.rotation.set(THREE.Math.degToRad(0), THREE.Math.degToRad(0), THREE.Math.degToRad(23));
在动画函数中,地球将相对于其父项围绕 Y(从下到上)轴旋转(如果您想知道,v
只是一个保存 [=16 值的对象=]即360度,.rate
即旋转速度,还有.roll
、.spin
、.tilt
变量分别对应球体的X、Y、Z旋转,以度为单位):
function animate()
{
delta = clock.getDelta();
resize();
v.spin = (v.loop + v.spin + v.rate * delta) % v.loop;
globe.rotation.set(THREE.Math.degToRad(v.roll), THREE.Math.degToRad(v.spin), THREE.Math.degToRad(v.tilt));
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
就像下面的绿色箭头指示的那样,而不是红色箭头指示地球是否没有旋转父对象的方式:
这很简单,而且效果很好,如果我这样做:
pivot.rotation.set(THREE.Math.degToRad(v.roll), THREE.Math.degToRad(0), THREE.Math.degToRad(v.tilt));
globe.rotation.set(THREE.Math.degToRad(0), THREE.Math.degToRad(v.spin), THREE.Math.degToRad(0));
在上面的动画功能和我的按需/手动旋转系统中,没有改变相机位置/方向,因为这是由 Three.js 的 ArcballControls 库按需要处理的,也在上面可见。
但是,我想通过使用 Three.js 中可用的其他工具(如矩阵、向量、四元数或其他内置函数)在其父对象内部实现此对象旋转,为地球设置父级并在父级和子级之间分配旋转。这个想法是像上面的原始动画功能一样正常地进行地球旋转,并应用一些其他工具(甚至公式)来改变旋转并产生所需的效果。我该怎么做?
为了清楚起见,这种方法相对于为地球创建父级的好处是:
- 我可以在
if (...) {...}
条件下轻松地在“正常”(红色箭头)和“改变的”(绿色箭头)旋转系统之间切换,而无需销毁、重新创建或重置父级- 子结构 - 我将能够为地球和改变方法自由地使用围绕所有 3 个轴的旋转,而不是在父级上应用一些旋转,在子级上应用一些旋转
此外,如果其他方法太复杂,以防万一我最终选择上面的父子方法,我将如何将旋转系统“重置”为“原始”(即红色箭头)方式在那种情况下,不改变对象的视觉方向?我的意思是,将 pivot
旋转重置为 (0, 0, 0)
很清楚,但是应用于地球子项的旋转是什么,以便即使其父项现在未旋转,它也保持不变?
注意:为简单起见,假定父组/子组/对象都位于 (0, 0, 0) 位置,并且父旋转在单个图上说明轴,但理想情况下,替代方案应该允许对枢轴和对象进行不同的假设定位,而地球仪改变旋转应该可以在所有 3 个轴上进行。
P.S. 随时提出改进问题的建议,以使其更清晰或更紧凑(抱歉,我不是专家在技术术语中,如世界或局部旋转等),但在你完全确定之前不要急于将其标记为重复或关闭它。
你的问题很长,但我认为你要找的是“轮换顺序”。旋转通常应用于 x,然后是 y,最后是 z 轴。
您可能希望将地球的倾斜度 (z) 放在第一位,然后将日自转 (y) 放在最后,因此您可以更改为:globe.rotation.order = "ZXY"