将位置附加到相机但在世界轴上旋转

时间:2018-03-12 00:12:57

标签: javascript three.js

快速抽象:我不知道如何将附加到相机的对象赋予局部旋转,使其旋转,就好像它附着在场景中一样。

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

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

如果首先想到this other thread通过实施Object3D.onBeforeRender功能来挽救我的生命,但我遇到了其他问题。

目前,这些对象附加到场景,并且它们的位置相对于相机更新,并且每个对象的onBeforeRender功能。通过这种方式,我注意到Edge和iPhone浏览器出现了一些闪烁的结果,尽管渲染中的一切都很好。现场轮换不好......

所以我通过将每个物体附加到相机并给予它们所谓的世界旋转来尝试其他的东西。现在在边缘测试时没有闪烁,结果好多了,但我不知道如何给它们提供与它们连接到场景时相同的旋转。

这是一个视觉效果:

Visual situation

和一个GIF动画(你可以看到右边部分的红色背景和立方体是如何移动/闪烁的,但如果更快地完成它会很糟糕):

Animation

对于#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);

我承认在最后一部分,让相机世界旋转是不够的,但这就是我被困住的地方,需要一些帮助:我不知道如何给一个物体,附在相机上,局部旋转,使其旋转,就好像它附着在场景上一样

这篇文章很长,但我希望我的问题能够得到很好的理解......并且有人会给我一些关键的工作。

Three.js r82

1 个答案:

答案 0 :(得分:0)

我已经找到了如何处理这个问题。我不得不进入一些微积分,我很惊讶它还没有在Three.js中实现。如果我遗漏了@WestLangley的内容,请告诉我!

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

rotateToWorld

这是我编写的功能:

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);
};

因此,这是我用透视相机得到的:

rotateToWorld

现在它适用于Microsoft Edge,Safari和其他浏览器,尽管它附加到场景并更新对象的位置(将其保持在相机前)它只适用于Firefox和Chrome(至于今天) )。

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

编辑:

@WestLangley在评论中指出clone()函数Vector3每次调用时都会实例化一个新对象,所以最好使用一个闭包函数来初始化po作为Vector3个对象,然后使用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! :)