【问题标题】:Attaching position to camera but rotating in world axis将位置附加到相机但在世界轴上旋转
【发布时间】:2018-03-22 07:40:10
【问题描述】:

快速摘要:我不知道如何为连接到相机的对象提供局部旋转,以便它像连接到场景一样旋转。

背景:我是this website 的创建者,它为相关游戏的玩家提供了在网络浏览器中在 3D Builder 上构建关卡的能力。一切正常,但有些部分没有得到很好的优化,特别是工具栏(或仪表板),可以选择对象添加到主场景中。

这些工具栏对象需要粘贴在屏幕底部并始终位于所有图层之上,但它们的旋转必须相对于场景的主轴。这就是我在 Firefox 和 Chrome 以外的浏览器上遇到一些奇怪行为的地方。

如果首先想到 this other thread 通过实现 Object3D.onBeforeRender 函数在这件事上挽救了我的生命,但我遇到了其他问题。

目前,这些对象附加到场景,并且它们的位置相对于相机更新,每个对象的 onBeforeRender 函数。在这种方式下,我注意到 Edge 和 iPhone 浏览器的一些闪烁结果,尽管在渲染中一切都很好。场景旋转不好...

所以我尝试了其他方法,方法是将每个对象附加到相机并赋予它们假定的世界旋转。现在在 Edge 上测试时没有闪烁,结果要好得多,但我不知道如何为它们提供与附加到场景时相同的旋转。

这是一个视觉效果:

还有一个 gif 动画(你可以看到右侧部分的红色背景和立方体是如何移动/闪烁的,但如果做得快一点会很糟糕):

#1(右侧)的渲染效果不错,但在某些浏览器上体验不佳,而 #2(左侧)基于摄像头的旋转效果不佳,但体验还不错。

以下是我实现的一些代码摘要:

  • 对于#1:
rightCube.relPos = new THREE.Vector3(500, 0, 0); // a new property to be used
rightCube.onBeforeRender = function( renderer, scene, camera, geometry, material, group ) {
    camReference.position.copy(this.relPos);
    var pos = camReference.getWorldPosition();
    this.position.set( pos.x, pos.y, pos.z );
};
scene.add(rightCube);

camReference 是一个简单的 Object3D 表示相机原点

  • 对于 #2:
leftCube.onBeforeRender = function( renderer, scene, camera, geometry, material, group ) {
    this.rotation.copy(camera.getWorldRotation());
};
camera.add(leftCube);

我承认在最后一部分,让相机世界旋转是不够的,但这就是我卡住并需要一些帮助的地方:我不知道 如何给一个连接到相机的对象, 局部旋转,使其像附加到场景一样旋转

这篇文章很长,但我希望我的问题能得到很好的理解......并且有人会给我让它工作的钥匙。

三.js r82

【问题讨论】:

  • 看看this SO answer是否有帮助。
  • @WestLangley 感谢回答。实际上,您链接中提到的 jsfiddle 是我部分用于实现此演示的第二个场景(“黄色”功能区)的那个。在this link 上,这是一张图片,其中红丝带,目前是主要场景的一部分,与正确的对象不在同一个场景中,而是跟随它,因为两者都使用相对位置进行了更新。左边的物体真的完全不动,完全粘在相机上。但只有他们的轮换是不行的。我有点急于只为左侧对象找到正确的旋转...

标签: javascript three.js


【解决方案1】:

我已经找到了解决这个问题的方法。我不得不进行一些微积分,我很惊讶它还没有在 Three.js 中实现。如果我错过了@WestLangley,请告诉我!

基本上我的要求是从相机坐标中获得rotateToWorld 功能。由于轨道控制位置偏移可能与场景轴不同,因此获得相机的旋转是不够的。从相机坐标来看,旋转到 World 可以看作是围绕 x 然后 y 旋转(欧拉旋转),z 指向观众。这是我试图绘制的一个图作为更好的解释:

这是我为此编写的函数:

var rotateToWorld = function (camera, controls) {
    var p = camera.position.clone();
    var o = controls.target.clone();

    // position relative to the control
    p.sub(o);

    var Dxyz = Math.sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
    var Dxz = Math.sqrt(p.x*p.x + p.z*p.z);

    return {
        x: Math.acos(Dxz/Dxyz) * (p.y>0?1:-1), // Angle Rotation on x axis camera
        y: Math.acos(p.z/Dxz) * (p.x>0?-1:1), // Angle Rotation on y axis camera
        z: 0 // No rotation around z axis
    };
};

然后从cube 对象附加到相机(不是场景)可以这样渲染:

cube.onBeforeRender = function( renderer, scene, camera, geometry, material, group ) {
    var R = rotateToWorld(camera, controls); // controls defined elsewhere in the code
    this.rotation.set(R.x, R.y, 0);
};

这就是我使用透视相机得到的结果:

现在它可以与 Microsoft Edge、Safari 和其他浏览器一起使用,尽管在附加到场景并更新对象的位置(以使其保持在相机前面)时,它仅适用于 Firefox 和 Chrome(就今天而言) )。

我现在想知道这是否是可以添加到 Three.js 中的功能...


编辑:

@WestLangley在cmets中指出Vector3clone()函数每次调用都会实例化一个新对象,所以最好使用闭包函数将po初始化一次为@987654333 @ 对象然后使用 copy() 函数更新它们。

所以这里有一个更好的版本:

var rotateToWorld = function() {
    var p = new THREE.Vector3();
    var o = new THREE.Vector3();
    return function rotateToWorld(camera, controls) {
        p.copy(camera.position);
        o.copy(controls.target);

        // position relative to the control
        p.sub(o);

        var Dxyz = Math.sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
        var Dxz = Math.sqrt(p.x*p.x + p.z*p.z);

        return {
            x: Math.acos(Dxz/Dxyz) * (p.y>0?1:-1), // Angle Rotation on X axis camera
            y: Math.acos(p.z/Dxz) * (p.x>0?-1:1), // Angle Rotation on Y axis camera
            z: 0 // No rotation around z axis
        };
    }
}();

再次感谢@WestLangley! :)

【讨论】:

  • 提示:了解如何使用闭包,这样您就不会在每次调用时都实例化新的Vector3s。或者完全不使用Vector3s 来编写你的方法。
  • 感谢@WestLangley 指出。现在我明白了为什么 Three.js 代码中有这么多闭包;)在这种情况下,我宁愿将 Vector3 对象的 clone() 函数用于 po 并从头开始定义生成的旋转参数,因为不需要真正的变量初始化。我将自行更新答案。的确,这是一个很棒的提示!
  • clone() 呼叫new。也不要使用clone()
  • 哦,那是真的......好吧,我将对其进行一些修改(因为这更直接作为解释)然后将添加一个带有闭包的更新作为增强。谢谢。
猜你喜欢
  • 2017-10-26
  • 1970-01-01
  • 1970-01-01
  • 2019-10-18
  • 1970-01-01
  • 1970-01-01
  • 2019-09-24
  • 1970-01-01
  • 2017-10-26
相关资源
最近更新 更多