Use camera like human eyes

I want to use the camera like human eyes.

The human being should walk (e.g. also backwards without turning around) in a limited space and also tilt his head.

Although I created a Quaternion data visualization, I could not solve this with this technique.
https://discourse.threejs.org/t/quaternion-axis-angle-visualization/1358

During the search I did not find a suitable solution for me.

With the elements

viewPoint = new THREE.Vector3( … );
camera.lookAt( viewPoint );

I’ve made a simple solution.

http://threejs.hofk.de/fiddle/camera_fiddle.html
(Use w s a d l r t b uparrow down arrow, moving with the mouse can be easily added to.)

Since it’s jerking, TWEEN must be added. For example like there: http://jsfiddle.net/prisoner849/r9vzm1uf/

As a room I took a skybox from Emil Persson.
http://www.humus.name/index.php?page=Textures&start=32
(Creative Commons License Attribution 3.0)

I don’t quite like my solution myself.

Question.
Is there a better solution somewhere,
or what should I change in my solution?


<!DOCTYPE html>
	<html lang="de">
<head>
<meta charset="utf-8">
<title> eye camera  </title>
<style> </style>
</head>
<body ></body>
<script src="three.min.92.js"></script>
<script src="THREEx.WindowResize.js"></script>

<script> 'use strict'

var scene = new THREE.Scene( );
var camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.001, 10000 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
var container = document.createElement('div');
document.body.appendChild( container );
container.appendChild( renderer.domElement );
THREEx.WindowResize( renderer, camera );

var speed = 0.88; // In this demo constant.

var phi = 0;
var theta = 0;
var viewR0 = 80;
var viewR = viewR0; 
var viewDir = new THREE.Vector2( );
var scout = new THREE.Object3D( );

camera.position.set( 0, 1.5 , 0 ); // height of human eyes

var viewPoint = new THREE.Vector3( 0, 1.5, -viewR0 );
camera.lookAt( viewPoint );

document.addEventListener( 'keydown', function( evt ) {
	
	if ( evt.keyCode === 87 ) { if ( withinBorders( moveForward ) ) moveForward( camera ) }	// w fast vorward
	if ( evt.keyCode === 83 ) { if ( withinBorders( moveBack ) ) moveBack( camera ) }		// s backward a little slower
	if ( evt.keyCode === 65 ) { if ( withinBorders( moveLeft ) ) moveLeft( camera ) }		// a slowly leftwards
	if ( evt.keyCode === 68 ) { if ( withinBorders( moveRight ) ) moveRight( camera ) }		// d slowly rightwards
		
	if ( evt.keyCode === 76 ) { turnLeft( camera ) }		// l turn to the left
	if ( evt.keyCode === 82 ) { turnRight( camera ) }		// r turn to the right
		
	if ( evt.keyCode === 84 ) { goTop( camera ) }	 		// t upstretch
	if ( evt.keyCode === 66 ) { goBottom( camera ) }	 	// b bend down
	if ( evt.keyCode === 38 ) { lookUp( camera ) }	 		// up arrow, looking higher
	if ( evt.keyCode === 40 ) { lookDown( camera ) }		// down arrow, looking deeper
	
}); 

var texturArray = [ 'CubeMap/', 'posx.jpg', 'negx.jpg', 'posy.jpg', 'negy.jpg', 'posz.jpg', 'negz.jpg'];

var skyboxTexture = new THREE.CubeTextureLoader( ).setPath( texturArray[ 0 ] ).load( [
		texturArray[ 1 ],
		texturArray[ 2 ],
		texturArray[ 3 ],
		texturArray[ 4 ],
		texturArray[ 5 ],
		texturArray[ 6 ]
	] );

var shader = THREE.ShaderLib[ "cube" ];
shader.uniforms[ "tCube" ].value = skyboxTexture;
var shMaterial = new THREE.ShaderMaterial( {
		fragmentShader: shader.fragmentShader,
		vertexShader: shader.vertexShader,
		uniforms: shader.uniforms,
		side: THREE.BackSide 
	} );

var surroundings = new THREE.Mesh( new THREE.BoxBufferGeometry( 10 * viewR0, 10 * viewR0, 10 * viewR0 ), shMaterial );
surroundings.position.set( 0 , 10, 0 );

scene.add( surroundings );

animate();

// ...................

function animate( ) {
	
	requestAnimationFrame( animate );
	camera.lookAt( viewPoint );	
	renderer.render( scene, camera );
	
}	

function turnRight( obj ) { 
	
	phi -= 0.006 * speed;
	
	viewPoint.x = obj.position.x - Math.sin( phi ) * viewR;
	viewPoint.z = obj.position.z - Math.cos( phi ) * viewR;
	
}

