Skip to content

Commit 03bc725

Browse files
committed
Merge branch 'master' of github.com:NASA-AMMOS/3DTilesRendererJS into master
2 parents 4be4a8b + 379f04c commit 03bc725

File tree

6 files changed

+130
-52
lines changed

6 files changed

+130
-52
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## Unreleased
8+
### Added
9+
- PriorityQueue: Added `schedulingCallback` to afford flexibility in job scheduling callback for scenarios where `requestAnimationFrame` will not work, such as with WebXR.
10+
11+
### Fixed
12+
- `autoDisableRendererCulling` incorrectly applying the inverse of the documented effect.
13+
- Screen space error calculations now use the camera projectionMatrix rather than camera type to determine frustum type.
14+
715
## [0.3.3] - 2021-09-08
816
### Added
917
- Support for embedded tileset / tile geometry URLs with hashes, search query parameters.

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,14 @@ priorityCallback = null : ( itemA, itemB ) => Number
612612

613613
Function to derive the job priority of the given item. Higher priority values get processed first.
614614

615+
### .schedulingCallback
616+
617+
```js
618+
schedulingCallback = requestAnimationFrame : ( cb : Function ) => void
619+
```
620+
621+
A function used for scheduling when to run jobs next so more work doesn't happen in a single frame than there is time for -- defaults to the next frame. This should be overriden in scenarios where requestAnimationFrame is not reliable, such as when running in WebXR. See the VR demo for one example on how to handle this with WebXR.
622+
615623
## LRUCache
616624

617625
Utility class for the TilesRenderer to keep track of currently used items so rendered items will not be unloaded.

example/vr.js

Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ let box, sphere, grid;
4242
let raycaster, fwdVector, intersectRing;
4343
let offsetParent;
4444
let controller, controllerGrip;
45+
let xrSession = null;
46+
let tasks = [];
4547

