@jdultra/threedtiles 4.0.0 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,8 @@ The fastest 3DTiles viewer for three.js
10
10
 
11
11
  [Occlusion culling (IFC conversion)](https://www.jdultra.com/occlusion/index.html)
12
12
 
13
+ [Instanced Tileset (pilot a swarm of highly detailed spaceships)](https://www.jdultra.com/instanced/index.html)
14
+
13
15
  Adding a tileset to a scene is as easy as :
14
16
 
15
17
  ```
@@ -42,6 +44,7 @@ Currently, the library is limmited to B3DM files.
42
44
  - Share a cache between tileset instances
43
45
  - Optimal tile load order
44
46
  - Occlusion culling
47
+ - Instanced tilesets
45
48
 
46
49
  ### geometric Error Multiplier
47
50
  The geometric error multiplier allows you to multiply the geometric error by a factor.
@@ -173,6 +176,10 @@ const occlusionCullingService = new OcclusionCullingService();
173
176
  occlusionCullingService.setSide(THREE.DoubleSide);
174
177
  ```
175
178
 
179
+ ### Instanced Tilesets
180
+ Using InstancedTileLoader and InstancedOGC3DTile allows displaying the same Tileset at many different places with little impact on performance.
181
+ Each Tileset is independent in terms of it's position, orientation and level of detail but each tile is created as an "InstancedMesh" giving much
182
+ higher performance when displaying the same Tileset many times.
176
183
 
177
184
  ### static tilesets and other performance tips
178
185
  When you know your tileset will be static, you can specify it in the OGC3DTile object constructor parameter.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jdultra/threedtiles",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "An OGC 3DTiles viewer for Three.js",
5
5
  "main": "tileset.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -11,8 +11,8 @@ import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
11
11
  import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
12
12
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
13
13
 
14
- import { InstancedOGC3DTile} from "./tileset/instanced/InstancedOGC3DTile.js"
15
- import { InstancedTileLoader} from "./tileset/instanced/InstancedTileLoader.js"
14
+ import { InstancedOGC3DTile } from "./tileset/instanced/InstancedOGC3DTile.js"
15
+ import { InstancedTileLoader } from "./tileset/instanced/InstancedTileLoader.js"
16
16
 
17
17
  import { B3DMDecoder } from "./decoder/B3DMDecoder";
18
18
 
@@ -58,12 +58,12 @@ animate();
58
58
 
59
59
  function initComposer(scene, camera, renderer) {
60
60
  const renderScene = new RenderPass(scene, camera);
61
- const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.4, 0.5, 0);
61
+ //const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.4, 0.5, 0);
62
62
 
63
63
 
64
64
  const composer = new EffectComposer(renderer);
65
65
  composer.addPass(renderScene);
66
- composer.addPass(bloomPass);
66
+ //composer.addPass(bloomPass);
67
67
  return composer;
68
68
  }
69
69
  function initScene() {
@@ -71,7 +71,7 @@ function initScene() {
71
71
  scene.matrixAutoUpdate = false;
72
72
  scene.background = new THREE.Color(0x000000);
73
73
  scene.add(new THREE.AmbientLight(0xFFFFFF, 0.2));
74
-
74
+
75
75
  const light = new THREE.PointLight(0xbbbbff, 2, 5000);
76
76
  const sphere = new THREE.SphereGeometry(2, 16, 8);
77
77
  light.add(new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ color: 0xbbbbff })));
@@ -146,9 +146,9 @@ function initTileset(scene) {
146
146
  mesh.material.side = THREE.FrontSide;
147
147
  }, 1000)
