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.
`
<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>
`
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.
+1
I guess that may explain:
http://stackoverflow.com/questions/43909459/setting-camera-position-and-fov-manually-with-trackball-controls-threejs
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.
@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.
@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).
@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);
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
Most helpful comment
Yes, the problem is that camera.up defaults to the y-axis.
I fixed it by adding
at line 170 in TrackballControls.js
If somebody could add this to the actual file that would be great.