Help! how to keep the camera look at same direction as it moves

Hello…everyone in this forum…

I have a problem with perspective camera in my three.js app. Below is my explanation.
I have a 3d mesh and two skyboxes inside. Everytime I move into a skybox using tween, it goes nicely looking at the target and at the end the camera turns to -Z direction with controls.update(). If I don’t put controls.update(), the camera stays the direction until I click mouse and move the mouse. So, after I move the mouse the camera turns to -Z direction. I guess in animate function controls get reset maybe. I have been trying to solve this problem at least a couple of days and I have no clue why it happens. Here is the code snippet. Thanks in advance.

		//-> init function
		function init() {
			//container = document.getElementById( 'container' );
			container = document.createElement( 'div' );
			container.style.width="100%";
			container.style.height="calc( 100% - 70px)";
			document.body.appendChild( container );
			// SCENE
			scene = new THREE.Scene(); // for model
			scene.background = new THREE.Color( 0x000000 );
			scene2 = new THREE.Scene(); // for other stuffs such as sprites				// RENDERER
			renderer = new THREE.WebGLRenderer();
			renderer.setPixelRatio( window.devicePixelRatio );
			renderer.setSize( window.innerWidth, window.innerHeight );
			renderer.gammaOutput = true;
			//document.body.appendChild( renderer.domElement );
			container.appendChild( renderer.domElement );
			// possibly vr button will show up at the bottom
			document.body.appendChild( WEBVR.createButton( renderer ) );
			renderer.vr.enabled = false;

			// CAMERA
			camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 2000 );
			camera.zoom = 0.8;
			camera.fov = 70;
			camera.near = 1;
			camera.far = 2000;
			camera.updateProjectionMatrix();

			var position = new THREE.Vector3( 0, 150, 500 );
				moveCameraOut( position );
				
			// CONTROL
			controls = new OrbitControls( camera, renderer.domElement );
			controls.update();

			// LIGHT
			var ambientLight = new THREE.AmbientLight( 0xffffff, 5 );
			scene.add( ambientLight );

			var pointLight = new THREE.PointLight( 0xffffff, 0.2 );
			camera.add( pointLight );
			scene.add( camera );
			
			// axes
			var axes = new THREE.AxesHelper();
			axes.scale.set( 1000, 1000, 1000 );
			scene.add( axes );

			// MODEL LOADING
			blah...blah...blah...
			
			// to load panorama boxes with hot points at the bottom of them
			for ( var i = 0 ; i < json_navi.length ; i++ ) {
				var background = json_navi[i].background;
				var textures = getTextures( background, 6 );
				var materials = [];
				for ( var j = 0 ; j < 6 ; j++ ) {
					materials.push( new THREE.MeshBasicMaterial( { map: textures[ j ], transparent: false, opacity: 0.5 } ) );
				}
				
				var position = json_navi[ i ].position;
				var skyBox = new THREE.Mesh( new THREE.BoxBufferGeometry( 10, 10, 10 ), materials );
					skyBox.geometry.scale( 1, 1, -1 );
					skyBox.position.copy( position );
					skyBox.rotation.y = Math.PI * json_navi[i].rotation / 180;
					skyBox.name = panoBox_name + '_' + json_navi[ i ].id;
				scene.add( skyBox );

				var naviGeometry = new THREE.RingBufferGeometry( 0.2, 0.5, 30, 30 );
				var naviMaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, transparent: true, opacity: 0.5, side: THREE.DoubleSide } );
					naviMaterial.depthTest = false;
				naviMesh = new THREE.Mesh( naviGeometry, naviMaterial );
				naviMesh.lookAt( new THREE.Vector3( 0, 1, 0 ) );
				naviMesh.position.set( position.x, position.y-5, position.z );
				naviMesh.name = panoBox_hp_name + '_' + json_navi[i].id;
				scene.add( naviMesh );
			}
			
			// event listeners
			window.addEventListener( 'resize', onWindowResize, false );
			container.addEventListener( 'mousemove', function(event) {
				if (floorplanMode != 'floorplan') {
					onDocumentMouseMove( event );
				}
			}, false );
			var singleClickTimer;
			var clickCount = 0;
			container.addEventListener( 'click', function(event) {
				if (floorplanMode != 'floorplan') {
					clickCount++;
					if ( clickCount === 1 ) {
						singleClickTimer = setTimeout( function() {
							clickCount = 0;
							onDocumentMouseDown( event );
						}, 400 );
					} else if ( clickCount === 2 ) {
						clearTimeout( singleClickTimer );
						clickCount = 0;
						onDocumentMouseDblClick( event );
					}
				}
			}, false );
		}
		//<- end of init function

		function animate() {
			requestAnimationFrame( animate );
			renderer.render( scene, camera );
			TWEEN.update();
		}
		
		function onWindowResize() {
			camera.aspect = window.innerWidth / window.innerHeight;
			camera.updateProjectionMatrix();
			renderer.setSize( window.innerWidth, window.innerHeight );
		}

		function onDocumentMouseDown( event ) {
			event.preventDefault();
			var mouse = new THREE.Vector2();     
				
			mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
			mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
				
			var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
			vector = vector.unproject( camera );
			var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
			raycaster.setFromCamera( mouse, camera );
			var intersects = raycaster.intersectObjects( scene.children, true );
			
			if ( intersects.length > 0 ) {
				var panoramaObject = null;
				var hotpointObject = null;
				for ( var i = 0; i < intersects.length; i++ ){
					var currentObject = intersects[i];
					if (currentObject.object.name.startsWith(panoBox_name)) { panoramaObject = currentObject; }
					if (hotpointObject == null && currentObject.object.name.startsWith(panoBox_hp_name)) { hotpointObject = currentObject; }
				}

				if (panoramaObject != null && hotpointObject != null) {
					moveCameraToHotPoint( panoramaObject );
				}
			}
		}

		function moveCameraToHotPoint( panoramaObject ) {
			var controlTo = panoramaObject.object.position.clone();
			var cameraTo = panoramaObject.object.position.clone();
				cameraTo.setZ( cameraTo.z + 0.01);
			var tween = new TWEEN.Tween( camera.position );
				tween.to( cameraTo, 1000 );
				tween.easing( TWEEN.Easing.Linear.None );
				tween.start();
				tween.onUpdate( function()   { /*camera.lookAt( cameraTo ); */controls.target.copy( controlTo ); } );
				tween.onComplete( function() { /*camera.lookAt( cameraTo ); */controls.target.copy( controlTo );  controls.update();} );
		}
1 Like

Similar to your other post, the actual problem is really hard to understand. Please describe in more detail the current and actual result. Sharing your code as an editable live example is also a good idea since it makes it easier to debug and thus provide a solution.

Thank you for your reply… Michael
I was trying to use fiddle but I am not familiar to use it at this time.
Instead I am including video for now.
In the video, the camera is moving toward the white door and it should stay in front of white door but the camera rotates towards isle.

1 Like

@kwonyu most likely camera is still looking at the same point :smiley: but bypasses it, so it turns back to keep looking at it. even if it reaches exactly the point it should look at, there is now zero distance and math breaks, so the camera is likely getting defult direction, which is different from what you desire.

Thanks for your reply…makc3d…
Can you provide any sample in javascript to make camera look at the direction camera is moving to?

In most cases, you compute some sort of translation or offset vector that represents the trajectory of a single frame. Hence, you can do the following:

// compute new position of the camera
newPosition.addVectors( camera.position, translation );

// use it to update the orientation of the camera  (and of course its position)
camera.lookAt( newPosition );
camera.position.copy( newPosition );
1 Like

Hi, kwonyu. Can you share your full source code? I am doing the similar project like you.

did your issue get solved, i am facing the same issue with camera looking at -z axis always
please share the solution .