Search code examples
javascriptandroidthree.jsaugmented-reality

Three.JS Rotate Camera around object by moving the device


I’ve asked in another forum but I thought I would like to be more clear on my problem.

Whats my intention? Currently I am using three.js within WebView on my android device and created a scene which contains a simple box (which should be used as a bounding box) and a camera. My camera needs to be an interactive one with my android device, which means that I set the position by moving the device dynamically. These vectors are coming from a SLAM-algorithmn named Direct Sparse Odometry which recreates the camera position, I can also call these values with javascript by using the provided WebViewInterface from Android. My goal is to “walk around” the box dynamically without using the camera.lookAt()-Method every time I change the values, because if I move away from the box, the view should not be centered anymore (like an AR-Application), so the point of view should be created dynamically such as the position and rotation of the camera towards the object. My goal is to place an object over a real world object with three.js to scan it later with DSO by walking around the box to detect feature points. The whole visualisation should be created with three.js.

What is DSO? DSO is a library to track the real environment by detecting points from a camera frames, which are provided by Android’s camera 2 API. This send me a 4x4 transformation Matrix with the current pose, which I try to apply on three.js’s camera position. Due to the complexity of this algorithm, lets pretend this gives me proper values (in meters, but I also tried to multiplicate the values by 10 or 100 to receive larger results than 0.XX).

Whats my Problem? The box does not seem to have an absolute position, even if the values seems to be fixed. Every time when placing the Box, it seem to move in an opposite direction. After many adjustments on the dso values, I am crystal clear that this the problem is happening with three.js. I’ve also tried to apply matrixes of the scene/camera and/or using the box as a child (because of the object-heredity), but the box seems not to have an absolute position inside the scene. Also I am not able to rotate the object that seem to be realistic.

Enclosed, you’ll find my code but p lease note that I am using dynamically dummy values as a replacement for the dso values.

    <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>

Link to my Fiddle

Do you have any suggestions?

Thank you very much in advance!

Best regards,


Solution

  • FWIW. I think part of the issue is that the box is not centered about the camera rotation. I tweaked your fiddle by centering the box at the origin, in addition to using spherical coordinates to move the camera about. This keeps the camera at a uniform distance from the box, and with the box being centered about the rotation, it does not appear to be moving about the viewport...

    <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>

    Not sure whether this helps you in the direction you're going, but hope it sheds some light.