function turnLeft( obj ) {
	
	phi += 0.006 * speed;
		
	viewPoint.x = obj.position.x - Math.sin( phi ) * viewR;
	viewPoint.z = obj.position.z - Math.cos( phi ) * viewR;
	
}

function moveForward( obj ) {
	
	viewDir.x = -Math.sin( phi );
	viewDir.z = -Math.cos( phi );
	
	move( obj, viewDir, 4 );
	
}

function moveRight( obj ) {
	
	viewDir.x = Math.cos( phi );
	viewDir.z = -Math.sin( phi );
	
	move( obj, viewDir, 1.2 );
	
}

function moveLeft( obj ) {
	
	viewDir.x = -Math.cos( phi );
	viewDir.z = Math.sin( phi );
	
	move( obj, viewDir, 1.2 );
	
}

function moveBack( obj ) {
	
	viewDir.x = Math.sin( phi );
	viewDir.z = Math.cos( phi );
	
	move( obj, viewDir, 2 );
	
}

function goTop( obj ) {
	
	if ( obj.position.y < viewR0 / 4) {
		
		obj.position.y += 0.6 * speed;
		viewPoint.y = obj.position.y + Math.sin( theta ) * viewR0;
		
	}
	
}

function goBottom( obj ) { 
	
	if ( obj.position.y > 1 ) {
	
		obj.position.y -= 0.6 * speed;
		viewPoint.y = obj.position.y + Math.sin( theta ) * viewR0;
		
	}
	
}

function lookDown( obj ) {
	
	if ( theta > -1.45 ) {
		
		theta -= 0.01 * speed;
		viewR = Math.cos( theta ) * viewR0;
		
		viewPoint.x = obj.position.x - Math.sin( phi ) * viewR;
		viewPoint.y = obj.position.y + Math.sin( theta ) * viewR0;
		viewPoint.z = obj.position.z - Math.cos( phi ) * viewR; 
		
	}
	
}

function lookUp( obj ) {
	
	if ( theta < 1.45 ) {
		
		theta += 0.01 * speed;
		viewR = Math.cos( theta ) * viewR0;
		
		viewPoint.x = obj.position.x - Math.sin( phi ) * viewR;
		viewPoint.y = obj.position.y + Math.sin( theta ) * viewR0;
		viewPoint.z = obj.position.z - Math.cos( phi ) * viewR;
		
	}
	
}

function move( obj, viewDir, factor ) {
	
	obj.position.x += viewDir.x * factor * speed;
	obj.position.z += viewDir.z * factor * speed;
	
	viewPoint.x = obj.position.x - Math.sin( phi ) * viewR;
	viewPoint.z = obj.position.z - Math.cos( phi ) * viewR;
	
}

function withinBorders( moveFunction ) {
	
	scout.position.x = camera.position.x;
	scout.position.z = camera.position.z;
	
	moveFunction( scout );
	
	// Here a simple circle. Uniting of figures is possible.
	return Math.sqrt( scout.position.x * scout.position.x + scout.position.z * scout.position.z ) < 200;
	
}

</script>

</html>

I’ve made a simplified version, based on yours. Movements are smooth enough. I hope it will be helpful, if I got correctly your conception:
https://jsfiddle.net/prisoner849/keLkfo5n/

Thank you very much! :star:

I see where I had a problem. You have to put the camera in a holder. The camera itself could only be rotated by 90° in each direction.

I’m gonna try this one.

The camera itself could be rotated up and down only. Rotation to the left and to the right is up to the holder.

Just had an enlightment: get delta in the animation loop and use it in the keydown event listener was a wrong idea, as the typerate differs from the framerate, thus there’s slower speed of movements and rotation.

I tried another approach with getting delta, but there’s a lag at the first keydown event. Maybe this is a dead-end idea? :thinking:
https://jsfiddle.net/prisoner849/sjrdom4t/

One more approach. Works as it meant to be :slight_smile:
https://jsfiddle.net/prisoner849/9xL0qp3h/

I used the procedure of the last fiddle from prisoner849. With movement limitation. That looks good.:relaxed:
http://threejs.hofk.de/fiddle/camera_fiddle_01.html

It is very compact. It uses methods of Object3D.

I had viewed:
_.translateOnAxis ( axis : Vector3, distance : Float ) : Object3D _
Translate an object by distance along an axis in object space.

and also
.translateX ( distance : Float ) : null
Translates object along x axis by distance units.

Because my English is so bad, I have problems with the overview of the documentation.
I’m sure I’ve misinterpreted a few things.

I thought, .translateX refers to the global x axis.
It doesn’t say …axis in object space ( like .translateOnAxis)

That’s why I did my own calculations with sin and cos.

The new code:

<!DOCTYPE html>
	<html lang="de">
<head>
<meta charset="utf-8">
<title> eye camera  </title>
<style> </style>
</head>
<body ></body>
<script src="three.min.92.js"></script>
<script src="THREEx.WindowResize.js"></script>

