它有什么问题 - 或者如何找到正确的 THREE.PerspectiveCamera 设置

what's wrong with it - or how to find correct THREE.PerspectiveCamera settings

我有一个简单的 THREE.Scene,其中主要内容是一个 THREE.Line 网格,可视化基于关键帧的路径,相机将遵循该路径进行一些脚本动画。然后有一个基于 THREE.SphereGeometry 的网格,它总是重新定位到当前相机位置。

当前错误的结果如下所示(分形背景独立渲染但使用相同的关键帧输入 - 最终的想法是 "camera path" 可视化结果与 scale/projection 相同各自的分形背景...):

base是一个关键帧数组,每个关键帧代表一个特定相机的modelViewMatrixposition/orientation,直接用于驱动背景的vertexshader,例如:

  varying vec3 eye, dir;
  void main()   {
    gl_Position = vec4(position, 1.0);
    eye = vec3(modelViewMatrix[3]);
    dir = vec3(modelViewMatrix * vec4(position.x , position.y , 1, 0));
  }

(据我了解,"eye" 基本上是相机位置,而 "dir" 反映了相机的方向,顺便说一句,它在光线行进期间使用,隐含地导致透视投影)

各个网格对象是这样创建的:

visualizeCameraPath: function(scene) {
        // debug: visualize the camera path
        var n= this.getNumberOfKeyFrames();

        var material = new THREE.LineBasicMaterial({
            color: 0xffffff
        });

        var geometry = new THREE.Geometry();
        for (var i= 0; i<n; i++) {
            var m= this.getKeyFrameMatrix(true, i);

            var pos= new THREE.Vector3();
            var q= new THREE.Quaternion();
            var scale= new THREE.Vector3();
            m.decompose(pos,q,scale);

            geometry.vertices.push( new THREE.Vector3( pos.x, pos.y, pos.z ));          
        }

        this.camPath = new THREE.Line( geometry, material );
        this.camPath.frustumCulled = false; // Avoid getting clipped - does not seem to help one little bit
        scene.add( this.camPath );


        var radius= 0.04;
        var g = new THREE.SphereGeometry(radius, 10, 10, 0, Math.PI * 2, 0, Math.PI * 2);

        this.marker = new THREE.Mesh(g, new THREE.MeshNormalMaterial());
        scene.add(this.marker);
    }

为了播放动画,我像这样更新相机和标记位置(我想我直接在 "shadowCamera" 上使用输入矩阵 "m" 的方式已经是错误的 - 尽管我认为它包含正确的位置):

syncShadowCamera(m) {
    var pos= new THREE.Vector3();
    var q= new THREE.Quaternion();
    var scale= new THREE.Vector3();
    m.decompose(pos,q,scale);

    this.applyMatrix(m, this.shadowCamera);     // also sets camera position to "pos"


    // highlight current camera-position on the camera-path-line        
    if (this.marker != null) this.marker.position.set(pos.x, pos.y, pos.z);

},

applyMatrix: function(m, targetObj3d) {
    var pos= new THREE.Vector3();
    var q= new THREE.Quaternion();
    var scale= new THREE.Vector3();
    m.decompose(pos,q,scale);

    targetObj3d.position.set(pos.x, pos.y, pos.z);
    targetObj3d.quaternion.set(q.x, q.y, q.z, q.w);
    targetObj3d.scale= scale;

    targetObj3d.updateMatrix(); // this.matrix.compose( this.position, this.quaternion, this.scale );   
    targetObj3d.updateMatrixWorld(true);
},

我已经尝试了很多关于相机的事情,屏幕截图反映了禁用 "this.projectionMatrix" 的输出(见下面的代码)。

createShadowCamera: function() {        
    var speed = 0.00039507;
    var z_near = Math.abs(speed);
    var z_far = speed * 65535.0;
    var fH = Math.tan( this.FOV_Y * Math.PI / 360.0 ) * z_near;
    var fW = Math.tan( this.FOV_X * Math.PI / 360.0 ) * z_near;
    // orig opengl used: glFrustum(-fW, fW, -fH, fH, z_near, z_far);

    var camera= new THREE.PerspectiveCamera();          
    camera.updateProjectionMatrix =  function() {
    //  this.projectionMatrix.makePerspective( -fW, fW, fH, -fH, z_near, z_far );
        this.projectionMatrix= new THREE.Matrix4();     // hack: fallback to no projection
    };
    camera.updateProjectionMatrix();
    return camera;
},

我最初的尝试是使用与分形背景的 opengl 着色器使用的相同类型的设置(参见上面的 glFrustum)。不幸的是,我似乎还没有成功地将输入"modelViewMatrix"(以及由着色器中的光线行进隐式执行的投影)正确映射到等效的THREE.PerspectiveCamera设置(orientation/projectionMatrix)。

这里有没有矩阵计算专家,知道如何获得正确的变换?

我终于找到了一种行之有效的技巧。

实际上问题由两部分组成:

1) modelViewMatrix 的行优先顺序与列优先顺序:顶点着色器预期的顺序与其余 THREE.js 预期的顺序相反..

2) Object3D 层次结构:即场景、网格、几何、线顶点 + 相机:放置 modelViewMatrix 数据的位置,以便它创建所需的结果(即与旧的该死的 opengl 应用程序产生的相同结果):我对我在这里发现的 hack 不满意 - 但到目前为止它是唯一一个似乎有效的:

  • 我没有碰相机..它停留在 0/0/0
  • 我直接移动我的 "line"-Geometry 相对于真实相机位置的所有顶点(参见 modelViewMatrix 中的 "position")
  • 然后我在包含我的 "line" 几何体的网格上禁用 "matrixAutoUpdate" 并将 modelViewMatrix(我首先将 "position" 置零)复制到 "matrix"场.

BINGO.. 然后就可以了。 (我通过 rotating/displacing 相机或 displacing/rotating 涉及的任何 Object3D 实现相同结果的所有尝试都惨遭失败..)

编辑:我找到了一种比更新顶点更好的方法,并且至少将所有操作都保持在网格级别(我仍在移动世界 - 就像旧的 OpenGL 应用程序所做的那样......)。要获得 translation/rotation 的正确顺序,还可以使用("m" 仍然是原始的 OpenGL modelViewMatrix - 具有 0/0/0 位置信息):

var t= new THREE.Matrix4().makeTranslation(-cameraPos.x, -cameraPos.y, -cameraPos.z);
t.premultiply ( m );

obj3d.matrixAutoUpdate=false;
obj3d.matrix.copy(t);

如果有人知道更好的方法(无需直接操作对象矩阵即可更新相机),我当然有兴趣听听。