4648
let params = {
4749

@@ -52,7 +54,6 @@ let params = {
5254
};
5355

5456
init();
55-
animate();
5657

5758
function init() {
5859

@@ -69,6 +70,8 @@ function init() {
6970
document.body.appendChild( renderer.domElement );
7071
renderer.domElement.tabIndex = 1;
7172

73+
renderer.setAnimationLoop( animate );
74+
7275
// create workspace
7376
workspace = new Group();
7477
scene.add( workspace );
@@ -102,6 +105,23 @@ function init() {
102105
tiles = new TilesRenderer( '../data/tileset.json' );
103106
offsetParent.add( tiles.group );
104107

108+
// We set camera for tileset
109+
tiles.setCamera( camera );
110+
tiles.setResolutionFromRenderer( camera, renderer );
111+
112+
113+
// We define a custom scheduling callback to handle also active WebXR sessions
114+
const tilesSchedulingCB = func => {
115+
116+
tasks.push( func );
117+
118+
};
119+
120+
// We set our scheduling callback for tiles downloading and parsing
121+
tiles.downloadQueue.schedulingCallback = tilesSchedulingCB;
122+
tiles.parseQueue.schedulingCallback = tilesSchedulingCB;
123+
124+
105125
// Raycasting init
106126
raycaster = new Raycaster();
107127
fwdVector = new Vector3( 0, 0, 1 );
@@ -206,16 +226,62 @@ function onWindowResize() {
206226

207227
}
208228

209-
function animate() {
229+
function handleCamera() {
230+
231+
// get the XR camera with a combined frustum for culling
232+
if ( renderer.xr.isPresenting ) {
233+
234+
if ( xrSession === null ) { // We setup XR camera once
235+
236+
// remove all cameras so we can use the VR camera instead
237+
tiles.cameras.forEach( c => tiles.deleteCamera( camera ) );
238+
239+
const currCamera = renderer.xr.getCamera( camera );
240+
tiles.setCamera( currCamera );
241+
242+
const leftCam = currCamera.cameras[ 0 ];
243+
if ( leftCam ) {
244+
245+
tiles.setResolution( currCamera, leftCam.viewport.z, leftCam.viewport.w );
246+
247+
}
248+
249+
xrSession = renderer.xr.getSession();
250+
251+
}
252+
253+
} else {
254+
255+
// Reset default camera (exiting WebXR session)
256+
if ( xrSession !== null ) {
257+
258+
tiles.cameras.forEach( c => tiles.deleteCamera( camera ) );
210259

211-
renderer.setAnimationLoop( render );
260+
tiles.setCamera( camera );
261+
tiles.setResolutionFromRenderer( camera, renderer );
262+
263+
camera.position.set( 0, 1, 0 );
264+
265+
xrSession = null;
266+
267+
}
268+
269+
}
212270

213271
}
214272

273+
function handleTasks() {
215274

216-
function render() {
275+
for ( let t = 0, l = tasks.length; t < l; t ++ ) {
217276

218-
requestAnimationFrame( animate );
277+
tasks[ t ]();
278+
279+
}
280+
tasks.length = 0;
281+
282+
}
283+
284+
function animate() {
219285

220286
grid.visible = params.displayGrid;
221287

@@ -236,32 +302,14 @@ function render() {
236302

237303
}
238304

239-
// remove all cameras so we can use the VR camera instead
240-
tiles.cameras.forEach( c => tiles.deleteCamera( camera ) );
305+
// We check for tiles camera setup (default and XR sessions)
306+
handleCamera();
241307

242-
// get the XR camera with a combined frustum for culling
243-
if ( renderer.xr.isPresenting ) {
244-
245-
const currCamera = renderer.xr.getCamera( camera );
246-
tiles.setCamera( currCamera );
247-
248-
const leftCam = currCamera.cameras[ 0 ];
249-
if ( leftCam ) {
250-
251-
tiles.setResolution( currCamera, leftCam.viewport.z, leftCam.viewport.w );
252-
253-
}
254-
255-
} else {
256-
257-
tiles.setCamera( camera );
258-
tiles.setResolutionFromRenderer( camera, renderer );
259-
260-
}
308+
// We handle pending tasks
309+
handleTasks();
261310

262311
tiles.update();
263312

264-
265313
if ( controller.controllerActive ) {
266314

267315
const { ray } = raycaster;

src/three/TilesRenderer.js

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ import {
1010
Sphere,
1111
Vector3,
1212
Vector2,
13-
Math as MathUtils,
1413
Frustum,
1514
LoadingManager
1615
} from 'three';
1716
import { raycastTraverse, raycastTraverseFirstHit } from './raycastTraverse.js';
1817

1918
const INITIAL_FRUSTUM_CULLED = Symbol( 'INITIAL_FRUSTUM_CULLED' );
20-
const DEG2RAD = MathUtils.DEG2RAD;
2119
const tempMat = new Matrix4();
2220
const tempMat2 = new Matrix4();
2321
const tempVector = new Vector3();
@@ -51,13 +49,9 @@ export class TilesRenderer extends TilesRendererBase {
5149
if ( this._autoDisableRendererCulling !== value ) {
5250

5351
super._autoDisableRendererCulling = value;
54-
this.traverse( tile => {
52+
this.forEachLoadedModel( ( scene ) => {
5553

56-
if ( tile.scene ) {
57-
58-
updateFrustumCulled( tile.scene, value );
59-
60-
}
54+
updateFrustumCulled( scene, ! value );
6155

6256
} );
6357

@@ -355,10 +349,11 @@ export class TilesRenderer extends TilesRendererBase {
355349
cameraInfo.push( {
356350

357351
frustum: new Frustum(),
358-
sseDenominator: - 1,
352+
isOrthographic: false,
353+
sseDenominator: - 1, // used if isOrthographic:false
359354
position: new Vector3(),
360355
invScale: - 1,
361-
pixelSize: 0,
356+
pixelSize: 0, // used if isOrthographic:true
362357

363358
} );
364359

@@ -392,18 +387,26 @@ export class TilesRenderer extends TilesRendererBase {
392387

393388
}
394389

395-
if ( camera.isPerspectiveCamera ) {
396-
397-
info.sseDenominator = 2 * Math.tan( 0.5 * camera.fov * DEG2RAD ) / resolution.height;
390+
// Read the calculated projection matrix directly to support custom Camera implementations
391+
const projection = camera.projectionMatrix.elements;
398392

399-
}
393+
// The last element of the projection matrix is 1 for orthographic, 0 for perspective
394+
info.isOrthographic = projection[ 15 ] === 1;
400395

401-
if ( camera.isOrthographicCamera ) {
396+
if ( info.isOrthographic ) {
402397

403-
const w = camera.right - camera.left;
404-
const h = camera.top - camera.bottom;
398+
// See OrthographicCamera.updateProjectionMatrix and Matrix4.makeOrthographic:
399+
// the view width and height are used to populate matrix elements 0 and 5.
400+
const w = 2 / projection[ 0 ];
401+
const h = 2 / projection[ 5 ];
405402
info.pixelSize = Math.max( h / resolution.height, w / resolution.width );
406403

404+
} else {
405+
406+
// See PerspectiveCamera.updateProjectionMatrix and Matrix4.makePerspective:
407+
// the vertical FOV is used to populate matrix element 5.
408+
info.sseDenominator = ( 2 / projection[ 5 ] ) / resolution.height;
409+
407410
}
408411

409412
info.invScale = invScale;
@@ -673,7 +676,7 @@ export class TilesRenderer extends TilesRendererBase {
673676
c[ INITIAL_FRUSTUM_CULLED ] = c.frustumCulled;
674677

675678
} );
676-
updateFrustumCulled( scene, this.autoDisableRendererCulling );
679+
updateFrustumCulled( scene, ! this.autoDisableRendererCulling );
677680

678681
cached.scene = scene;
679682

@@ -842,12 +845,11 @@ export class TilesRenderer extends TilesRendererBase {
842845
}
843846

844847
// transform camera position into local frame of the tile bounding box
845-
const camera = cameras[ i ];
846848
const info = cameraInfo[ i ];
847849
const invScale = info.invScale;
848850

849851
let error;
850-
if ( camera.isOrthographicCamera ) {
852+
if ( info.isOrthographic ) {
851853

852854
const pixelSize = info.pixelSize;
853855
error = tile.geometricError / ( pixelSize * invScale );

src/utilities/PriorityQueue.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ export class PriorityQueue {
33
maxJobs : Number;
44
autoUpdate : Boolean;
55
priorityCallback : ( itemA : any , itemB : any ) => Number;
6+
7+
schedulingCallback : ( func : Function ) => void;
68

79
sort() : void;
810
add( item : any, callback : ( item : any ) => any ) : Promise< any >;

src/utilities/PriorityQueue.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,20 @@ class PriorityQueue {
1717

1818
};
1919

20+
// Customizable scheduling callback. Default using requestAnimationFrame()
21+
this.schedulingCallback = func => {
22+
23+
requestAnimationFrame( func );
24+
25+
};
26+
27+
this._runjobs = () => {
28+
29+
this.tryRunJobs();
30+
this.scheduled = false;
31+
32+
};
33+
2034
}
2135

2236
sort() {
@@ -110,12 +124,8 @@ class PriorityQueue {
110124

111125
if ( ! this.scheduled ) {
112126

113-
requestAnimationFrame( () => {
114-
115-
this.tryRunJobs();
116-
this.scheduled = false;
127+
this.schedulingCallback( this._runjobs );
117128

118-
} );
119129
this.scheduled = true;
120130

121131
}

0 commit comments

Comments
 (0)