<script> 'use strict'

var scene = new THREE.Scene( );
var camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.001, 10000 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
var container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
THREEx.WindowResize( renderer, camera );

var scout = new THREE.Object3D( );

// The  speeds in this demo are constant.
var speedVorward = 40;
var speedBackward = 20;
var speedLeftRight = 12;
var speedTurn = 0.1;
var speedUpDown = 15;
var speedLookHighDeep = 0.06;

var clock = new THREE.Clock( );
var delta = 0;

var camHolder = new THREE.Group( );
camHolder.add( camera );
camHolder.position.set( 0, 1.5, 0 ); // height of human eyes
scene.add( camHolder );

var keyCode = -1;
document.addEventListener( 'keydown', function( evt ) { keyCode = evt.keyCode; } );
document.addEventListener( 'keyup', function( ) { keyCode = -1; } );

var texturArray = [ 'CubeMap/', 'posx.jpg', 'negx.jpg', 'posy.jpg', 'negy.jpg', 'posz.jpg', 'negz.jpg'];

var skyboxTexture = new THREE.CubeTextureLoader( ).setPath( texturArray[ 0 ] ).load( [
		texturArray[ 1 ],
		texturArray[ 2 ],
		texturArray[ 3 ],
		texturArray[ 4 ],
		texturArray[ 5 ],
		texturArray[ 6 ]
	] );

var shader = THREE.ShaderLib[ "cube" ];
shader.uniforms[ "tCube" ].value = skyboxTexture;
var shMaterial = new THREE.ShaderMaterial( {
		fragmentShader: shader.fragmentShader,
		vertexShader: shader.vertexShader,
		uniforms: shader.uniforms,
		side: THREE.BackSide 
	} );

var surroundings = new THREE.Mesh( new THREE.BoxBufferGeometry( 800, 800, 800 ), shMaterial );
surroundings.position.set( 0 , 10, 0 );

scene.add( surroundings );

animate();

// ...................

function animate( ) {
	
	requestAnimationFrame( animate );
	delta = clock.getDelta( );
	if ( keyCode !== -1 ) move( );
	renderer.render( scene, camera );
	
}

function move( ) {
	
	if ( keyCode === 87 ) { if ( withinBorders( moveForward ) ) moveForward( camHolder ) }	// w fast vorward
	if ( keyCode === 83 ) { if ( withinBorders( moveBack ) ) moveBack( camHolder ) }	// s  backward a little slower
	if ( keyCode === 65 ) { if ( withinBorders( moveLeft ) ) moveLeft( camHolder ) }	// a slowly leftwards
	if ( keyCode === 68 ) { if ( withinBorders( moveRight ) ) moveRight( camHolder ) }	// d slowly rightwards
		
	if ( keyCode === 76 ) { turnLeft( camHolder ) }		// l turn to the left
	if ( keyCode === 82 ) { turnRight( camHolder ) }	// r turn to the right
		
	if ( keyCode === 84 ) { goTop( camHolder ) }	 	// t upstretch
	if ( keyCode === 66 ) { goBottom( camHolder ) }	 	// b bend down
	
	if ( keyCode === 38 ) { lookUp( camera ) }	 	// up arrow, looking higher	-> camera
	if ( keyCode === 40 ) { lookDown( camera ) }		// down arrow, looking deeper	-> camera
}

function withinBorders( moveFunction ) {
	
	scout.position.x = camHolder.position.x;
	scout.position.z = camHolder.position.z;
	
	moveFunction( scout );
	
	// Here a simple circle. Uniting of figures is possible.
	return Math.sqrt( scout.position.x * scout.position.x + scout.position.z * scout.position.z ) < 200;
	
}

function moveForward( obj ) { obj.translateZ( -speedVorward * delta ); }
function moveRight( obj ) { obj.translateX( speedLeftRight * delta ); }
function moveLeft( obj ) { obj.translateX( -speedLeftRight * delta ); }
function moveBack( obj ) { obj.translateZ( speedBackward * delta ); }

function turnLeft( obj ) { obj.rotateY( speedTurn * delta ); }
function turnRight( obj ) { obj.rotateY( -speedTurn * delta ); }

function goTop( obj ) {	if ( obj.position.y < 20 ) obj.translateY( speedUpDown * delta ); }
function goBottom( obj ) { if ( obj.position.y > -5 ) obj.translateY( -speedUpDown * delta ); }

function lookUp( obj ) { if ( obj.rotation.x < 1.45 ) obj.rotation.x += speedLookHighDeep * delta; }
function lookDown( obj ) { if ( obj.rotation.x > -1.45 ) obj.rotation.x += -speedLookHighDeep * delta; }

</script>

</html>
1 Like