Три. JS Поворот камеры вокруг объекта путем перемещения устройства - PullRequest
1 голос
/ 24 января 2020

Я спросил на другом форуме, но подумал, что хотел бы быть более ясным в своей проблеме.

Каково мое намерение? В настоящее время я использую три. js в WebView на моем android устройстве и создал сцену, которая содержит простую рамку (которая должна использоваться в качестве ограничительной рамки) и камеру. Моя камера должна быть интерактивной с моим android устройством, что означает, что я устанавливаю положение, динамически перемещая устройство. Эти векторы взяты из алгоритма SLAM с именем Direct Sparse Odometry, который воссоздает положение камеры, я также могу назвать эти значения с javascript, используя предоставленный WebViewInterface из Android. Моя цель состоит в том, чтобы динамически «обходить» поле без использования camera.lookAt () - Метод каждый раз, когда я меняю значения, потому что, если я удаляюсь от поля, представление больше не должно центрироваться (как AR-приложение). ), поэтому точка обзора должна создаваться динамически, например, положение и поворот камеры по отношению к объекту. Моя цель - поместить объект поверх объекта реального мира с тремя. js, чтобы затем отсканировать его с помощью DSO, обходя прямоугольник для обнаружения характерных точек. Вся визуализация должна быть создана с тремя. js.

Что такое DSO? DSO - это библиотека для отслеживания реальной среды путем обнаружения точек в кадрах камеры, которые предоставляются Android-камерой 2 API. Это отправляет мне Матрицу преобразования 4x4 с текущей позой, которую я пытаюсь применить к положению камеры three.js. Из-за сложности этого алгоритма, давайте представим, что это дает мне правильные значения (в метрах, но я также пытался умножить значения на 10 или 100, чтобы получить результаты больше, чем 0.XX).

В чем моя проблема ? Поле не имеет абсолютной позиции, даже если значения кажутся фиксированными. Каждый раз при размещении ящика он, кажется, движется в противоположном направлении. После многих корректировок значений dso мне стало ясно, что эта проблема возникает с тремя. js. Я также пытался применить матрицы сцены / камеры и / или использовать прямоугольник как дочерний элемент (из-за наследственности объекта), но блок, похоже, не имеет абсолютного положения внутри сцены. Также я не могу повернуть объект, который кажется реалистичным c.

В приложении вы найдете мой код, но обратите внимание, что я использую динамически фиктивные значения в качестве замены для значений dso .

    <body>
<canvas id="mCanvas">
</canvas>
</body>
<script>
// Var Init
    var renderer, scene, camera, box, transformControl, orbitControl, geometry, material, poseMatrix;
    var mPoints = [];
    //Box coordinate
    var xBCordinate, yBCordinate, zBCordinate, isScaled, posVec, startPosVec, lookPos, helper;
    var process = false;
    var scanActive = false;
    var pointArr = [];

     init();
    animate();

  function init() {

        // renderer
       renderer = new THREE.WebGLRenderer({canvas: document.getElementById("mCanvas"),
            alpha: true});
       renderer.setSize( window.innerWidth, window.innerHeight );
       document.body.appendChild( renderer.domElement );
        renderer.setClearColor(0xffffff, 0);
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // scene
        scene = new THREE.Scene();

        // camera
        camera = new THREE.PerspectiveCamera(
            45,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );

        camera.up.set(0, 0, 1); // Definition of coordinationsystem

        // set initial scale position of camera 
        camera.position.x = 0;
        camera.position.y = -0.5;
        camera.position.z = 0.15;  

        scene.add(camera);

        // set position to look at 
        camera.lookAt(0,2.5,-0.2);

        // apply values
        camera.updateMatrix();

        // light
        var light = new THREE.HemisphereLight( 0xeeeeee, 0x888888, 1 );
        light.position.set( 0, -0.75, 2.5 );
        scene.add(light);


        placeBox();


    }
    function placeBox()
    {


        geometry = new THREE.BoxGeometry(0.5, 1, 0.5); //3,5,3
        material = new THREE.MeshLambertMaterial({color: 0xfece46});

        box = new THREE.Mesh(geometry, material);

        box.position.set(0, 2.5, -0.2);
        box.updateMatrix();
        scene.add(box);

    }
    function animate() {
        requestAnimationFrame(animate);
        if(process == false){
        setCurrentPose();
        }

        renderer.render(scene, camera);
    }

    function setCurrentPose(){
        process = true;

        // this is where I receive the position data via Android
        // but lets try using random numbers between 0.01 - 0.99 (which are the results interval of dso)

        moveRotateCamera();
    }
      function moveRotateCamera(){
       // Create Vector to work with
       posVec = new THREE.Vector3();

       posVec.x = getRandomFloat(0.01, 0.99);
       posVec.y = pgetRandomFloat(0.01, 0.99);
       posVec.z = getRandomFloat(0.01, 0.99);


        camera.position.x = posVec.x;
        camera.position.y = (posVec.y) - 0.50; // minus initial scale position 
        camera.position.z = (posVec.z) + 0.15; 

     //   camera.updateMatrix(); <- seem to change nothing such as UpdateWorldMatrix() etc.    

     // camera rotation tried to calculate with quaternions (result NaN) and/or euler by using former and current point.
        process = false;
    }
    function getRandomFloat(min, max) {
  return Math.random() * (max - min) + min;
}   


