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

CameraTransition: Add support for rotation transition #931

Merged
merged 8 commits into from
Jan 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions example/googleMapsExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ let statsContainer, stats;
const params = {

orthographic: false,
topDownOrtho: false,

enableCacheDisplay: false,
enableRendererStats: false,
Expand Down Expand Up @@ -137,14 +138,37 @@ function init() {

controls.getPivotPoint( transition.fixedPoint );

// sync the camera positions and then adjust the camera views
transition.syncCameras();
controls.adjustCamera( transition.perspectiveCamera );
controls.adjustCamera( transition.orthographicCamera );
// don't update the cameras if they are already being animated
if ( ! transition.animating ) {

// sync the camera positions and then adjust the camera views
transition.syncCameras();

// If transitioning to ortho view then use a top-down perspective
if ( v && params.topDownOrtho ) {

const invMat = tiles.group.matrixWorld.clone().invert();
const p = transition.fixedPoint.clone().applyMatrix4( invMat );

const { lat, lon } = tiles.ellipsoid.getPositionToCartographic( p, {} );
const { orthographicCamera } = transition;
tiles.ellipsoid.getFrame( lat, lon, 0, 0, 0, 1000, orthographicCamera.matrixWorld );
orthographicCamera.matrixWorld.premultiply( tiles.group.matrixWorld );
orthographicCamera.matrixWorld.decompose( orthographicCamera.position, orthographicCamera.quaternion, orthographicCamera.scale );
orthographicCamera.updateMatrixWorld();

}

controls.adjustCamera( transition.perspectiveCamera );
controls.adjustCamera( transition.orthographicCamera );

}

transition.toggle();

} );
gui.add( params, 'topDownOrtho' );


const mapsOptions = gui.addFolder( 'Google Photorealistic Tiles' );
mapsOptions.add( params, 'useBatchedMesh' ).listen();
Expand Down
31 changes: 23 additions & 8 deletions src/three/controls/CameraTransitionManager.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { Clock, EventDispatcher, MathUtils, OrthographicCamera, PerspectiveCamera, Vector3 } from 'three';
import { Clock, EventDispatcher, MathUtils, OrthographicCamera, PerspectiveCamera, Quaternion, Vector3 } from 'three';

const _forward = new Vector3();
const _vec = new Vector3();
const _orthographicCamera = new OrthographicCamera();
const _targetPos = new Vector3();
const _targetOffset = new Vector3();
const _perspOffset = new Vector3();
const _orthoOffset = new Vector3();
const _quat = new Quaternion();
const _targetQuat = new Quaternion();

export class CameraTransitionManager extends EventDispatcher {

Expand Down Expand Up @@ -79,6 +83,8 @@ export class CameraTransitionManager extends EventDispatcher {
this._target = this._target === 1 ? 0 : 1;
this._clock.getDelta();

this.dispatchEvent( { type: 'toggle' } );

}

update() {
Expand Down Expand Up @@ -276,15 +282,24 @@ export class CameraTransitionManager extends EventDispatcher {
const distToPoint = Math.abs( _vec.subVectors( perspectiveCamera.position, fixedPoint ).dot( _forward ) );
const projectionHeight = 2 * Math.tan( MathUtils.DEG2RAD * perspectiveCamera.fov * 0.5 ) * distToPoint;

// calculate the orientation to transition to
const targetQuat = _targetQuat.slerpQuaternions( perspectiveCamera.quaternion, _orthographicCamera.quaternion, alpha );

// calculate the target distance and fov to position the camera at
const targetFov = MathUtils.lerp( perspectiveCamera.fov, 1, alpha );
const targetDistance = projectionHeight * 0.5 / Math.tan( MathUtils.DEG2RAD * targetFov * 0.5 );
const targetPos = _targetPos.lerpVectors( perspectiveCamera.position, _orthographicCamera.position, alpha );
targetPos.addScaledVector( _forward, Math.abs( _vec.subVectors( targetPos, fixedPoint ).dot( _forward ) ) - targetDistance );

const distToPersp = _vec.subVectors( perspectiveCamera.position, targetPos ).dot( _forward );
const distToOrtho = _vec.subVectors( _orthographicCamera.position, targetPos ).dot( _forward );
// calculate the offset from the fixed point
const orthoOffset = _orthoOffset.copy( _orthographicCamera.position ).sub( fixedPoint ).applyQuaternion( _quat.copy( _orthographicCamera.quaternion ).invert() );
const perspOffset = _perspOffset.copy( perspectiveCamera.position ).sub( fixedPoint ).applyQuaternion( _quat.copy( perspectiveCamera.quaternion ).invert() );
const targetOffset = _targetOffset.lerpVectors( perspOffset, orthoOffset, alpha );
targetOffset.z -= Math.abs( targetOffset.z ) - targetDistance;

// calculate distances to the target point so the offset can be accounted for in near plane calculations
const distToPersp = - ( perspOffset.z - targetOffset.z );
const distToOrtho = - ( orthoOffset.z - targetOffset.z );

// calculate the near and far plane positions
const targetNearPlane = MathUtils.lerp( distToPersp + perspectiveCamera.near, distToOrtho + _orthographicCamera.near, alpha );
const targetFarPlane = MathUtils.lerp( distToPersp + perspectiveCamera.far, distToOrtho + _orthographicCamera.far, alpha );
const planeDelta = Math.max( targetFarPlane, 0 ) - Math.max( targetNearPlane, 0 );
Expand All @@ -297,8 +312,8 @@ export class CameraTransitionManager extends EventDispatcher {
transitionCamera.fov = targetFov;
transitionCamera.near = Math.max( targetNearPlane, planeDelta * 1e-5 );
transitionCamera.far = targetFarPlane;
transitionCamera.position.copy( targetPos );
transitionCamera.rotation.copy( perspectiveCamera.rotation );
transitionCamera.position.copy( targetOffset ).applyQuaternion( targetQuat ).add( fixedPoint );
transitionCamera.quaternion.copy( targetQuat );
transitionCamera.updateProjectionMatrix();
transitionCamera.updateMatrixWorld();

Expand Down
5 changes: 5 additions & 0 deletions src/three/math/Ellipsoid.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ export class Ellipsoid {
target: Matrix4, frame: Frames,
): Matrix4;

getFrame(
lat: number, lon: number, az: number, el: number, roll: number, height: number,
target: Matrix4, frame: Frames,
): Matrix4;

getEastNorthUpFrame( lat: number, lon: number, target: Matrix4 ): Matrix4;
getEastNorthUpAxes( lat: number, lon: number, vecEast: Vector3, vecNorth: Vector3, vecUp: Vector3, point?: Vector3 );

Expand Down
9 changes: 9 additions & 0 deletions src/three/math/Ellipsoid.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,15 @@ export class Ellipsoid {

}

getFrame( lat, lon, az, el, roll, height, target, frame = ENU_FRAME ) {

this.getRotationMatrixFromAzElRoll( lat, lon, az, el, roll, target, frame );
this.getCartographicToPosition( lat, lon, height, _pos );
target.setPosition( _pos );
return target;

}

getCartographicToPosition( lat, lon, height, target ) {

// From Cesium function Ellipsoid.cartographicToCartesian
Expand Down
Loading