Jump to content
  • Advertisement
Awoken

Camera movement about a sphere.

Recommended Posts

 

// 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?

Edited by Awoken

Share this post


Link to post
Share on other sites
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;
}

 

Edited by Awoken

Share this post


Link to post
Share on other sites
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.

Edited by Awoken

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!