// My attempts in trying to calculate the rotation
/*
function setQuaternionRotation(poseMatrix){
        // TODO: delete if not needed!
        // adapted from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm, 2.12.2019, 2.34pm
        mQuaternion = new THREE.Quaternion();

        // Calculate Angle w
        mQuaternion.w = ((Math.sqrt(Math.max(0, (1.0 + poseMatrix.elements[0] + poseMatrix.elements[5] + poseMatrix.elements[10])))/2.0));

        //Sign x,y,z values of quaternion
        mQuaternion.x = ((Math.sqrt(Math.max(0, (1.0 + poseMatrix.elements[0] - poseMatrix.elements[5] - poseMatrix.elements[10])))/2.0));
        mQuaternion.y = ((Math.sqrt(Math.max(0, (1.0 - poseMatrix.elements[0] + poseMatrix.elements[5] - poseMatrix.elements[10])))/2.0));
        mQuaternion.y = ((Math.sqrt(Math.max(0, (1.0 - poseMatrix.elements[0] - poseMatrix.elements[5] + poseMatrix.elements[10])))/2.0));

        //Sign element values
        mQuaternion.x = (Math.sign(mQuaternion.x * (poseMatrix.elements[6] - poseMatrix.elements[9])));
        mQuaternion.y = (Math.sign(mQuaternion.y * (poseMatrix.elements[8] - poseMatrix.elements[2])));
        mQuaternion.z = (Math.sign(mQuaternion.z * (poseMatrix.elements[1] - poseMatrix.elements[4])));

        // debug
        console.log("QuaternionVal: "+mQuaternion.x+ ", " +mQuaternion.y+", "+mQuaternion.z+", "+mQuaternion.w);

        camera.applyQuaternion(mQuaternion);
        camera.quaternion.normalize();


        // debug
        console.log("newCamRotation: "+camera.rotation.x +", "+camera.rotation.y+", "+ camera.rotation.z);

   //     camera.updateMatrix(true);
    }

*/
    </script>

Ссылка на мою скрипку

У вас есть предложения?

Заранее большое спасибо!

С уважением,

1 Ответ

1 голос
/ 28 января 2020

FWIW. Я думаю, что часть проблемы заключается в том, что коробка не центрирована относительно поворота камеры. Я настроил вашу скрипку, центрировав прямоугольник в начале координат, в дополнение к использованию сферических координат для перемещения камеры. Это удерживает камеру на одинаковом расстоянии от рамки, а при центрировании рамки вокруг поворота она, кажется, не движется вокруг области просмотра ...

<body>
<canvas id="mCanvas">
</canvas>
</body>
<script src="https://threejs.org/build/three.js"></script>
<script>
// Var Init
    var renderer, scene, camera, box, transformControl, orbitControl, geometry, material, poseMatrix;
    var mPoints = [];
    //Box coordinate
    var xBCordinate, yBCordinate, zBCordinate, isScaled, posVec, startPosVec, lookPos, helper;
    var process = false;
    var scanActive = false;
    var pointArr = [];
    
    var cameraSpherical;
    
     init();
    animate();

  function init() {

        // renderer
       renderer = new THREE.WebGLRenderer({canvas: document.getElementById("mCanvas"),
            alpha: true});
       renderer.setSize( window.innerWidth, window.innerHeight );
       document.body.appendChild( renderer.domElement );
        renderer.setClearColor(0xffffff, 0);
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // scene
        scene = new THREE.Scene();

        // camera
        camera = new THREE.PerspectiveCamera(
            45,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );

        camera.up.set(0, 0, 1); // Definition of coordinationsystem
        
        // set initial scale position of camera 
        camera.position.x = 0;
        camera.position.y = -0.5;
        camera.position.z = 0.15;  
        
        scene.add(camera);
        
        cameraSpherical = new THREE.Spherical( camera.position );
        
        // set position to look at 
        camera.lookAt(0,2.5,-0.2);
        
        // apply values
        camera.updateMatrix();

        // light
        var light = new THREE.HemisphereLight( 0xeeeeee, 0x888888, 1 );
        light.position.set( 0, -0.75, 2.5 );
        scene.add(light);


        placeBox();


    }
    function placeBox()
    {
        

        geometry = new THREE.BoxGeometry(0.5, 1, 0.5); //3,5,3
        material = new THREE.MeshLambertMaterial({color: 0xfece46});
        
        box = new THREE.Mesh(geometry, material);
        
        box.position.set(0, 0, 0);
        box.updateMatrix();
        scene.add(box);

    }
    function animate() {
        requestAnimationFrame(animate);
        if(process == false){
        setCurrentPose();
        }

        renderer.render(scene, camera);
    }
    
    function setCurrentPose(){
        process = true;
        
        // this is where I receive the position data via Android
        // but lets try using random numbers between 0.01 - 0.99 (which are the results interval of dso)
        
        moveRotateCamera();
    }
      function moveRotateCamera(){
       // Create Vector to work with
      /* posVec = new THREE.Vector3();
          
       posVec.x = getRandomFloat(0.01, 0.05);
       posVec.y = getRandomFloat(0.01, 0.05);
       posVec.z = getRandomFloat(0.01, 0.02);
    
          
        camera.position.x += posVec.x;
        camera.position.y += posVec.y; // minus initial scale position 
        camera.position.z += posVec.z; 
        */
        cameraSpherical.radius = 5;
        cameraSpherical.phi += getRandomFloat(0.001, 0.015);
        cameraSpherical.theta += getRandomFloat(0.001, 0.015);
        let xyz = new THREE.Vector3().setFromSpherical( cameraSpherical );
        camera.position.x = xyz.x;
        camera.position.y = xyz.y;
        camera.position.z = xyz.z;
        
        camera.lookAt(0,0,0);
        
        camera.updateMatrix();
        
        
        
     //   camera.updateMatrix(); <- seem to change nothing such as UpdateWorldMatrix() etc.    
     
     // camera rotation tried to calculate with quaternions (result NaN) and/or euler by using former and current point.
        process = false;
    }
    function getRandomFloat(min, max) {
  return Math.random() * (max - min) + min;
}   


// My attempts in trying to calculate the rotation
/*
function setQuaternionRotation(poseMatrix){
        // TODO: delete if not needed!
        // adapted from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm, 2.12.2019, 2.34pm
        mQuaternion = new THREE.Quaternion();

        // Calculate Angle w
        mQuaternion.w = ((Math.sqrt(Math.max(0, (1.0 + poseMatrix.elements[0] + poseMatrix.elements[5] + poseMatrix.elements[10])))/2.0));

        //Sign x,y,z values of quaternion
        mQuaternion.x = ((Math.sqrt(Math.max(0, (1.0 + poseMatrix.elements[0] - poseMatrix.elements[5] - poseMatrix.elements[10])))/2.0));
        mQuaternion.y = ((Math.sqrt(Math.max(0, (1.0 - poseMatrix.elements[0] + poseMatrix.elements[5] - poseMatrix.elements[10])))/2.0));
        mQuaternion.y = ((Math.sqrt(Math.max(0, (1.0 - poseMatrix.elements[0] - poseMatrix.elements[5] + poseMatrix.elements[10])))/2.0));

        //Sign element values
        mQuaternion.x = (Math.sign(mQuaternion.x * (poseMatrix.elements[6] - poseMatrix.elements[9])));
        mQuaternion.y = (Math.sign(mQuaternion.y * (poseMatrix.elements[8] - poseMatrix.elements[2])));
        mQuaternion.z = (Math.sign(mQuaternion.z * (poseMatrix.elements[1] - poseMatrix.elements[4])));

        // debug
        console.log("QuaternionVal: "+mQuaternion.x+ ", " +mQuaternion.y+", "+mQuaternion.z+", "+mQuaternion.w);

        camera.applyQuaternion(mQuaternion);
        camera.quaternion.normalize();


        // debug
        console.log("newCamRotation: "+camera.rotation.x +", "+camera.rotation.y+", "+ camera.rotation.z);

   //     camera.updateMatrix(true);
    }
   
*/
    </script>

Не уверен, поможет ли это вам в том направлении, куда вы идете, но надеюсь, что он проливает свет.

...