如何以编程方式撤消到枢轴点的位置转换?

Posted

技术标签:

【中文标题】如何以编程方式撤消到枢轴点的位置转换?【英文标题】:How to programmatically undo positional translation to pivot point? 【发布时间】:2019-05-29 17:35:07 【问题描述】:

我认为这最终是一个非常简单的问题,但很难描述,因此,我提供了一个工作示例here (在示例中按“z”查看不需要的平移和“x”键旋转带有补偿的重新定位)。

基本上,我试图围绕通过 gltf 加载的复杂模型(oculus rift 触摸控制器的模型)的 z 轴旋转对象(拇指杆)。绕 x 轴旋转很容易,因为它是 90 度。与 x 轴正交。关于 z 轴,它更难,因为拇指杆所连接的平面呈 30 度角。我意识到如果拇指杆使用本地坐标,这不会是一个问题,但“thumb.rotation.z”似乎没有使用本地坐标并且围绕模型(作为一个整体)旋转,甚至可能场景的全局 y 和 z (?)。无论如何,经过一番折腾,我能够通过执行以下操作使事情正常进行:

// occulus plane is angle at 30 deg, which corresponds to
// 5 units forward to 3 units down.
var axis = new THREE.Vector3(0, 5, -3).normalize();
factory.thumbstick.geometry.center();
var dir = (evt.key === 'x' ? 1 : -1);
thumb.rotateOnAxis(axis, factory.ONE_DEG * 5.0 * dir);  

基本上,我围绕“倾斜”轴旋转,然后调用 'center' 使摇杆以枢轴点为中心,因此它围绕枢轴点旋转 ,而不是 围绕枢轴点(就像地球绕太阳运行一样)。

唯一的问题是,当您调用“geometry.center()”然后调用“rotateOnAxis”时,它会将拇指摇杆转换为枢轴点:

注意:摇杆对象上的位置是调用前后的 (0,0,0)。

我根据经验确定,如果我在翻译后改变拇指杆的位置,如下所示:

   // magic numbers compensating position
    var zDisp = 0.0475;
    var yDisp = zDisp / 6.0
    thumb.position.x = 0.001;
    thumb.position.y = -yDisp;
    thumb.position.z = zDisp;

然后它(几乎)回到原来的位置:

问题是这些数字只是通过交互和反复尝试重新定位拇指杆(即凭经验)确定的。我根本找不到一种编程的、分析的、api 的方式来恢复原始位置。注意:保存原始位置不起作用,因为它在翻译前后都为零。我尝试的一些事情是获取全局对象和拇指棒对象的边界球之间的差异,试图在一个距离上提出一些“sin xcos x”关系等,但没有任何效果。

我的问题是,由于调用“geometry.center()”和 rotateOnAxis(转换为枢轴点),我如何以编程方式反转偏移量,而不必求助于破解的经验“魔术”数字,这可能如果 gltf 模型发生变化,可能会发生变化。

当然,如果有人也能想出更好的方法来实现这种轮换,那就太好了。

让我感到震惊的是 gltf 模型本身的(感觉?)复杂性。这很令人困惑,因为我很难解释它并且它是各个部分:我真的不确定“中心”在哪里,在某些情况下,它与“THREE.AxesHelper”一起出现,我附上了它所显示的内容因为'y'实际上是'z',有时'up'实际上是'down'等等,它很快就会变得混乱。

任何帮助将不胜感激。

【问题讨论】:

我也觉得你想做的可能很简单。我只是不太明白你想要达到什么目的。但是,如果我正确理解一件事,那就是您希望拇指旋转类似于在您的示例中按“X”时的旋转方式?拇指是如何添加到场景中的?我认为如果将它作为子元素添加到触摸控制器而不是场景中,这将更容易实现。检查这个例子是否有意义:codepen.io/micnil/pen/VqXeVR 是的,按“x”是解决方案。并不是说我没有什么不起作用的东西——我现在可能会推送这段代码(这是框架问题github.com/aframevr/aframe/issues/3928 的一部分)。我只是想改进实施,例如不必诉诸“黑客”来重新定位它。拇指是由 oculus (facebook) 创建的 gltf 的一部分——这不是我创建的。我真的无法控制 oculus 如何定义他们的 gltf 模型——我认为这是一个附加了各种对象的场景。 换句话说,当您按下“z”并且拇指摇杆发生位移时,我如何计算运行时的位移(因此我可以随后减去它)而不是使用硬编码的经验常数,只有大约。恢复原来的位置。调用 THREE.center() 移动拇指杆,我想要像“uncenter()”这样的东西将它移回原来的位置。 p.s gltf 模型是一个三组,而不是一个场景。 看起来 WestLangley 在这个线程 ***.com/questions/28848863/… 上的回答给了我我需要的东西。如果成功,我会发布官方答案。 【参考方案1】:

我在这方面的突破是将问题重新定义为如何更改摇杆的枢轴点,而不是如何将摇杆移动到(默认和预先存在的)枢轴点。套用 JFK 的话说,“不要问你如何移动到枢轴,而要问枢轴如何移动到你”:-)

改变攻角后,我很快找到了aforementioned link,这就是我的解决方案。

我发布了更新的故障here,所以现在按 z 可以正常工作。以下是相关代码部分:

  factory.onModelLoaded = function(evt) 
    console.log(`onModelLoaded: entered`);

    factory.thumbstick = this.scene.children[1].children[2]
    let thumb = factory.thumbstick;
    // make the thumb red so it's easier to see
    thumb.material = (new THREE.MeshBasicMaterial(color: 0xFF7777));

    // use method from https://***.com/questions/28848863/threejs-how-to-rotate-around-objects-own-center-instead-of-world-center/28860849#28860849
    // to translate the pivot point of the thumbstick to the the thumbstick center
    factory.thumbParent = thumb.parent;
    let thumbParent = factory.thumbParent;
    thumbParent.remove(thumb);

    var box = new THREE.Box3().setFromObject( thumb );
    box.getCenter( thumb.position ); // this basically yields my prev. "magic numbers"
    // thumb.position.multiplyScalar( - 1 );
    var pivot = new THREE.Group();
    thumbParent.add( pivot );
    pivot.add( thumb );

    thumb.geometry.center();

    // add axeshelp after centering, otherwise the axes help, as a child of thumb,
    // will increase the bounding box of thumb, and positioning will be wrong.
    axesHelper = new THREE.AxesHelper();
    thumb.add(axesHelper);
  

这使我的“z”处理程序无需进行平移即可旋转:

  case 'z':
  case 'Z':
    var axis = new THREE.Vector3(0, 5, -3).normalize();
    var dir = (evt.key === 'z' ? 1 : -1);
    thumb.rotateOnAxis(axis, factory.ONE_DEG * 5.0 * dir);
  break;

有趣的是,调用box.getCenter() 生成的数字非常接近我的“幻数”:

box.getCenter()
Vector3 x: 0.001487499801442027, y: -0.007357006114165027, z: 0.04779449797522323

我的经验猜测是x: 0.001, y: -0.00791666666, z: 0.0475,即%error x: 32.7%, y: 7.6%, z: 0.61%,所以我非常接近,尤其是。在 z 组件上,但仍然不是 box.getCenter() 的“完美”数字。

【讨论】:

以上是关于如何以编程方式撤消到枢轴点的位置转换?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式在 CKEditor 5 的当前位置插入链接

如何以编程方式设置 UILabel 位置 iOS 7

以编程方式滚动到 Android ListView 中的特定位置

以 Android 编程方式启用 GPS(无需导航到位置设置)

您如何在中间位置实现枢轴快速排序,这种变化称为啥? [关闭]

如何以编程方式在CKEditor 5中的当前位置插入链接