148
148
  const ogc3DTile = new OGC3DTile({
149
- url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
150
- //url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
151
- geometricErrorMultiplier: 1.0,
149
+ //url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
150
+ url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
151
+ geometricErrorMultiplier: 0.1,
152
152
  loadOutsideView: false,
153
153
  tileLoader: tileLoader,
154
154
  //occlusionCullingService: occlusionCullingService,
@@ -160,7 +160,7 @@ function initTileset(scene) {
160
160
 
161
161
 
162
162
  //// The OGC3DTile object is a threejs Object3D so you may do all the usual opperations like transformations e.g.:
163
- //ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
163
+ ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
164
164
  //// If the OGC3DTile object is marked as "static" (constructorParameter), these operations will not work.
165
165
 
166
166
 
@@ -201,20 +201,20 @@ function initTileset(scene) {
201
201
  return ogc3DTile;
202
202
  }
203
203
 
204
- function createInstancedTileLoader(scene){
204
+ function createInstancedTileLoader(scene) {
205
205
  return new InstancedTileLoader(scene, mesh => {
206
206
  //// Insert code to be called on every newly decoded mesh e.g.:
207
207
  mesh.material.wireframe = false;
208
208
  mesh.material.side = THREE.FrontSide;
209
209
  }, 1000, 1000);
210
210
  }
211
- function initInstancedTilesets(instancedTileLoader){
211
+ function initInstancedTilesets(instancedTileLoader) {
212
212
 
213
213
  const instancedTilesets = [];
214
214
 
215
- for(let x = 0; x<10; x++){
216
- for(let y = 0; y<10; y++){
217
- for(let z = 0; z<10; z++){
215
+ for (let x = 0; x < 10; x++) {
216
+ for (let y = 0; y < 10; y++) {
217
+ for (let z = 0; z < 10; z++) {
218
218
  const tileset = new InstancedOGC3DTile({
219
219
  url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
220
220
  //url: "http://localhost:8080/tileset.json",
@@ -223,25 +223,29 @@ function initInstancedTilesets(instancedTileLoader){
223
223
  tileLoader: instancedTileLoader,
224
224
  static: false,
225
225
  });
226
- tileset.translateOnAxis(new THREE.Vector3(1, 0, 0), 50*x)
227
- tileset.translateOnAxis(new THREE.Vector3(0, 1, 0), 15*y)
228
- tileset.translateOnAxis(new THREE.Vector3(0, 0, 1), 25*z)
226
+ tileset.rotateOnAxis(new THREE.Vector3(0, 0, 1), 50 * z)
227
+ tileset.translateOnAxis(new THREE.Vector3(1, 0, 0), 50 * x)
228
+ tileset.translateOnAxis(new THREE.Vector3(0, 1, 0), 50 * y)
229
+ tileset.translateOnAxis(new THREE.Vector3(0, 0, 1), 50 * z)
229
230
  scene.add(tileset);
230
231
  instancedTilesets.push(tileset);
231
232
 
232
- idleCallback();
233
233
 
234
- function idleCallback(){
235
- tileset.update(camera);
236
- setTimeout(()=>{
237
- window.requestIdleCallback(idleCallback,{timeout:50})
238
- },20)
239
-
240
- }
241
234
  }
242
235
  }
243
236
  }
244
237
 
238
+ idleCallback();
239
+
240
+ function idleCallback() {
241
+ instancedTilesets.forEach(tileset=>{
242
+ tileset.update(camera);
243
+ })
244
+ setTimeout(() => {
245
+ window.requestIdleCallback(idleCallback, { timeout: 50 })
246
+ }, 20)
247
+
248
+ }
245
249
  initLODMultiplierSlider(instancedTilesets);
246
250
  }
247
251
 
@@ -251,7 +255,7 @@ function initLODMultiplierSlider(instancedTilesets) {
251
255
  output.innerHTML = slider.value;
252
256
 
253
257
  slider.oninput = () => {
254
- instancedTilesets.forEach(tileset=>{
258
+ instancedTilesets.forEach(tileset => {
255
259
  tileset.setGeometricErrorMultiplier(slider.value)
256
260
  })
257
261
  output.innerHTML = slider.value;
@@ -81,7 +81,6 @@ class TileLoader {
81
81
  }
82
82
 
83
83
  getNextDownloads() {
84
- let smallestLevel = Number.MAX_VALUE;
85
84
  let smallestDistance = Number.MAX_VALUE;
86
85
  let closest = -1;
87
86
  for (let i = this.downloads.length - 1; i >= 0; i--) {
@@ -95,13 +94,10 @@ class TileLoader {
95
94
  }
96
95
  if (this.nextDownloads.length > 0) return;
97
96
  for (let i = this.downloads.length - 1; i >= 0; i--) {
98
- const dist = this.downloads[i].distanceFunction();
97
+ const dist = this.downloads[i].distanceFunction()*this.downloads[i].level;
99
98
  if (dist < smallestDistance) {
100
99
  smallestDistance = dist;
101
100
  closest = i;
102
- } else if (dist == smallestDistance && this.downloads[i].level < smallestLevel) {
103
- smallestLevel = this.downloads[i].level;
104
- closest = i
105
101
  }
106
102
  }
107
103
  if (closest >= 0) {
@@ -117,7 +113,6 @@ class TileLoader {
117
113
  }
118
114
 
119
115
  getNextReady() {
120
- let smallestLevel = Number.MAX_VALUE;
121
116
  let smallestDistance = Number.MAX_VALUE;
122
117
  let closest = -1;
123
118
  for (let i = this.ready.length - 1; i >= 0; i--) {
@@ -128,13 +123,9 @@ class TileLoader {
128
123
  }
129
124
  if (this.nextReady.length > 0) return;
130
125
  for (let i = this.ready.length - 1; i >= 0; i--) {
131
- const dist = this.ready[i][3]();
126
+ const dist = this.ready[i][3]() * this.ready[i][5];
132
127
  if (dist < smallestDistance) {
133
128
  smallestDistance = dist;
134
- smallestLevel = this.ready[i][5]
135
- closest = i
136
- } else if (dist == smallestDistance && this.ready[i][5] < smallestLevel) {
137
- smallestLevel = this.ready[i][5]
138
129
  closest = i
139
130
  }
140
131
  }
@@ -110,7 +110,6 @@ class InstancedTileLoader {
110
110
  }
111
111
 
112
112
  getNextReady() {
113
- let smallestLevel = Number.MAX_VALUE;
114
113
  let smallestDistance = Number.MAX_VALUE;
115
114
  let closest = -1;
116
115
  for (let i = this.ready.length - 1; i >= 0; i--) {
@@ -121,13 +120,9 @@ class InstancedTileLoader {
121
120
  }
122
121
  if (this.nextReady.length > 0) return;
123
122
  for (let i = this.ready.length - 1; i >= 0; i--) {
124
- const dist = this.ready[i].distanceFunction();
123
+ const dist = this.ready[i].distanceFunction() * this.ready[i].level;
125
124
  if (dist < smallestDistance) {
126
125
  smallestDistance = dist;
127
- smallestLevel = this.ready[i].level
128
- closest = i
129
- } else if (dist == smallestDistance && this.ready[i].level < smallestLevel) {
130
- smallestLevel = this.ready[i].level
131
126
  closest = i
132
127
  }
133
128
  }
@@ -216,7 +211,6 @@ class InstancedTileLoader {
216
211
 
217
212
 
218
213
  getNextDownloads() {
219
- let smallestLevel = Number.MAX_VALUE;
220
214
  let smallestDistance = Number.MAX_VALUE;
221
215
  let closest = -1;
222
216
  for (let i = this.downloads.length - 1; i >= 0; i--) {
@@ -232,13 +226,10 @@ class InstancedTileLoader {
232
226
  if (this.nextDownloads.length > 0) return;
233
227
  for (let i = this.downloads.length - 1; i >= 0; i--) {
234
228
  const download = this.downloads[i];
235
- const dist = download.distanceFunction();
229
+ const dist = download.distanceFunction()*download.level;
236
230
  if (dist < smallestDistance) {
237
231
  smallestDistance = dist;
238
232
  closest = i;
239
- } else if (dist == smallestDistance && download.level < smallestLevel) {
240
- smallestLevel = download.level;
241
- closest = i
242
233
  }
243
234
  }
244
235
  if (closest >= 0) {
@@ -60,7 +60,7 @@ class MeshTile{
60
60
  self.instancedTiles[i].meshContent = self.instancedMesh;
61
61
  if(self.instancedTiles[i].materialVisibility && !!self.instancedTiles[i].meshContent){
62
62
  self.instancedMesh.count++;
63
- self.instancedMesh.setMatrixAt(self.instancedMesh.count-1, self.reuseableMatrix.multiplyMatrices(self.instancedMesh.baseMatrix, self.instancedTiles[i].getWorldMatrix()) )
63
+ self.instancedMesh.setMatrixAt(self.instancedMesh.count-1, self.reuseableMatrix.multiplyMatrices(self.instancedTiles[i].getWorldMatrix(), self.instancedMesh.baseMatrix) )
64
64
  }
65
65
 
66
66
  }