Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TrackballControls don't work if camera.position is on the y-axis #10161

Closed
3 of 12 tasks
h-a-n-n-e-s opened this issue Nov 18, 2016 · 9 comments
Closed
3 of 12 tasks

TrackballControls don't work if camera.position is on the y-axis #10161

h-a-n-n-e-s opened this issue Nov 18, 2016 · 9 comments
Labels

Comments

@h-a-n-n-e-s
Copy link

In the example below, if camera.position is set to (0,distance,0) where distance is some positive number, the trackball controls don't work properly anymore. Instead there is only zooming if the left mouse button is pressed and the mouse is moved around. Just press the "ALIGN Y" button to see this. The behavior is not observed pressing the "ALIGN X" or "ALIGN Z" button.

`

<title>TrackballControls test</title>
<body>

	<script src='js/libs/inflate.min.js'></script>
	<script src="js/three.js"></script>

	<script src="js/controls/TrackballControls.js"></script>

	<div>
	<button onclick="alignX()" >ALIGN X</button>
	<button onclick="alignY()" >ALIGN Y</button>
	<button onclick="alignZ()" >ALIGN Z</button>
	</div>

	<script>

		var container, camera, controls, scene, renderer, distance;

		init();
		animate();

		function alignX() {controls.reset(); camera.position.set(distance,0,0);}
		function alignY() {controls.reset(); camera.position.set(0,distance,0);}
		function alignZ() {controls.reset(); camera.position.set(0,0,distance);}

		function init() {

			camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1000 );
			distance = 2.2;
			camera.position.set(0,0,distance);

			controls = new THREE.TrackballControls( camera );

			controls.rotateSpeed = 5.0;
			controls.zoomSpeed = 5;
			controls.panSpeed = 2;

			controls.noZoom = false;
			controls.noPan = false;

			controls.staticMoving = true;
			controls.dynamicDampingFactor = 0.3;

			scene = new THREE.Scene();

			// light

			var ambientLight = new THREE.AmbientLight(0x222222);
			camera.add( ambientLight );

			var light = new THREE.PointLight();
                            light.position.set( 2, 2, 2 );
                            camera.add( light );

			scene.add( camera );

			// objects

			var material = new THREE.MeshLambertMaterial({ vertexColors: THREE.FaceColors });

			var ico = new THREE.IcosahedronGeometry( 0.8, 0 );
			for ( var i = 0; i < ico.faces.length; i ++ ) {
				var face = ico.faces[ i ];
				face.color.setHex( Math.random() * 0xffffff );
			}
			var bert = new THREE.Mesh( ico, material );
			scene.add( bert )

			// renderer

			renderer = new THREE.WebGLRenderer( { antialias: false } );
			renderer.setPixelRatio( window.devicePixelRatio );
			renderer.setSize( window.innerWidth, window.innerHeight );

			container = document.createElement( 'div' );
			document.body.appendChild( container );
			container.appendChild( renderer.domElement );

			window.addEventListener( 'resize', onWindowResize, false );

		}

		function onWindowResize() {

			camera.aspect = window.innerWidth / window.innerHeight;
			camera.updateProjectionMatrix();

			renderer.setSize( window.innerWidth, window.innerHeight );

			controls.handleResize();

		}

		function animate() {

			requestAnimationFrame( animate );

			controls.update();
			renderer.render( scene, camera );

		}

	</script>

</body>
`
Three.js version
  • Dev
  • r82
  • ...
Browser
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • Windows
  • Linux
  • Android
  • IOS
@WestLangley
Copy link
Collaborator

WestLangley commented Jan 10, 2017

Reopening... I think this is a problem with TrackballControls, and is due to its sensitivity to camera.up, which defaults to the y-axis.

@h-a-n-n-e-s You code should be written like so

function alignX() { controls.position0.set( distance, 0, 0 ); controls.reset(); }
function alignY() { controls.position0.set( 0, distance, 0 ); controls.reset(); }
function alignZ() { controls.position0.set( 0, 0, distance ); controls.reset(); }

But the issue remains.

This is going to take some work, if anyone is interested in looking at it.

@NicolasRannou
Copy link
Contributor

@h-a-n-n-e-s
Copy link
Author

Yes, the problem is that camera.up defaults to the y-axis.
I fixed it by adding

if ( objectSidewaysDirection.lengthSq() < EPS ) {
  var a = - Math.sign(_this.object.position.y);
  _this.object.up.set(0,0,a);
  objectUpDirection.set(0,0,a);
  objectSidewaysDirection.set(a,0,0);
}

at line 170 in TrackballControls.js
If somebody could add this to the actual file that would be great.

@WestLangley
Copy link
Collaborator

@h-a-n-n-e-s I doubt the solution can ignore the value of target.

Also, Math.sign( 0 ) is 0, and up cannot be set to ( 0, 0, 0 ).`

Also, objectSidewaysDirection is normalized in line 169, so your EPS test is relying on predictable behavior of normalize() when the method is clearly producing an unexpected result.

@h-a-n-n-e-s
Copy link
Author

@WestLangley true, target should be involved. Sorry, I just assumed target to be positioned at (0,0,0).

In the critical case objectSidewaysDirection.lengthSq() < EPS evaluates to true anyway, although objectSidewaysDirection is normalized. The way this works is that once objectUpDirection and eyeDirection are identical (0,1,0), their cross product objectSidewaysDirection becomes (0,0,0). The zero vector cannot be normalized so it just remains the zero vector.

Anyway, there should be a short and simple solution to this, I was just playing around with it for fun (Currently I'm not using threejs anyway).

@MarkBirch3D
Copy link

@h-a-n-n-e-s this helped me greatly, and for anyone else, changing my camera's up after construction also works

this.camera.up.set(0, 0, 1);

@RaphiStein
Copy link

RaphiStein commented Oct 5, 2020

I think when you set up your camera, it by default "looks at" the origin. Also, by default its "up" vector is [0, 1, 0]
(Someone correct me if I'm wrong)

That means that when you click "ALIGN Y", you are moving the camera to [0, 2.2, 0] and it is "looking" down the Y axis to see the origin at [0, 0, 0]

Here's the problem: You repositioned the camera, but you didn't change the up vector! It's still [0, 1, 0]
So you are now looking in the direction [0, -1, 0] but up is on the same exact "line!"

When you have up on the same line you are "looking", the up becomes pretty useless, since it can't tell you anything about the x axis, and ultimately the camera's true y axis. Normally, you can get x by getting the cross product of the lookAt (i.e. z) and up

This Udacity video is a good explainer on this concept

@mrdoob
Copy link
Owner

mrdoob commented Feb 6, 2021

@WestLangley Do you wan to continue keep this issue open?

@WestLangley
Copy link
Collaborator

I do not.

BTW, I provided much simpler Trackball update logic here. Unlike the existing TrackballControls, it does not modify camera.up. It also leverages the existing OrbitControls code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants