Camera movement about a sphere.

Started by
5 comments, last by CrazyCdn 5 years, 9 months ago

 


// camera.tilt is a preset value determined for best intended effect, ignore for the question.
// camera.tilt_value is a preset value determined for best result, ignore for the question.

if(  keyboard.pressed('d')){

	// Move right
    camera.camPosi = rotatePoint( angleToRadians( camera.rotationSpeed ), 1, camera.camPosi, camera.upAxis, true );
    camera.position.set(camera.camPosi.x * camera.Zoom, camera.camPosi.y * camera.Zoom , camera.camPosi.z * camera.Zoom);
    camera.up = camera.upAxis.clone();
    if ( camera.Zoom <=camera._tilt ) {
      camera.lookAtVector = newLookAt( camera.upAxis , camera.Zoom , camera._tilt , camera._tilt_value );
      camera.lookAt( camera.lookAtVector.clone() );
    } else {
      camera.lookAtVector = newLookAt( camera._base , camera.Zoom , camera._tilt , camera._tilt_value );
      camera.lookAt( camera.lookAtVector.clone() );
    }

}
if( keyboard.pressed('s') ){

  	// Move down
    camera.crossVector = rotatePoint( angleToRadians( 90 ), 1, camera.camPosi, camera.upAxis, true );
    camera.upAxis = rotatePoint( angleToRadians( camera.rotationSpeed ), 1, camera.upAxis, camera.crossVector, true );
    camera.camPosi = rotatePoint( angleToRadians( camera.rotationSpeed ), 1, camera.camPosi, camera.crossVector, true );
    camera.position.set(camera.camPosi.x * camera.Zoom, camera.camPosi.y * camera.Zoom , camera.camPosi.z * camera.Zoom);
    camera.up = camera.upAxis.clone();
    if ( camera.Zoom <=camera._tilt ) {
      camera.lookAtVector = newLookAt( camera.upAxis , camera.Zoom , camera._tilt , camera._tilt_value );
      camera.lookAt( camera.lookAtVector.clone() );
    } else {
      camera.lookAtVector = newLookAt( camera._base , camera.Zoom , camera._tilt , camera._tilt_value );
      camera.lookAt( camera.lookAtVector.clone() );
    }

}
if( keyboard.pressed('e')){

  	// Rotate left
    camera.upAxis = rotatePoint($m.A_R(5 * camera.rotationSpeed), 1, camera.upAxis, camera.camPosi, true);
    camera.position.set(camera.camPosi.x * camera.Zoom, camera.camPosi.y * camera.Zoom , camera.camPosi.z * camera.Zoom);
    camera.up = camera.upAxis.clone();

    if ( camera.Zoom <=camera._tilt ) {
      camera.lookAtVector = newLookAt( camera.upAxis , camera.Zoom , camera._tilt , camera._tilt_value );
      camera.lookAt( camera.lookAtVector.clone() );
    } else {
      camera.lookAtVector = newLookAt( camera._base , camera.Zoom , camera._tilt , camera._tilt_value );
      camera.lookAt( camera.lookAtVector.clone() );
    }

}

function rotatePoint( angle , inverseSpeed , v1 , v2 , toNormalize ){
	var c = Math.cos(angle);
	var s = Math.sin(angle);
	// inverseSpeed directly affects the speed of the camera.  so a higher inverseSpeed = slower speed.
	var v3 = new THREE.Vector3(
		inverseSpeed*(c*v1.x)+(s*((v2.y*v1.z)-(v2.z*v1.y))),
		inverseSpeed*(c*v1.y)+(s*((v2.z*v1.x)-(v2.x*v1.z))),
		inverseSpeed*(c*v1.z)+(s*((v2.x*v1.y)-(v2.y*v1.x)))
	);
	if ( toNormalize ){ v3.normalize(); }
	return v3;
}; // used to rotate position of camera.

function newLookAt( axisVector , zoom , tilt , tiltIncrement ) {
	var a = new THREE.Vector3(axisVector.x * ((tilt - zoom)*c*0.5), axisVector.y * ((tilt - zoom)*c*0.5), axisVector.z * ((tilt - zoom)*tiltIncrement*0.5));
	return a;
}; // used to update camera lookat position.  As the camera gets closer to the world the true lookAt vector is no longer the center of the planet, but rather a point that gradually gets further from the center the closer to the planet the camera gets.  That way the camera tilts upwards when zooming in closer to give a better field of view for the user.

The above gives a quick snapshot of my code for moving my camera around the world.  examples of the three types of movement, pan left and right, move up and down, rotate left and right.

camera.cv is the position of the camera
camera.av is the cameras up axis
camera.iv is the cross vector at 90 degrees from both the up axis and lookAt vector
camera.zv is the lookAt vector

What I want to do is incorporate more intuitive rotation functionality for the camera so that when I rotate left or right the camera pans to the left and right, and looks At the center of the screen.  That way when I rotate, it will appear to rotate around the center of the screen as opposed to in circles.

Anyone know how to do this?

Advertisement

Here is code I just added to give the illusion of what I'm going for.  But as you can imagine it only works the way I want at a specific distance from the sphere.


if( keyboard.pressed('left') ){
    var raycaster = new THREE.Raycaster()
    raycaster.setFromCamera( new THREE.Vector2( 0 , 0 ) , camera );

    var intersects = raycaster.intersectObjects( globalMesh );
    var point = intersects[ 0 ].point;

    var oldPosi = camera.cv.clone();
    var angleTo;

    camera.cv = $m.rV($m.A_R(-camera._rSpeed), 1, camera.cv, camera.av, false);
    camera.position.set(camera.cv.x * camera._zoom, camera.cv.y * camera._zoom , camera.cv.z * camera._zoom);
    camera.up = new THREE.Vector3(camera.av.x, camera.av.y, camera.av.z);

    var angleTo = oldPosi.clone().angleTo( camera.cv.clone() );

    camera.av = $m.rV( -angleTo*2.5 , 1, camera.av, camera.cv, false);
    camera.position.set(camera.cv.x * camera._zoom, camera.cv.y * camera._zoom , camera.cv.z * camera._zoom);
    camera.up = new THREE.Vector3(camera.av.x, camera.av.y, camera.av.z);

    if ( camera._zoom <=camera._tilt ) {
      camera.zv = $m.zV( camera.av , camera._zoom , camera._tilt , camera._tilt_value );
      camera.lookAt(new THREE.Vector3(camera.zv.x, camera.zv.y, camera.zv.z));
    } else {
      camera.zv = $m.zV( camera._base , camera._zoom , camera._tilt , camera._tilt_value );
      camera.lookAt(new THREE.Vector3(camera.zv.x, camera.zv.y, camera.zv.z));
    }
    camera._change = true;
}

 

Your code is a little hard to read, what with all the dollar signs, underscores, and two-letter variable names.

If I understand what you are trying to accomplish, you want to orbit the camera around a central point? Have you looked at three.js' own OrbitCamera setup?

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

21 hours ago, swiftcoder said:

Your code is a little hard to read, what with all the dollar signs, underscores, and two-letter variable names.

Sorry about that, In the future I'll be sure to make it legible.  I've modified the original code in the post, not my reply.  Should be a bit easier to understand.

21 hours ago, swiftcoder said:

If I understand what you are trying to accomplish, you want to orbit the camera around a central point? Have you looked at three.js' own OrbitCamera setup?

Very quickly on in development I realised that their orbitCamera had major limitations.  For one it always kept the camera fixed to a permanent up position.  So basically there was a 'true up', 'true down' and left and right.  I didn't want that.  I wanted a user to be able to move all about the world and never be fixed to a 'true up' or 'true down'  I don't know if I'm describing the effect with accuracy.  But anyways, I found Rodrigues' rotation formula.  It allows for the type of rotations I was wanting. https://en.wikipedia.org/wiki/Rodrigues'_rotation_formula  However; it's more than I needed because the formula allows you to rotate around any position in 3d space.  I only needed to rotate around x:0 , y:0 , z:0.  So I simplified it and presto.  You can see the formula modified for my code in my code revamp.

Anyways, the way the camera is set up right now is it's starting location is 0,0,1 and it's upAxis initially is 0,1,0.  It's cross vector is 1,0,0.  If the camera moves left or right only the position and cross vectors are modified and the upAxis stays the same.  If the camera moves up or down then the upAxis and position change, but the crossVector stays the same.  Is my description clear as mud?  hope not. 

To carry on, if the user zooms in closer to the planet the camera's lookAt vector point begins to tilt up and away from the centre of the planet.  That way the camera isn't just looking directly at the ground like a space satellite would.  This allows for the camera to be fixed at about a 45 degree angle from the planet's surface once the camera is zoomed all the way in.

The intended effect I want to add is to allow the camera to appear to rotate around a fixed point on the planet.  That point would be where ever the centre of the camera's field of view is.  In my reply code the effect is achieved, but not gracefully.  Only at a certain distance from the planet's surface does the effect look good.  Otherwise it looks shoddy.  I thought maybe someone might know what to do so that the effect looks clean and proper at any distance from the surface of the planet.

I solved this problem.
For anyone who is interested in the solution I've come up with here is a quick visual representation.


The technique I used was the following:
- obtained distance from centre of sphere to camera's position.
- obtained normalised vector of the centre of screen ( mouse.x '0', mouse.y '0' )
- multiplied scalar of normalised vector by the distance obtained in first step.
- calculated circumference of camera movement path using the two vectors ( camera.position , centre of screen ) 
- using my own move left and right matrix calculations moved the camera to the left and right and then rotated the camera to point at the 
  obtain a new centre of screen. 

Only downfall of this approach is that the centre of the screen slowly moves ever so slightly in little circles.  But nat a big deal.
 

First off, good job on fixing your problem and posting the solution!

Just an idea.  You might thank yourself later for it.  Don't use two letter variable names.  v1 is much more expressive as vec1, should take next to no extra time to type honestly and when you return to code years later it will be much less cryptic.  Also, why do some variables have underscores and others do not?  Seems rather inconsistent.  Again, good job.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This topic is closed to new replies.

Advertisement