简体   繁体   中英

Placing camera W.R.T 3d object in three.js

I have an object that moves and rotates, and I want the camera to stay a certain distance behind it. To be clear, I'm drawing an airplane and want the camera to always be looking at its rear. (Unless the user drags the mouse, for example to look at the top of the airplane as it flies).

So say I have set the position and rotation of the airplane (instance of THREE.Object3D):

airplane.position = {x: 1, y:2, z: 3};
airplane.rotation = {x: Math.PI/4, y:1.2, z: 0};

And say, when the rotation and positions are (0,0,0) the camera is at (5, 0, 0), (ie 5 units behind the airplane's center), what would be the simplest way of finding the position vector to set the camera at?

Thanks

Sorry for the sprawled code, I'm hacking it to death. I'd make a jsfiddle for it, but haven't got a server to host three.js on...

$(function(){
    var camera1, camera2, scene, renderer, viewPort;
    var objectManager;
    var views = [];
    var vpWidth, vpHeight;
    init();
    animate();
    updateSize();
    function updateSize(){
        vpWidth = viewPort.innerWidth();
        vpHeight = viewPort.innerHeight();
    }
    function init() {
        viewPort = $('#viewPort');
        objectManager = new ObjectManager();

        views[0] = new View(viewPort, objectManager);
        var view = views[0];
        view.fov = 20;
        view.proportions.height = 0.5;
        view.proportions.bottom = 0.5;
        view.init();
        views[1] = new View(viewPort, objectManager);
        var view = views[1];
        view.fov = 10;
        view.proportions.height = 0.5;
        view.init();
        view.updateCamera = function(){

            //-----------------------------------------------------
            // when the user drags the mouse, (not yet implemented)
            // the following camera position numbers would change
            // so that he could view for example the top of the
            // airplane as it flies
            //-----------------------------------------------------
            this.camera.position.set( 5,5,5 );

            //-----------------------------------------------------
            // This line does not work as expected: the airplane
            // does not stay in the center of the view but follows
            // some sort of curved path with respect to the camera
            //-----------------------------------------------------
            this.camera.lookAt(objectManager.airplane.position);

            this.camera.updateProjectionMatrix();
        };
        scene = new THREE.Scene();
        objectManager.addTo(scene);

        objectManager.airplane.add(views[1].camera);

        //-----------------------------------------------
        // The following two lines *do* work correctly //
        //-----------------------------------------------
        views[1].camera.position.set( 0,0,5 );
        views[1].camera.lookAt(objectManager.airplane.position);

        var ambientLight = new THREE.AmbientLight(0x808080);
        scene.add(ambientLight);        

        var pointLight = new THREE.PointLight(0x808080);
        pointLight.position = {x: 100, y: 100, z: 100};
        scene.add(pointLight);      

        renderer = new THREE.WebGLRenderer();
        renderer.setClearColorHex(0x000000, 1);
        renderer.setSize( viewPort.innerWidth(), viewPort.innerHeight() );
        viewPort.get(0).appendChild(renderer.domElement);
    }

    function animate() {
        requestAnimationFrame( animate );
        render();
    }
    function render() {
        objectManager.tick();
        var view;
        for (var i in views){
            view = views[i];
            view.updateCamera();
            pixels = view.pixels;
            renderer.setViewport(pixels.left, pixels.bottom, pixels.width, pixels.height);
            renderer.setScissor(pixels.left, pixels.bottom, pixels.width, pixels.height);
            renderer.enableScissorTest(true);
            renderer.render( scene, view.camera );
        }
    }
});
function View(vp, om){
    this.objectManager = om;
    this.viewPort = vp;
    this.fov = 30;
    this.proportions = { left: 0, bottom: 0, height: 1, width: 1 };
    this.pixels = { left: 0, bottom: 0, height: 0, width: 0, aspect: 0 };
    this.aspect;
    this.init = function(){
        this.camera = new THREE.PerspectiveCamera( 
                this.fov, 
                this.viewPort.innerWidth() / this.viewPort.innerHeight(), 
                0.1, 10000 
        );
        this.pixels.left = Math.floor(this.proportions.left * this.viewPort.innerWidth()); 
        this.pixels.width = Math.floor(this.proportions.width * this.viewPort.innerWidth()); 
        this.pixels.bottom = Math.floor(this.proportions.bottom * this.viewPort.innerHeight()); 
        this.pixels.height = Math.floor(this.proportions.height * this.viewPort.innerHeight()); 
        this.pixels.aspect = this.pixels.width / this.pixels.height;
        this.camera.position.y = 0;
        this.camera.position.z = 10;
        this.camera.aspect = this.pixels.aspect;
        this.camera.updateProjectionMatrix();
    };
    this.updateCamera = function(){};
}

function newCube(dims, pos, cols, colAss){
    var mesh;
    var geometry;
    var materials = [];
    geometry = new THREE.CubeGeometry( dims.x, dims.y, dims.z );
    for (var i in cols){
        materials[i] = new THREE.MeshLambertMaterial( { color: cols[i], ambient: cols[i], overdraw: true } );
    }
    geometry.materials = materials;
    for (var i in colAss){
        geometry.faces[i].materialIndex = colAss[i];
    }
    mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
    mesh.position = pos;
    return mesh;
}
function ObjectManager(){
    this.airplane;
    var fuselage;
    var tail;
    var grid;
    this.addTo = function(scene){
        this.airplane = new THREE.Object3D();
        fuselage = newCube(
                {x: 1, y: 0.1, z: 0.1}, 
                {x: 0, y: 0, z: 0},
                [0xffff00, 0x808000, 0x0000ff, 0xff00000, 0xffffff, 0x808080],
                [0, 1, 2, 3, 4, 5]
        );
        this.airplane.add(fuselage);
        tail = newCube(
                {x: 0.15, y: 0.2, z: 0.05}, 
                {x: 0.5, y: 0.199, z: 0},
                [0xffff00, 0x808000, 0x0000ff, 0xff00000, 0xffffff, 0x808080],
                [0, 1, 2, 3, 4, 5]
        );
        this.airplane.add(tail);
        scene.add( this.airplane );

        grid = new THREE.Object3D();

        var geometry = new THREE.Geometry();
        geometry.vertices.push(new THREE.Vector3( - 200, 0, 0 ) );
        geometry.vertices.push(new THREE.Vector3( 200, 0, 0 ) );

        linesMaterial = new THREE.LineBasicMaterial( { color: 0x00ff00, opacity: 1, linewidth: .1 } );

        for ( var i = 0; i <= 200; i ++ ) {

            var line = new THREE.Line( geometry, linesMaterial );
            line.position.z = ( i * 2 ) - 200;
            grid.add( line );

            var line = new THREE.Line( geometry, linesMaterial );
            line.position.x = ( i * 2 ) - 200;
            line.rotation.y = 90 * Math.PI / 180;
            grid.add( line );
        }       
        scene.add( grid );

    };
    this.tick = function(){
        this.airplane.rotation.x += 0.005;
        this.airplane.rotation.y += 0.01;
        this.airplane.position.x += 0.01;
    };
};

Add the camera as a child of the airplane, instead.

airplane.add( camera );
camera.position.set( 5, 0, 0 );
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );

Now, when you rotate/move the airplane, the camera will follow automatically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM