Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

three.js rotate camera in plane

I have a camera in my app:

camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = 1;
camera.position.y = -5;
camera.rotateOnAxis(new THREE.Vector3(1, 0, 0), degInRad(90));
camera.up = new THREE.Vector3(0, 0, 1);  

Those code in render function must rotate the camera while I'm pressing the keys:

if (leftPressed) {
    camera.rotateOnAxis((new THREE.Vector3(0, 1, 0)).normalize(), degInRad(1));
} else if (rightPressed) {
    camera.rotateOnAxis((new THREE.Vector3(0, 1, 0)).normalize(), degInRad(-1));
}
if (upPressed) {
    camera.rotateOnAxis((new THREE.Vector3(1, 0, 0)).normalize(), degInRad(1));
} else if (downPressed) {
    camera.rotateOnAxis((new THREE.Vector3(1, 0, 0)).normalize(), degInRad(-1));
}  

Camera rotates, but not in way I need. I want that camera rotates like in FPS (first person shooter) on plane. See picture to understand what I want...
I'm try to use sin(1) and cos(1) but can't understand how rotateOnAxis works, cause translate functions work like a charm and moves camera in direction in what she sees.
P.S.
Here is a docs to the three.js maybe it helps.
To handle keyboard events I use KeyboardJS
And here is a degInRad function:

function degInRad(deg) {
    return deg * Math.PI / 180;
}  

Link on JSFiddle

camera rotation

O - position of camera
O-O1 - current camera direction
R1 - current rotation direction
R - direction what I want
Sorry for good picture.

like image 489
ostapische Avatar asked Nov 30 '22 20:11

ostapische


2 Answers

believe what your looking for conceptually is a camera rig setup. In this approach you first build an Object3D to be the "neck", then attach the camera to that object with your desired rotation. Then you can apply the rotations to the Object3D to look around without the wobble effect. To carry it further you could nest that "neck" object in another Object3D to act as the "body" and apply the translations to that object to move about the scene. In this way you have a basic camera controller rig. I modified your fiddle like so:

Edit: implementation change to better suit @ostapische use case. Here's the fiddle link

function degInRad(deg) {
    return deg * Math.PI / 180;
}
/////////////////////////////////
function render() {
    requestAnimationFrame(render);
    if (leftPressed) {
        neck.rotation.y += degInRad(1);
    } else if (rightPressed) {
        neck.rotation.y -= degInRad(1);
    }
    if (upPressed) {
        camera.rotation.x += degInRad(1);
    } else if (downPressed) {
        camera.rotation.x -= degInRad(1);
    }
    renderer.render(scene, camera);
}
/////////////////////////////////
var scene, camera, renderer, grass, neck;
var leftPressed = false;
var rightPressed = false;
var upPressed = false;
var downPressed = false;
/////////////////////////////////
window.onload = function() {
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
    cameraHolder = new THREE.Object3D();
    cameraHolder.add( camera );
    renderer = new THREE.WebGLRenderer();
    renderer.rendererSize = {width: window.innerWidth, height: window.innerHeight, quality: 100, maxQuality: 400, minQuality: 20};
    renderer.setSize( renderer.rendererSize.width, renderer.rendererSize.height );
    document.body.appendChild( renderer.domElement );

    var texture, material, geometry, element;

    material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
    material.side = THREE.DoubleSide;
    geometry = new THREE.PlaneGeometry(24, 24);   
    grass = new THREE.Mesh( geometry, material );
    grass.name = "grass";
    scene.add( grass );

    neck = new THREE.Object3D();
    neck.rotateOnAxis(new THREE.Vector3(1, 0, 0), degInRad(90));
    neck.up = new THREE.Vector3(0, 0, 1);
    neck.position.z = 1;
    neck.position.y = -5;


    neck.add(camera);
    scene.add(neck);    

    KeyboardJS.on('left', function() { leftPressed = true; }, function() { leftPressed = false; });
    KeyboardJS.on('right', function() { rightPressed = true; }, function() { rightPressed = false; });
    KeyboardJS.on('up', function() { upPressed = true; }, function() { upPressed = false; });
    KeyboardJS.on('down', function() { downPressed = true; }, function() { downPressed = false; });

    render();
}

I was going to mention the PointLockControl or FirstPersonControl, but I see WestLangley has been so kind to suggest. Anyway good luck,

like image 36
Darryl_Lehmann Avatar answered Dec 03 '22 10:12

Darryl_Lehmann


You might get what you want simply by setting camera.rotation.order = 'YXZ';

like image 152
IceCreamYou Avatar answered Dec 03 '22 09:12

IceCreamYou