Skip to content

Commit

Permalink
Add new Map / Globe controls (#434)
Browse files Browse the repository at this point in the history
* Add support for globe controls

* Globe controls progress

* Add comments

* Cleanup

* Add detach

* Clean up

* Add angle clamping

* Update controls

* Add min and max distance

* Add snap back

* Add better pivot point

* Update pivot

* Update params

* Improve pivot mesh transform

* Add initial support for pointers

* Get touch controls working

* Add better touch support

* Simplification

* Simplification

* More updates

* Comment

* Fix pivot icon display

* more simplify

* Fix touch action init

* Offset fixes

* Fix issue with reverse dragg

* Update globe controls

* Add set frame function

* Updates

* Fix rotation

* Reuse function

* Fix drag issue

* Add shared direction update function

* fixes to zoom logic

* Cleanup

* More cleanup

* Fix zoom

* Fix zoom scaling

* Add function for getting the up direction

* Zoom based on distance to tileset

* Fix dragging

* Add Maps, GlobeControls

* Fix zoom

* Improvements

* Fix drag reorientation issue

* Fix zoom issue

* Separate tiles

* Fix globe orientation

* Fix up orientation issue, embed "getUpDirection

* Cleanup

* Move to controls folder

* Cleanup

* clean up, comments

* Move getUpDirection function

* Fix rotation limit

* Update google maps example

* Start cleanup of google tiles example

* More example update

* Small fixes, demo update, fix to FadeRenderer

* Fix pivot point

* setFrame to _setFrame, reuse pivot cast

* Fix touch zoom

* Fix touch rotation

* Fixes
  • Loading branch information
gkjohnson authored Jan 2, 2024
1 parent 86ae004 commit 8111f54
Show file tree
Hide file tree
Showing 8 changed files with 1,440 additions and 104 deletions.
141 changes: 39 additions & 102 deletions example/googleMapsExample.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,31 @@
import { GeoUtils, WGS84_ELLIPSOID, WGS84_RADIUS, DebugGoogleTilesRenderer as GoogleTilesRenderer } from '../src/index.js';
import { GeoUtils, WGS84_ELLIPSOID, DebugGoogleTilesRenderer as GoogleTilesRenderer } from '../src/index.js';
import {
Scene,
WebGLRenderer,
PerspectiveCamera,
Raycaster,
Box3,
MathUtils,
} from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js';
import { estimateBytesUsed } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
import Stats from 'three/examples/jsm/libs/stats.module.js';

import { MapControls } from './src/lib/MapControls.js';
import { GlobeControls } from './src/controls/GlobeControls.js';

let camera, controls, scene, renderer, tiles;
let statsContainer, stats;

const raycaster = new Raycaster();
raycaster.firstHitOnly = true;

const apiKey = localStorage.getItem( 'googleApiKey' ) ?? 'put-your-api-key-here';

const params = {

'enableUpdate': true,
'enableCacheDisplay': false,
'enableRendererStats': false,
'apiKey': apiKey,
enableCacheDisplay: false,
enableRendererStats: false,
apiKey: apiKey,

'displayBoxBounds': false,
'displaySphereBounds': false,
'displayRegionBounds': false,
'reload': reinstantiateTiles,
displayBoxBounds: false,
displayRegionBounds: false,

};

Expand All @@ -42,8 +34,6 @@ animate();

function reinstantiateTiles() {

localStorage.setItem( 'googleApiKey', params.apiKey );

if ( tiles ) {

scene.remove( tiles.group );
Expand All @@ -52,6 +42,8 @@ function reinstantiateTiles() {

}

localStorage.setItem( 'googleApiKey', params.apiKey );

tiles = new GoogleTilesRenderer( params.apiKey );
tiles.group.rotation.x = - Math.PI / 2;

Expand All @@ -69,6 +61,8 @@ function reinstantiateTiles() {
tiles.setResolutionFromRenderer( camera, renderer );
tiles.setCamera( camera );

controls.setScene( tiles.group );

}

function init() {
Expand All @@ -82,14 +76,11 @@ function init() {
document.body.appendChild( renderer.domElement );

camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 160000000 );
camera.position.set( 7326000, 10279000, - 823000 );
camera.position.set( 4800000, 2570000, 14720000 );
camera.lookAt( 0, 0, 0 );

// controls
controls = new MapControls( camera, renderer.domElement );
controls.minDistance = 1;
controls.maxDistance = Infinity;
controls.minPolarAngle = Math.PI / 4;
controls.target.set( 0, 0, 1 );
controls = new GlobeControls( scene, camera, renderer.domElement );

reinstantiateTiles();

Expand All @@ -103,30 +94,14 @@ function init() {
const mapsOptions = gui.addFolder( 'Google Tiles' );
mapsOptions.add( params, 'apiKey' );
mapsOptions.add( params, 'reload' );
mapsOptions.open();

const debug = gui.addFolder( 'Debug Options' );
debug.add( params, 'displayBoxBounds' );
debug.add( params, 'displaySphereBounds' );
debug.add( params, 'displayRegionBounds' );

const exampleOptions = gui.addFolder( 'Example Options' );
exampleOptions.add( params, 'enableUpdate' ).onChange( v => {

tiles.parseQueue.autoUpdate = v;
tiles.downloadQueue.autoUpdate = v;

if ( v ) {

tiles.parseQueue.scheduleJobRun();
tiles.downloadQueue.scheduleJobRun();

}

} );
exampleOptions.add( params, 'enableCacheDisplay' );
exampleOptions.add( params, 'enableRendererStats' );
gui.open();

statsContainer = document.createElement( 'div' );
document.getElementById( 'info' ).appendChild( statsContainer );
Expand All @@ -152,39 +127,6 @@ function onWindowResize() {

}

function updateControls() {

const raycaster = new Raycaster();
raycaster.ray.origin.copy( controls.target ).normalize().multiplyScalar( WGS84_RADIUS * 1.5 );
raycaster.ray.direction.copy( raycaster.ray.origin ).normalize().multiplyScalar( - 1 );
raycaster.firstHitOnly = true;

const hit = raycaster.intersectObject( scene, true )[ 0 ];
if ( hit ) {

controls.target.copy( hit.point );

} else {

controls.target.normalize().multiplyScalar( WGS84_RADIUS );

}
controls.panPlane.copy( controls.target ).normalize();

const dist = camera.position.length();
camera.position.copy( controls.target ).normalize().multiplyScalar( dist );
camera.lookAt( controls.target );
controls.update();

const box = new Box3();
tiles.getBounds( box );

camera.far = dist;
camera.near = Math.max( 1, dist - Math.max( ...box.min, ...box.max ) );
camera.updateProjectionMatrix();

}

function updateHash() {

if ( ! tiles ) {
Expand All @@ -195,7 +137,7 @@ function updateHash() {

const res = {};
const mat = tiles.group.matrixWorld.clone().invert();
const vec = controls.target.clone().applyMatrix4( mat );
const vec = camera.position.clone().applyMatrix4( mat );
WGS84_ELLIPSOID.getPositionToCartographic( vec, res );

res.lat *= MathUtils.RAD2DEG;
Expand All @@ -215,11 +157,11 @@ function initFromHash() {
}

const [ lat, lon ] = tokens;
WGS84_ELLIPSOID.getCartographicToPosition( lat * MathUtils.DEG2RAD, lon * MathUtils.DEG2RAD, 0, controls.target );
WGS84_ELLIPSOID.getCartographicToPosition( lat * MathUtils.DEG2RAD, lon * MathUtils.DEG2RAD, 0, camera.position );

tiles.group.updateMatrixWorld();
controls.target.applyMatrix4( tiles.group.matrixWorld );
updateControls();
camera.position.applyMatrix4( tiles.group.matrixWorld ).multiplyScalar( 2 );
camera.lookAt( 0, 0, 0 );

}

Expand All @@ -229,36 +171,35 @@ function animate() {

if ( ! tiles ) return;

updateControls();
controls.update();

// update options
tiles.setResolutionFromRenderer( camera, renderer );
tiles.setCamera( camera );
tiles.displayBoxBounds = params.displayBoxBounds;
tiles.displayRegionBounds = params.displayRegionBounds;

// update tiles
if ( params.enableUpdate ) {
camera.updateMatrixWorld();
tiles.update();

camera.updateMatrixWorld();
tiles.update();

}

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

}
updateHtml();

function render() {
}

// render primary view
renderer.render( scene, camera );
function updateHtml() {

// render html text updates
const cacheFullness = tiles.lruCache.itemList.length / tiles.lruCache.maxSize;
let str = `Downloading: ${ tiles.stats.downloading } Parsing: ${ tiles.stats.parsing } Visible: ${ tiles.visibleTiles.size }`;
let str = '';

if ( params.enableCacheDisplay ) {

str += `Downloading: ${ tiles.stats.downloading } Parsing: ${ tiles.stats.parsing } Visible: ${ tiles.visibleTiles.size }<br/>`;

const geomSet = new Set();
tiles.traverse( tile => {

Expand All @@ -282,18 +223,18 @@ function render() {
let count = 0;
geomSet.forEach( g => {

count += BufferGeometryUtils.estimateBytesUsed( g );
count += estimateBytesUsed( g );

} );
str += `<br/>Cache: ${ ( 100 * cacheFullness ).toFixed( 2 ) }% ~${ ( count / 1000 / 1000 ).toFixed( 2 ) }mb`;
str += `Cache: ${ ( 100 * cacheFullness ).toFixed( 2 ) }% ~${ ( count / 1000 / 1000 ).toFixed( 2 ) }mb<br/>`;

}

if ( params.enableRendererStats ) {

const memory = renderer.info.memory;
const programCount = renderer.info.programs.length;
str += `<br/>Geometries: ${ memory.geometries } Textures: ${ memory.textures } Programs: ${ programCount }`;
str += `Geometries: ${ memory.geometries } Textures: ${ memory.textures } Programs: ${ programCount }`;

}

Expand All @@ -303,15 +244,11 @@ function render() {

}

if ( tiles ) {

const mat = tiles.group.matrixWorld.clone().invert();
const vec = camera.position.clone().applyMatrix4( mat );

const res = {};
WGS84_ELLIPSOID.getPositionToCartographic( vec, res );
document.getElementById( 'credits' ).innerText = GeoUtils.toLatLonString( res.lat, res.lon ) + '\n' + tiles.getCreditsString();
const mat = tiles.group.matrixWorld.clone().invert();
const vec = camera.position.clone().applyMatrix4( mat );

}
const res = {};
WGS84_ELLIPSOID.getPositionToCartographic( vec, res );
document.getElementById( 'credits' ).innerText = GeoUtils.toLatLonString( res.lat, res.lon ) + '\n' + tiles.getCreditsString();

}
2 changes: 1 addition & 1 deletion example/src/FadeTilesRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function onTileVisibilityChange( scene, tile, visible ) {

}

if ( ! isRootTile || ! this.fadeRootTiles || this.initialLayerRendered ) {
if ( ! isRootTile || this.fadeRootTiles || this.initialLayerRendered ) {

this._fadeManager.fadeIn( scene );

Expand Down
Loading

0 comments on commit 8111f54

Please sign in to comment.