0

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

当前错误的结果看起来像这样(分形背景是独立渲染的,但使用相同的关键帧输入 - 最终的想法是“相机路径”可视化最终以与相应分形背景相同的比例/投影结束......) : 可视化相机路径

base 是一个关键帧数组,每个关键帧代表特定相机位置/方向的模型视图矩阵,并直接用于驱动背景的顶点着色器,例如:

  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 设置(方向/投影矩阵)。

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

4

1 回答 1

0

最后,我找到了一种可行的方法。

在此处输入图像描述 实际上,问题由两部分组成:

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

2)Object3D-hierarchy:即场景,网格,几何,线顶点+相机:将modelViewMatrix数据放在哪里,以便它创建所需的结果(即与旧的血腥opengl应用程序产生的结果相同):我不满意我在这里找到的 hack - 但到目前为止,它似乎是唯一可行的:

  • 我不碰相机..它停留在 0/0/0
  • 我直接移动我的“线”的所有顶点 - 几何相对于真实相机位置(参见modelViewMatrix中的“位置”)
  • 然后我在包含我的“线”几何的网格上禁用“matrixAutoUpdate”,并将modelViewMatrix(我首先将“位置”归零)复制到“矩阵”字段中。

BINGO .. 然后它的工作原理。(我通过旋转/移动相机或移动/旋转任何涉及的 Object3D 来获得相同结果的所有尝试都失败了......)

编辑:我找到了一种比更新顶点更好的方法,并且至少将所有操作保持在网格级别(我仍在移动世界 - 就像旧的 OpenGL 应用程序所做的那样......)。为了获得正确的平移/旋转顺序,还可以使用(“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);

如果有人知道一种更好的方法(在无需直接操作对象矩阵的情况下更新相机的方法),我当然很想听听。

于 2017-03-13T03:24:09.283 回答