ThreeJS:获取对象位置向量而不进行旋转

时间:2017-09-03 22:22:34

标签: three.js

所以,我正盯着自己对这个问题视而不见,解决方案可能很容易。我只是看不到它。

tl; dr:我需要知道我的Object3D实例移动到哪个轴上,完全忽略了方向。

// Init code.
let last_position = new THREE.Vector3(0, 0, 0);

// Update code (called every frame)
if (object.position.distanceTo(last_position) > 0) {
    // The object has moved.
    let delta = object.position.clone().sub(last_position);

    // ... what do I do now?
    // - The object can rotate around its Y-axis. (looking around)
    // - I'm trying to "remove" the rotation from the delta vector.

    // Desired result:
    if (delta.z > 0) // Object moved forward!
    if (delta.z < 0) // Object moved backward!
    if (delta.x > 0) // Object moved right
    if (delta.x < 0) // Object moved left
}
last_position = object.position.clone();

基本上,我所要做的就是从delta矢量中有效地“移除”旋转。它基本上是Object3D.translateX / Y / Z函数的工作原理,但我没有更新对象,而是试图读取这些值。

提前致谢!

2 个答案:

答案 0 :(得分:1)

您需要将delta矢量的基础从世界空间更改为对象空间(局部空间)。

每次更新场景图时计算的THREE.Object3D.matrixWorld表示从对象空间到世界空间的转换。

要获得从世界空间到对象空间的转换,您需要invert the matrix

在你的情况下,我们只对旋转/缩放感兴趣,它是matrixWorld的左上角3x3矩阵。

所以我会一步一步地做这样的事情:

// compute delta ...

// transform delta in local space
var localToWorld = obj.matrixWorld;
var localToWorldRot = new THREE.Matrix3().setFromMatrix4(localToWorld);
var invLocalToWorldRot = new THREE.Matrix3().getInverse(localToWorldRot);
delta.applyMatrix3(invLocalToWorldRot);

检查this fiddle。 (使用WASDQE键)

如果您的想法是用它来检查玩家如何在网络游戏中移动以便您可以播放相应的动画,那么我会说这是错误的做法,原因如下:

  • 这是计算密集型的
  • 这不依赖于基于播放器的显式操作(您可能最终会随机扫描字符,因为某些数据包丢失或延迟)

相反,您应该考虑发送操作码进行扫描/旋转,并使用某种运动预测,以便客户端可以看到单位平稳移动。

您可能需要read this

答案 1 :(得分:0)

我打赌你要找的是THREE.Object3D.getWorldPosition

此函数将为您提供对象的世界位置,无论其旋转方式如何,以及其父对象的旋转。

我可以想到几种方法,其中之一就是:

  • 使用scene.autoUpdate = false
  • 禁用自动场景图更新
  • 在渲染循环中:
    1. 更新对象的位置
    2. 使用scene.updateMatrixWorld()
    3. 更新场景图
    4. 使用以下功能
    5. 计算增量位置
    6. 使用delta
    7. 执行某些操作

以下是computeDelta的代码:

function computeDelta(obj) {
    if (!obj.userData.lastPosition) {
        obj.userData.lastPosition = new THREE.Vector3();
        obj.getWorldPosition(obj.userData.lastPosition);
    }
    if (!obj.userData.delta) {
        obj.userData.delta = new THREE.Vector3();
    }
    obj.userData.delta.copy(obj.userData.lastPosition);
    obj.getWorldPosition(obj.userData.lastPosition);
    return obj.userData.delta.sub(obj.userData.lastPosition).negate();
}

请注意,每个对象的计算都保存在userData中。每帧调用THREE.Vector3.clone()是一件坏事,因为它会创建一个新的向量。

检查this fiddle

当您必须计算多个对象的增量时,此功能并不是很方便。在这种情况下,计算obj.onBeforeRender中的增量更合适。