что с ней не так - или как найти правильные настройки THREE.PerspectiveCamera

У меня есть простая THREE.Scene, где основным содержимым является сетка THREE.Line, которая визуализирует путь на основе ключевого кадра, по которому камера будет следовать для некоторой анимации по сценарию. Затем существует одна сетка на основе THREE.SphereGeometry, которая всегда перемещается в текущее положение камеры.

В настоящее время НЕПРАВИЛЬНЫЙ результат выглядит следующим образом (фрактальный фон визуализируется независимо, но с использованием одного и того же ввода ключевого кадра - и, в конечном итоге, идея состоит в том, что визуализация «пути камеры» заканчивается в том же масштабе/проекции, что и соответствующий фрактальный фон...) : визуализированный путь камеры

База представляет собой массив ключевых кадров, каждый из которых представляет modelViewMatrix для определенного положения/ориентации камеры и напрямую используется для управления вершинным шейдером для фона, например:

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

(насколько я понимаю, «глаз» — это в основном положение камеры, в то время как «режим» отражает ориентацию камеры, и то, как он используется во время марша луча, неявно приводит к перспективной проекции)

Соответствующие объекты сетки создаются следующим образом:

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

чтобы воспроизвести анимацию, я обновляю камеру и позицию маркера следующим образом (думаю, это уже неправильно, как я использую входную матрицу «m» непосредственно на «shadowCamera» — хотя я думаю, что она содержит правильную позицию):

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" (и проекцию, неявно выполняемую raymarching в шейдере) с эквивалентными настройками THREE.PerspectiveCamera (ориентация/projectionMatrix).

Есть ли здесь специалист по расчету матриц, который знает, как получить правильные преобразования?


person wothke    schedule 12.03.2017    source источник


Ответы (1)


Наконец-то я нашел один лайфхак, который работает.

введите здесь описание изображения На самом деле проблема состояла из двух частей:

1) порядок строк и столбцов в modelViewMatrix: порядок, ожидаемый вершинным шейдером, противоположен тому, что ожидает остальные THREE.js.

2) Object3D-иерархия: т.е. сцена, сетка, геометрия, вершины линий + камера: куда поместить данные моделиViewMatrix, чтобы они создавали желаемый результат (т.е. тот же результат, что выдавало старое чертово приложение opengl): я не доволен хак, который я нашел здесь - но пока что он единственный, который работает:

  • Я НЕ прикасаюсь к камере.. она остается на 0/0/0
  • Я напрямую перемещаю все вершины моей «линейной» геометрии относительно реального положения камеры (см. «Положение» из modelViewMatrix)
  • Затем я отключаю «matrixAutoUpdate» в сетке, содержащей мою «линейную» геометрию, и копирую modelViewMatrix (в которой я сначала обнулил «позицию») в поле «матрица».

БИНГО.. тогда это работает. (Все мои попытки добиться того же результата, вращая/смещая камеру или перемещая/вращая любой из задействованных Object3D, с треском провалились..)

РЕДАКТИРОВАТЬ: я нашел лучший способ, чем обновление вершин и, по крайней мере, сохранение всех манипуляций на уровне сетки (я все еще перемещаю мир - как это сделало бы старое приложение OpenGL ..). Чтобы получить правильную последовательность перевода/вращения, можно также использовать ("m" по-прежнему является исходной моделью OpenGL ViewMatrix - с информацией о положении 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);

Если кто-то знает лучший способ, который также работает (тот, где камера обновляется без необходимости напрямую манипулировать матрицами объектов), мне, безусловно, было бы интересно это услышать.

person wothke    schedule 13.03.2017