@jdultra/threedtiles 4.0.4 → 5.1.0

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
@@ -20,7 +20,8 @@ import { OGC3DTile } from "./tileset/OGC3DTile";
20
20
  ...
21
21
 
22
22
  const ogc3DTile = new OGC3DTile({
23
- url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json"
23
+ url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
24
+ renderer: renderer
24
25
  });
25
26
 
26
27
  scene.add(ogc3DTile);
@@ -56,6 +57,7 @@ you may also set this value at initialization:
56
57
  ```
57
58
  const ogc3DTile = new OGC3DTile({
58
59
  url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
60
+ renderer: renderer,
59
61
  geometricErrorMultiplier: 2.0
60
62
  });
61
63
  ```
@@ -66,11 +68,12 @@ A value of 1.0 is the default.
66
68
 
67
69
  ### load tiles outside of view
68
70
  By default, only the tiles that intersect the view frustum are loaded. When the camera moves, the scene will have to load the missing tiles and the user might see some holes in the model.
69
- Instead of this behaviour, you can force the lowest possible LODs to be loaded for tiles outside the view so that there are no gaps in the mesh when the camera moves. This also allows displaying shadows correctly.
71
+ Instead of this behaviour, you can force the lowest possible LODs to be loaded for tiles outside the view so that there are no gaps in the mesh when the camera moves. This also allows displaying shadows from parts of the scene that are not in the view.
70
72
 
71
73
  ```
72
74
  const ogc3DTile = new OGC3DTile({
73
75
  url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
76
+ renderer: renderer,
74
77
  loadOutsideView: true
75
78
  });
76
79
  ```
@@ -84,6 +87,7 @@ This can be useful to position the tileset at a specific location when it is not
84
87
  ```
85
88
  const ogc3DTile = new OGC3DTile({
86
89
  url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
90
+ renderer: renderer,
87
91
  onLoadCallback: tilese => {
88
92
  console.log(tileset.boundingVolume);
89
93
  }
@@ -96,6 +100,7 @@ Add a callback on loaded tiles in order to set a material or do some logic on th
96
100
  ```
97
101
  const ogc3DTile = new OGC3DTile({
98
102
  url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
103
+ renderer: renderer,
99
104
  meshCallback: mesh => {
100
105
  mesh.material.wireframe = true;
101
106
  mesh.material.side = THREE.DoubleSide;
@@ -116,6 +121,7 @@ import { TileLoader } from "@jdultra/threedtiles/src/tileset/TileLoader";
116
121
 
117
122
  const ogc3DTile = new OGC3DTile({
118
123
  url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
124
+ renderer: renderer,
119
125
  tileLoader: new TileLoader(mesh => {
120
126
  //// Insert code to be called on every newly decoded mesh e.g.:
121
127
  mesh.material.wireframe = false;
@@ -133,6 +139,7 @@ The OGC 3DTile object is a regular three.js Object3D so it can be transformed vi
133
139
  ```
134
140
  const ogc3DTile = new OGC3DTile({
135
141
  url: "https://ebeaufay.github.io/ThreedTilesViewer.github.io/momoyama/tileset.json"
142
+ renderer: renderer,
136
143
  });
137
144
 
138
145
  ogc3DTile.translateOnAxis(new THREE.Vector3(0,1,0), -450);
@@ -156,6 +163,7 @@ This service must be passed to every OGC3DTiles object like so:
156
163
  ```
157
164
  const ogc3DTile = new OGC3DTile({
158
165
  url: "path/to/tileset.json",
166
+ renderer: renderer,
159
167
  occlusionCullingService: occlusionCullingService
160
168
  });
161
169
  ```
@@ -201,11 +209,12 @@ const instancedTileLoader = new InstancedTileLoader(scene, mesh => {
201
209
  const instancedTilesets = [];
202
210
  for (let i = 0; i < 100; i++) {
203
211
  const tileset = new InstancedOGC3DTile({
204
- url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
205
- geometricErrorMultiplier: 1.0,
206
- loadOutsideView: false,
207
- tileLoader: instancedTileLoader,
208
- static: true // when static is set to true, don't forget to call InstancedOGC3DTile#updateMatrix manually
212
+ url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
213
+ renderer: renderer,
214
+ geometricErrorMultiplier: 1.0,
215
+ loadOutsideView: false,
216
+ tileLoader: instancedTileLoader,
217
+ static: true // when static is set to true, don't forget to call InstancedOGC3DTile#updateMatrix manually
209
218
  });
210
219
 
211
220
  tileset.translateOnAxis(new THREE.Vector3(1, 0, 0), 50 * i);
@@ -238,6 +247,7 @@ This will skip recalculating the transformation matrix of every tile each frame
238
247
  ```
239
248
  const ogc3DTile = new OGC3DTile({
240
249
  url: "path/to/tileset.json",
250
+ renderer: renderer,
241
251
  static: true
242
252
  });
243
253
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jdultra/threedtiles",
3
- "version": "4.0.4",
3
+ "version": "5.1.0",
4
4
  "description": "An OGC 3DTiles viewer for Three.js",
5
5
  "main": "tileset.js",
6
6
  "scripts": {
@@ -31,15 +31,15 @@
31
31
  "path-browserify": "^1.0.1",
32
32
  "regenerator-runtime": "^0.13.11",
33
33
  "set-interval-async": "^2.0.3",
34
- "three": "0.146.0",
34
+ "three": "0.148.0",
35
35
  "uuid": "^8.3.2"
36
36
  },
37
37
  "devDependencies": {
38
- "@babel/core": "^7.20.2",
38
+ "@babel/core": "^7.20.12",
39
39
  "@babel/preset-env": "^7.20.2",
40
40
  "babel-loader": "^8.3.0",
41
41
  "copy-webpack-plugin": "^6.3.2",
42
- "core-js": "^3.26.1",
42
+ "core-js": "^3.27.1",
43
43
  "html-loader": "^1.3.2",
44
44
  "html-webpack-plugin": "^4.5.0",
45
45
  "mini-css-extract-plugin": "^1.6.2",
@@ -1,9 +1,11 @@
1
1
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
2
2
  import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
3
3
  import * as THREE from 'three';
4
+ import {FeatureTable, BatchTable} from './FeatureTable';
4
5
 
5
6
  const gltfLoader = new GLTFLoader();
6
7
  const dracoLoader = new DRACOLoader();
8
+ const tempMatrix = new THREE.Matrix4();
7
9
  dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.4.3/');
8
10
  gltfLoader.setDRACOLoader(dracoLoader);
9
11
  const dummy = new THREE.Object3D();
@@ -31,10 +33,10 @@ function parseB3DM(arrayBuffer, meshCallback) {
31
33
  const batchTableBinaryByteLength = dataView.getUint32(24, true);
32
34
 
33
35
  const featureTableStart = 28;
34
- //const featureTable = new FeatureTable( arrayBuffer, featureTableStart, featureTableJSONByteLength, featureTableBinaryByteLength );
36
+ const featureTable = new FeatureTable(arrayBuffer, featureTableStart, featureTableJSONByteLength, featureTableBinaryByteLength);
35
37
 
36
38
  const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength;
37
- //const batchTable = new BatchTable( arrayBuffer, featureTable.getData( 'BATCH_LENGTH' ), batchTableStart, batchTableJSONByteLength, batchTableBinaryByteLength );
39
+ const batchTable = new BatchTable(arrayBuffer, featureTable.getData('BATCH_LENGTH'), batchTableStart, batchTableJSONByteLength, batchTableBinaryByteLength);
38
40
 
39
41
  const glbStart = batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength;
40
42
  const glbBytes = new Uint8Array(arrayBuffer, glbStart, byteLength - glbStart);
@@ -48,6 +50,7 @@ function parseB3DM(arrayBuffer, meshCallback) {
48
50
  gltfLoader.parse(gltfBuffer, null, model => {
49
51
 
50
52
  ////TODO
53
+
51
54
  //model.batchTable = b3dm.batchTable;
52
55
  //model.featureTable = b3dm.featureTable;
53
56
 
@@ -55,6 +58,15 @@ function parseB3DM(arrayBuffer, meshCallback) {
55
58
  //model.scene.featureTable = b3dm.featureTable;
56
59
 
57
60
  //const scene = mergeColoredObject(model.scene);
61
+
62
+ //model.scene.applyMatrix4(ytozUpMatrix);
63
+
64
+ const rtcCenter = featureTable.getData('RTC_CENTER');
65
+ if (rtcCenter) {
66
+ tempMatrix.makeTranslation(rtcCenter[0], rtcCenter[2], -rtcCenter[1])
67
+ model.scene.applyMatrix4(tempMatrix);
68
+ }
69
+
58
70
  model.scene.traverse((o) => {
59
71
  if (o.isMesh) {
60
72
  if (!!meshCallback) {
@@ -76,11 +88,11 @@ const B3DMDecoder = {
76
88
 
77
89
  return parseB3DM(arrayBuffer, meshCallback).then(mesh => {
78
90
  let instancedMesh;
91
+ mesh.updateWorldMatrix(false, true)
79
92
  mesh.traverse(child => {
80
93
  if (child.isMesh) {
81
94
  instancedMesh = new THREE.InstancedMesh(child.geometry, child.material, maxCount);
82
- instancedMesh.baseMatrix = child.matrix;
83
- //console.log(child.matrix.elements[12])
95
+ instancedMesh.baseMatrix = child.matrixWorld;
84
96
  }
85
97
  });
86
98
  return instancedMesh;
@@ -0,0 +1,169 @@
1
+ /**
2
+ * This class is taken straight from NASA-AMMOS library.
3
+ * https://github.com/NASA-AMMOS/3DTilesRendererJS/blob/master/src/utilities/FeatureTable.js
4
+ */
5
+
6
+ const utf8decoder = new TextDecoder();
7
+ export class FeatureTable {
8
+
9
+ constructor(buffer, start, headerLength, binLength) {
10
+
11
+ this.buffer = buffer;
12
+ this.binOffset = start + headerLength;
13
+ this.binLength = binLength;
14
+
15
+ let header = null;
16
+ if (headerLength !== 0) {
17
+
18
+ try {
19
+ const headerData = new Uint8Array(buffer, start, headerLength);
20
+ header = JSON.parse(utf8decoder.decode(headerData));
21
+ } catch (e) {
22
+ header = {};
23
+ }
24
+
25
+ } else {
26
+
27
+ header = {};
28
+
29
+ }
30
+ this.header = header;
31
+
32
+ }
33
+
34
+ getKeys() {
35
+
36
+ return Object.keys(this.header);
37
+
38
+ }
39
+
40
+ getData(key, count, defaultComponentType = null, defaultType = null) {
41
+
42
+ const header = this.header;
43
+
44
+ if (!(key in header)) {
45
+
46
+ return null;
47
+
48
+ }
49
+
50
+ const feature = header[key];
51
+ if (!(feature instanceof Object)) {
52
+
53
+ return feature;
54
+
55
+ } else if (Array.isArray(feature)) {
56
+
57
+ return feature;
58
+
59
+ } else {
60
+
61
+ const { buffer, binOffset, binLength } = this;
62
+ const byteOffset = feature.byteOffset || 0;
63
+ const featureType = feature.type || defaultType;
64
+ const featureComponentType = feature.componentType || defaultComponentType;
65
+
66
+ if ('type' in feature && defaultType && feature.type !== defaultType) {
67
+
68
+ throw new Error('FeatureTable: Specified type does not match expected type.');
69
+
70
+ }
71
+
72
+ let stride;
73
+ switch (featureType) {
74
+
75
+ case 'SCALAR':
76
+ stride = 1;
77
+ break;
78
+
79
+ case 'VEC2':
80
+ stride = 2;
81
+ break;
82
+
83
+ case 'VEC3':
84
+ stride = 3;
85
+ break;
86
+
87
+ case 'VEC4':
88
+ stride = 4;
89
+ break;
90
+
91
+ default:
92
+ throw new Error(`FeatureTable : Feature type not provided for "${key}".`);
93
+
94
+ }
95
+
96
+ let data;
97
+ const arrayStart = binOffset + byteOffset;
98
+ const arrayLength = count * stride;
99
+
100
+ switch (featureComponentType) {
101
+
102
+ case 'BYTE':
103
+ data = new Int8Array(buffer, arrayStart, arrayLength);
104
+ break;
105
+
106
+ case 'UNSIGNED_BYTE':
107
+ data = new Uint8Array(buffer, arrayStart, arrayLength);
108
+ break;
109
+
110
+ case 'SHORT':
111
+ data = new Int16Array(buffer, arrayStart, arrayLength);
112
+ break;
113
+
114
+ case 'UNSIGNED_SHORT':
115
+ data = new Uint16Array(buffer, arrayStart, arrayLength);
116
+ break;
117
+
118
+ case 'INT':
119
+ data = new Int32Array(buffer, arrayStart, arrayLength);
120
+ break;
121
+
122
+ case 'UNSIGNED_INT':
123
+ data = new Uint32Array(buffer, arrayStart, arrayLength);
124
+ break;
125
+
126
+ case 'FLOAT':
127
+ data = new Float32Array(buffer, arrayStart, arrayLength);
128
+ break;
129
+
130
+ case 'DOUBLE':
131
+ data = new Float64Array(buffer, arrayStart, arrayLength);
132
+ break;
133
+
134
+ default:
135
+ throw new Error(`FeatureTable : Feature component type not provided for "${key}".`);
136
+
137
+ }
138
+
139
+ const dataEnd = arrayStart + arrayLength * data.BYTES_PER_ELEMENT;
140
+ if (dataEnd > binOffset + binLength) {
141
+
142
+ throw new Error('FeatureTable: Feature data read outside binary body length.');
143
+
144
+ }
145
+
146
+ return data;
147
+
148
+ }
149
+
150
+ }
151
+
152
+ }
153
+
154
+ export class BatchTable extends FeatureTable {
155
+
156
+ constructor(buffer, batchSize, start, headerLength, binLength) {
157
+
158
+ super(buffer, start, headerLength, binLength);
159
+ this.batchSize = batchSize;
160
+
161
+ }
162
+
163
+ getData(key, componentType = null, type = null) {
164
+
165
+ return super.getData(key, this.batchSize, componentType, type);
166
+
167
+ }
168
+
169
+ }
package/src/index.js CHANGED
@@ -14,43 +14,23 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
14
14
  import { InstancedOGC3DTile } from "./tileset/instanced/InstancedOGC3DTile.js"
15
15
  import { InstancedTileLoader } from "./tileset/instanced/InstancedTileLoader.js"
16
16
 
17
- import { B3DMDecoder } from "./decoder/B3DMDecoder";
18
17
 
19
18
  const occlusionCullingService = new OcclusionCullingService();
20
19
  occlusionCullingService.setSide(THREE.DoubleSide);
21
20
  const scene = initScene();
22
21
 
23
22
  const domContainer = initDomContainer("screen");
24
- const camera = initCamera();
25
- //const ogc3DTiles = initTileset(scene);
26
-
27
-
28
- const instancedTileLoader = createInstancedTileLoader(scene);
29
- initInstancedTilesets(instancedTileLoader);
30
-
31
- const controller = initController(camera, domContainer);
32
-
23
+ const camera = initCamera(domContainer.offsetWidth, domContainer.offsetHeight);
33
24
  const stats = initStats(domContainer);
34
25
  const renderer = initRenderer(camera, domContainer);
35
- const composer = initComposer(scene, camera, renderer);
26
+ const ogc3DTiles = initTileset(scene, 1.0);
36
27
 
28
+ //const instancedTileLoader = createInstancedTileLoader(scene);
29
+ //initInstancedTilesets(instancedTileLoader);
37
30
 
38
- /* fetch("https://storage.googleapis.com/ogc-3d-tiles/droneship/1/2007.b3dm").then(result => {
39
-
40
- if (!result.ok) {
41
- console.error("could not load tile with path : " + path)
42
- throw new Error(`couldn't load "${path}". Request failed with status ${result.status} : ${result.statusText}`);
43
- }
44
- return result.arrayBuffer();
31
+ const controller = initController(camera, domContainer);
45
32
 
46
- })
47
- .then(resultArrayBuffer=>{
48
- return B3DMDecoder.parseB3DMInstanced(resultArrayBuffer, self.meshCallback, 1);
49
- })
50
- .then(mesh=>{
51
- scene.add(mesh)
52
-
53
- }) */
33
+ const composer = initComposer(scene, camera, renderer);
54
34
 
55
35
 
56
36
  animate();
@@ -69,11 +49,11 @@ function initComposer(scene, camera, renderer) {
69
49
  function initScene() {
70
50
  const scene = new THREE.Scene();
71
51
  scene.matrixAutoUpdate = false;
72
- scene.matrixWorldAutoUpdate = false;
73
- scene.background = new THREE.Color(0x000000);
52
+ //scene.matrixWorldAutoUpdate = false;
53
+ scene.background = new THREE.Color(0xffffff);
74
54
  scene.add(new THREE.AmbientLight(0xFFFFFF, 1.0));
75
55
 
76
- /*const light = new THREE.PointLight(0xbbbbff, 2, 5000);
56
+ /* const light = new THREE.PointLight(0xbbbbff, 2, 5000);
77
57
  const sphere = new THREE.SphereGeometry(2, 16, 8);
78
58
  light.add(new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ color: 0xbbbbff })));
79
59
  scene.add(light);
@@ -84,9 +64,9 @@ function initScene() {
84
64
  const sphere2 = new THREE.SphereGeometry(2, 16, 8);
85
65
  light2.add(new THREE.Mesh(sphere2, new THREE.MeshBasicMaterial({ color: 0xffbbbb })));
86
66
  scene.add(light2);
87
- light2.position.set(200, 100, -100);*/
67
+ light2.position.set(200, 100, -100); */
68
+
88
69
 
89
-
90
70
  return scene;
91
71
  }
92
72
 
@@ -132,114 +112,85 @@ function initStats(dom) {
132
112
  }
133
113
 
134
114
 
135
- function initCamera() {
136
- const camera = new THREE.PerspectiveCamera(70, window.offsetWidth / window.offsetHeight, 1.0, 100000);
137
- camera.position.set(-800, 800, 800);
115
+ function initCamera(width, height) {
116
+ const camera = new THREE.PerspectiveCamera(60, width / height, 1, 100000);
117
+ camera.position.set(10000,0,0);
118
+ camera.lookAt(0,0,0);
119
+
138
120
  camera.matrixAutoUpdate = true;
139
121
  return camera;
140
122
  }
141
123
 
142
- function initTileset(scene) {
124
+ function initTileset(scene, gem) {
143
125
 
144
126
  const tileLoader = new TileLoader(mesh => {
145
127
  //// Insert code to be called on every newly decoded mesh e.g.:
146
128
  mesh.material.wireframe = false;
147
129
  mesh.material.side = THREE.DoubleSide;
148
- }, 1000)
130
+ mesh.material.metalness = 0.0
131
+ }, 100)
149
132
  const ogc3DTile = new OGC3DTile({
150
- //url: "http://localhost:8080/tileset.json",
151
- //url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
152
- url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
153
- //url: "https://s3.eu-central-2.wasabisys.com/construkted-assets-eu/ands2ty8orz/tileset.json",
154
- geometricErrorMultiplier: 0.01,
133
+ //url: "https://sampledata.luciad.com/data/ogc3dtiles/LucerneAirborneMesh/tileset.json",
134
+ url: "https://sampleservices.luciad.com/ogc/3dtiles/marseille-mesh/tileset.json",
135
+ //url: "https://storage.googleapis.com/ogc-3d-tiles/baltimore/tileset.json",
136
+ //url: "http://localhost:8082/tileset.json",
137
+ geometricErrorMultiplier: gem,
155
138
  loadOutsideView: false,
156
139
  tileLoader: tileLoader,
157
140
  //occlusionCullingService: occlusionCullingService,
158
141
  static: false,
142
+ centerModel:true,
143
+ renderer: renderer
159
144
 
160
145
  });
146
+ setIntervalAsync(function () {
147
+ ogc3DTile.update(camera);
148
+ }, 20);
149
+ //ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
150
+ //ogc3DTile.translateOnAxis(new THREE.Vector3(0, 0, 1), 1)
151
+ /*
152
+ ogc3DTile.translateOnAxis(new THREE.Vector3(0, 0, 1), 10) // Z-UP to Y-UP
153
+ ogc3DTile.translateOnAxis(new THREE.Vector3(0, 1, 0), 18.5) // Z-UP to Y-UP */
154
+ scene.add(ogc3DTile);
161
155
 
162
-
163
-
164
-
165
- //// The OGC3DTile object is a threejs Object3D so you may do all the usual opperations like transformations e.g.:
166
- ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
167
- //ogc3DTile.scale.set(10.0,10.0,10.0)
168
- //// If the OGC3DTile object is marked as "static" (constructorParameter), these operations will not work.
169
-
170
-
171
-
172
- //// It's up to the user to call updates on the tileset. You might call them whenever the camera moves or at regular time intervals like here
173
-
174
-
175
-
176
- var interval;
177
- document.addEventListener('keyup', (e) => {
178
- console.log(camera.position)
179
- if (!!e.key && e.key !== "p") {
180
-
181
- if (!!interval) {
182
- clearInterval(interval);
183
- interval = null;
184
- } else {
185
- startInterval();
186
- }
187
- }
188
- if (!!e.key && e.key !== "l") {
189
-
190
- console.log("new THREE.Vector3(" + camera.position.x + "," + camera.position.y + "," + camera.position.z + ")");
191
- console.log("new THREE.Quaternion(" + camera.quaternion.x + "," + camera.quaternion.y + "," + camera.quaternion.z + "," + camera.quaternion.w + ")");
192
-
193
- }
194
-
195
- });
196
- function startInterval() {
197
- interval = setIntervalAsync(function () {
198
- ogc3DTile.update(camera);
199
-
200
- }, 20);
201
- }
202
- startInterval();
203
-
204
- scene.add(ogc3DTile)
205
156
  return ogc3DTile;
206
157
  }
207
158
 
159
+
208
160
  function createInstancedTileLoader(scene) {
209
161
  return new InstancedTileLoader(scene, mesh => {
210
162
  //// Insert code to be called on every newly decoded mesh e.g.:
211
163
  mesh.material.wireframe = false;
212
164
  mesh.material.side = THREE.DoubleSide;
213
- }, 1000, 3375);
165
+ mesh.material.metalness = 0.0;
166
+ }, 0, 1);
214
167
  }
215
168
  function initInstancedTilesets(instancedTileLoader) {
216
169
 
170
+ /*new GLTFLoader().load('http://localhost:8080/test.glb', function ( gltf ) {
171
+ scene.add(gltf.scene);
172
+ } );*/
173
+
217
174
  const instancedTilesets = [];
218
175
 
219
- for (let x = 0; x < 15; x++) {
220
- for (let y = 0; y < 15; y++) {
221
- for (let z = 0; z < 15; z++) {
222
- const tileset = new InstancedOGC3DTile({
223
- url: "https://storage.googleapis.com/ogc-3d-tiles/droneship/tileset.json",
224
- //url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
225
- //url: "http://localhost:8080/tileset.json",
226
- geometricErrorMultiplier: 1.0,
227
- loadOutsideView: true,
228
- tileLoader: instancedTileLoader,
229
- static: true,
230
- });
231
- //tileset.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
232
- tileset.translateOnAxis(new THREE.Vector3(1, 0, 0), 50 * x)
233
- tileset.translateOnAxis(new THREE.Vector3(0, 1, 0), 50 * y)
234
- tileset.translateOnAxis(new THREE.Vector3(0, 0, 1), 50 * z)
235
- tileset.updateMatrix()
236
- scene.add(tileset);
237
- instancedTilesets.push(tileset);
238
-
239
-
240
- }
241
- }
242
- }
176
+
177
+ const tileset = new InstancedOGC3DTile({
178
+ //url: "https://storage.googleapis.com/ogc-3d-tiles/berlinTileset/tileset.json",
179
+ //url: "https://sampleservices.luciad.com/ogc/3dtiles/marseille-mesh/tileset.json",
180
+ //url: "https://s3.eu-central-2.wasabisys.com/construkted-assets-eu/ab13lasdc9i/tileset.json",
181
+ url: "http://localhost:8081/tileset.json",
182
+ geometricErrorMultiplier: 1.0,
183
+ loadOutsideView: true,
184
+ tileLoader: instancedTileLoader,
185
+ static: false,
186
+ centerModel:true,
187
+ renderer: renderer
188
+ });
189
+ //tileset.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * -0.5) // Z-UP to Y-UP
190
+
191
+ tileset.updateMatrix()
192
+ scene.add(tileset);
193
+ instancedTilesets.push(tileset);
243
194
 
244
195
  scene.updateMatrixWorld(true)
245
196
  function now() {
@@ -248,14 +199,14 @@ function initInstancedTilesets(instancedTileLoader) {
248
199
  let updateIndex = 0;
249
200
  setInterval(() => {
250
201
  let startTime = now();
251
- do{
202
+ do {
252
203
  const frustum = new THREE.Frustum();
253
204
  frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
254
205
  instancedTilesets[updateIndex].update(camera, frustum);
255
- updateIndex= (updateIndex+1)%instancedTilesets.length;
256
- }while(updateIndex < instancedTilesets.length && now()-startTime<4);
257
- },40);
258
-
206
+ updateIndex = (updateIndex + 1) % instancedTilesets.length;
207
+ } while (updateIndex < instancedTilesets.length && now() - startTime < 4);
208
+ }, 40);
209
+
259
210
  //initLODMultiplierSlider(instancedTilesets);
260
211
  }
261
212
 
@@ -266,7 +217,7 @@ function initLODMultiplierSlider(instancedTilesets) {
266
217
 
267
218
  slider.oninput = () => {
268
219
  instancedTilesets.forEach(tileset => {
269
- tileset.setGeometricErrorMultiplier(slider.value*0.1)
220
+ tileset.setGeometricErrorMultiplier(slider.value * 0.1)
270
221
  })
271
222
  output.innerHTML = slider.value;
272
223
  }
@@ -275,8 +226,11 @@ function initLODMultiplierSlider(instancedTilesets) {
275
226
  function initController(camera, dom) {
276
227
  const controller = new OrbitControls(camera, dom);
277
228
 
278
- controller.target.set(0, 0, 0);
279
- controller.minDistance = 0.01;
229
+ controller.target.set(0,0,0);
230
+ //controller.target.set(0,0,0);
231
+
232
+
233
+ controller.minDistance = 0.1;
280
234
  controller.maxDistance = 100000;
281
235
  controller.update();
282
236
  return controller;
@@ -285,7 +239,7 @@ function initController(camera, dom) {
285
239
 
286
240
  function animate() {
287
241
  requestAnimationFrame(animate);
288
- instancedTileLoader.update();
242
+ //instancedTileLoader.update();
289
243
  composer.render();
290
244
  //occlusionCullingService.update(scene, renderer, camera)
291
245
  stats.update();
@@ -5,8 +5,12 @@ import { v4 as uuidv4 } from "uuid";
5
5
  import * as path from "path-browserify"
6
6
  import { clamp } from "three/src/math/MathUtils";
7
7
 
8
- const tempSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0, 1));
9
-
8
+ const tempSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0), 1);
9
+ const tempVec1 = new THREE.Vector3(0, 0, 0);
10
+ const tempVec2 = new THREE.Vector3(0, 0, 0);
11
+ const upVector = new THREE.Vector3(0, 1, 0);
12
+ const rendererSize = new THREE.Vector2();
13
+ const tempQuaternion = new THREE.Quaternion();
10
14
 
11
15
  class OGC3DTile extends THREE.Object3D {
12
16
 
@@ -27,7 +31,9 @@ class OGC3DTile extends THREE.Object3D {
27
31
  * parentTile: OGC3DTile,
28
32
  * onLoadCallback: function,
29
33
  * occlusionCullingService: OcclusionCullingService,
30
- * static: Boolean
34
+ * static: Boolean,
35
+ * centerModel: Boolean
36
+ * renderer: Renderer
31
37
  * } properties
32
38
  */
33
39
  constructor(properties) {
@@ -43,10 +49,11 @@ class OGC3DTile extends THREE.Object3D {
43
49
  mesh.material.wireframe = false;
44
50
  mesh.material.side = THREE.DoubleSide;
45
51
  } : properties.meshCallback);
46
- }
47
- // set properties general to the entire tileset
48
- this.geometricErrorMultiplier = !!properties.geometricErrorMultiplier ? properties.geometricErrorMultiplier : 1.0;
49
-
52
+ }
53
+ // set properties general to the entire tileset
54
+ this.geometricErrorMultiplier = !!properties.geometricErrorMultiplier ? properties.geometricErrorMultiplier : 1.0;
55
+
56
+ this.renderer = properties.renderer;
50
57
  this.meshCallback = properties.meshCallback;
51
58
  this.loadOutsideView = properties.loadOutsideView;
52
59
  this.cameraOnLoad = properties.cameraOnLoad;
@@ -58,9 +65,10 @@ class OGC3DTile extends THREE.Object3D {
58
65
  this.color.setHex(Math.random() * 0xffffff);
59
66
  this.colorID = clamp(self.color.r * 255, 0, 255) << 16 ^ clamp(self.color.g * 255, 0, 255) << 8 ^ clamp(self.color.b * 255, 0, 255) << 0;
60
67
  }
61
- if(this.static){
68
+ if (this.static) {
62
69
  this.matrixAutoUpdate = false;
63
70
  }
71
+
64
72
  // declare properties specific to the tile for clarity
65
73
  this.childrenTiles = [];
66
74
  this.meshContent;
@@ -82,6 +90,7 @@ class OGC3DTile extends THREE.Object3D {
82
90
  if (!!properties.json) { // If this tile is created as a child of another tile, properties.json is not null
83
91
  self.setup(properties);
84
92
  if (properties.onLoadCallback) properties.onLoadCallback(self);
93
+
85
94
  } else if (properties.url) { // If only the url to the tileset.json is provided
86
95
  fetch(properties.url, { signal: self.abortController.signal }).then(result => {
87
96
  if (!result.ok) {
@@ -90,6 +99,34 @@ class OGC3DTile extends THREE.Object3D {
90
99
  result.json().then(json => {
91
100
  self.setup({ rootPath: path.dirname(properties.url), json: json });
92
101
  if (properties.onLoadCallback) properties.onLoadCallback(self);
102
+ if (!!properties.centerModel) {
103
+ const tempSphere = new THREE.Sphere();
104
+ if (self.boundingVolume instanceof OBB) {
105
+ // box
106
+ tempSphere.copy(self.boundingVolume.sphere);
107
+ } else if (self.boundingVolume instanceof THREE.Sphere) {
108
+ //sphere
109
+ tempSphere.copy(self.boundingVolume);
110
+ }
111
+
112
+ //tempSphere.applyMatrix4(self.matrixWorld);
113
+ if (!!this.json.boundingVolume.region) {
114
+ this.transformWGS84ToCartesian(
115
+ (this.json.boundingVolume.region[0] + this.json.boundingVolume.region[2]) * 0.5,
116
+ (this.json.boundingVolume.region[1] + this.json.boundingVolume.region[3]) * 0.5,
117
+ (this.json.boundingVolume.region[4] + this.json.boundingVolume.region[5]) * 0.5,
118
+ tempVec1);
119
+ tempVec2.set(tempVec1.x, tempVec1.z, -tempVec1.y);
120
+
121
+ tempQuaternion.setFromUnitVectors(tempVec2.normalize(), upVector.normalize());
122
+ self.applyQuaternion(tempQuaternion);
123
+ }
124
+
125
+ self.translateX(-tempSphere.center.x * self.scale.x);
126
+ self.translateY(-tempSphere.center.y * self.scale.y);
127
+ self.translateZ(-tempSphere.center.z * self.scale.z);
128
+
129
+ }
93
130
  });
94
131
  });
95
132
  }
@@ -131,7 +168,10 @@ class OGC3DTile extends THREE.Object3D {
131
168
  this.boundingVolume = new OBB(this.json.boundingVolume.box);
132
169
  } else if (!!this.json.boundingVolume.region) {
133
170
  const region = this.json.boundingVolume.region;
134
- this.boundingVolume = new THREE.Box3(new THREE.Vector3(region[0], region[2], region[4]), new THREE.Vector3(region[1], region[3], region[5]));
171
+ this.transformWGS84ToCartesian(region[0], region[1], region[4], tempVec1);
172
+ this.transformWGS84ToCartesian(region[2], region[3], region[5], tempVec2);
173
+ tempVec1.lerp(tempVec2, 0.5);
174
+ this.boundingVolume = new THREE.Sphere(new THREE.Vector3(tempVec1.x, tempVec1.z, -tempVec1.y), tempVec1.distanceTo(tempVec2));
135
175
  } else if (!!this.json.boundingVolume.sphere) {
136
176
  const sphere = this.json.boundingVolume.sphere;
137
177
  this.boundingVolume = new THREE.Sphere(new THREE.Vector3(sphere[0], sphere[2], -sphere[1]), sphere[3]);
@@ -176,7 +216,7 @@ class OGC3DTile extends THREE.Object3D {
176
216
  if (!!url) {
177
217
  if (url.includes(".b3dm")) {
178
218
  self.contentURL = url;
179
- self.tileLoader.get(self.abortController,this.uuid, url, mesh => {
219
+ self.tileLoader.get(self.abortController, this.uuid, url, mesh => {
180
220
  if (!!self.deleted) return;
181
221
  mesh.traverse((o) => {
182
222
  if (o.isMesh) {
@@ -189,13 +229,13 @@ class OGC3DTile extends THREE.Object3D {
189
229
  }
190
230
  o.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
191
231
  }
192
- if(self.static){
232
+ if (self.static) {
193
233
  o.matrixAutoUpdate = false;
194
234
  }
195
235
  //o.material.visible = false;
196
236
  }
197
237
  });
198
-
238
+
199
239
  self.add(mesh);
200
240
  self.updateWorldMatrix(false, true);
201
241
  // mesh.layers.disable(0);
@@ -204,7 +244,7 @@ class OGC3DTile extends THREE.Object3D {
204
244
  return self.calculateDistanceToCamera(self.cameraOnLoad);
205
245
  }, () => self.getSiblings(), self.level);
206
246
  } else if (url.includes(".json")) {
207
- self.tileLoader.get(self.abortController,this.uuid, url, json => {
247
+ self.tileLoader.get(self.abortController, this.uuid, url, json => {
208
248
  if (!!self.deleted) return;
209
249
  if (!self.json.children) self.json.children = [];
210
250
  json.rootPath = path.dirname(url);
@@ -273,7 +313,7 @@ class OGC3DTile extends THREE.Object3D {
273
313
  if (self.occlusionCullingService && self.hasMeshContent && !self.occlusionCullingService.hasID(self.colorID)) {
274
314
  return;
275
315
  }
276
- if (!self.hasMeshContent || (metric < self.geometricError && !!self.meshContent)) {
316
+ if (!self.hasMeshContent || (metric < self.geometricErrorMultiplier * self.geometricError && !!self.meshContent)) {
277
317
  if (!!self.json && !!self.json.children && self.childrenTiles.length != self.json.children.length) {
278
318
  loadJsonChildren();
279
319
  return;
@@ -307,10 +347,10 @@ class OGC3DTile extends THREE.Object3D {
307
347
  }
308
348
 
309
349
  // has children
310
- if (metric >= self.geometricError) { // Ideal LOD or before ideal lod
350
+ if (metric >= self.geometricErrorMultiplier * self.geometricError) { // Ideal LOD or before ideal lod
311
351
 
312
352
  self.changeContentVisibility(true);
313
- } else if (metric < self.geometricError) { // Ideal LOD is past this one
353
+ } else if (metric < self.geometricErrorMultiplier * self.geometricError) { // Ideal LOD is past this one
314
354
  // if children are visible and have been displayed, can be hidden
315
355
  let allChildrenReady = true;
316
356
  self.childrenTiles.every(child => {
@@ -345,7 +385,7 @@ class OGC3DTile extends THREE.Object3D {
345
385
  updateNodeVisibility(metric);
346
386
  return;
347
387
  }
348
- if (metric >= self.geometricError) {
388
+ if (metric >= self.geometricErrorMultiplier * self.geometricError) {
349
389
  self.disposeChildren();
350
390
  updateNodeVisibility();
351
391
  return;
@@ -367,7 +407,8 @@ class OGC3DTile extends THREE.Object3D {
367
407
  level: self.level + 1,
368
408
  tileLoader: self.tileLoader,
369
409
  cameraOnLoad: camera,
370
- occlusionCullingService:self.occlusionCullingService,
410
+ occlusionCullingService: self.occlusionCullingService,
411
+ renderer: self.renderer,
371
412
  static: self.static
372
413
  });
373
414
  self.childrenTiles.push(childTile);
@@ -382,11 +423,11 @@ class OGC3DTile extends THREE.Object3D {
382
423
  const self = this;
383
424
  this.childrenTiles.every(child => {
384
425
  if (child.hasMeshContent) {
385
- if(child.childrenTiles.length>0){
426
+ if (child.childrenTiles.length > 0) {
386
427
  allLoadedAndHidden = false;
387
428
  return false;
388
429
  }
389
- if (!child.inFrustum ) {
430
+ if (!child.inFrustum) {
390
431
  return true;
391
432
  };
392
433
  if (!child.materialVisibility || child.meshesToDisplay != child.meshesDisplayed) {
@@ -459,15 +500,15 @@ class OGC3DTile extends THREE.Object3D {
459
500
 
460
501
  changeContentVisibility(visibility) {
461
502
  const self = this;
462
- if(self.hasMeshContent && self.meshContent){
463
- if(visibility){
464
-
503
+ if (self.hasMeshContent && self.meshContent) {
504
+ if (visibility) {
505
+
465
506
  self.meshContent.traverse((o) => {
466
507
  if (o.isMesh) {
467
508
  o.layers.enable(0);
468
509
  }
469
510
  });
470
- }else{
511
+ } else {
471
512
  self.meshContent.traverse((o) => {
472
513
  if (o.isMesh) {
473
514
  o.layers.disable(0);
@@ -515,29 +556,30 @@ class OGC3DTile extends THREE.Object3D {
515
556
  tempSphere.copy(this.boundingVolume);
516
557
  tempSphere.applyMatrix4(this.matrixWorld);
517
558
  if (!frustum.intersectsSphere(tempSphere)) return -1;
518
- } else if (this.boundingVolume instanceof THREE.Box3) {
519
- // Region
520
- // Region not supported
521
- //throw Error("Region bounding volume not supported");
522
- return -1;
559
+ } else {
560
+ console.error("unsupported shape");
561
+ return -1
562
+
523
563
  }
524
564
 
525
565
  /////// return metric based on geometric error and distance
526
- if (this.boundingVolume instanceof OBB || this.boundingVolume instanceof THREE.Sphere) {
527
- // box
528
- const distance = Math.max(0, camera.position.distanceTo(tempSphere.center) - tempSphere.radius);
529
- if (distance == 0) {
530
- return 0;
531
- }
532
- const scale = this.matrixWorld.getMaxScaleOnAxis();
533
- return Math.pow(distance, 2) /(this.geometricErrorMultiplier*this.geometricError*Math.pow(scale,2.0)*35);
534
- //return (((distance / Math.pow(scale, 2)) / 100) / this.geometricErrorMultiplier);
535
- } else if (this.boundingVolume instanceof THREE.Box3) {
536
- // Region
537
- // Region not supported
538
- //throw Error("Region bounding volume not supported");
539
- return -1;
566
+
567
+ const distance = Math.max(0, camera.position.distanceTo(tempSphere.center) - tempSphere.radius);
568
+ if (distance == 0) {
569
+ return 0;
540
570
  }
571
+ const scale = this.matrixWorld.getMaxScaleOnAxis();
572
+ this.renderer.getDrawingBufferSize(rendererSize);
573
+ let s = rendererSize.y;
574
+ let fov = camera.fov;
575
+ if (camera.aspect < 1) {
576
+ fov *= camera.aspect;
577
+ s = rendererSize.x;
578
+ }
579
+
580
+ let lambda = 2.0 * Math.tan(0.5 * fov * 0.01745329251994329576923690768489) * distance;
581
+
582
+ return (window.devicePixelRatio * 16 * lambda) / (s * scale);
541
583
  }
542
584
 
543
585
  getSiblings() {
@@ -570,8 +612,8 @@ class OGC3DTile extends THREE.Object3D {
570
612
  tempSphere.applyMatrix4(this.matrixWorld);
571
613
  //if (!frustum.intersectsSphere(tempSphere)) return -1;
572
614
  }
573
- if (this.boundingVolume instanceof THREE.Box3) {
574
- return -1; // region not supported
615
+ else {
616
+ console.error("unsupported shape")
575
617
  }
576
618
  return Math.max(0, camera.position.distanceTo(tempSphere.center) - tempSphere.radius);
577
619
  }
@@ -579,5 +621,21 @@ class OGC3DTile extends THREE.Object3D {
579
621
  this.geometricErrorMultiplier = geometricErrorMultiplier;
580
622
  this.childrenTiles.forEach(child => child.setGeometricErrorMultiplier(geometricErrorMultiplier));
581
623
  }
624
+
625
+ transformWGS84ToCartesian(lon, lat, h, sfct) {
626
+ const a = 6378137.0;
627
+ const e = 0.006694384442042;
628
+ const N = a / (Math.sqrt(1.0 - (e * Math.pow(Math.sin(lat), 2))));
629
+ const cosLat = Math.cos(lat);
630
+ const cosLon = Math.cos(lon);
631
+ const sinLat = Math.sin(lat);
632
+ const sinLon = Math.sin(lon);
633
+ const nPh = (N + h);
634
+ const x = nPh * cosLat * cosLon;
635
+ const y = nPh * cosLat * sinLon;
636
+ const z = (0.993305615557957 * N + h) * sinLat;
637
+
638
+ sfct.set(x, y, z);
639
+ }
582
640
  }
583
641
  export { OGC3DTile };
@@ -19,12 +19,14 @@ class InstancedOGC3DTile extends THREE.Object3D {
19
19
  * cameraOnLoad: camera,
20
20
  * parentTile: OGC3DTile,
21
21
  * onLoadCallback: function,
22
+ * renderer: Renderer
22
23
  * static: Boolean
23
24
  * } properties
24
25
  */
25
26
  constructor(properties) {
26
27
  super();
27
28
  properties.master = this;
29
+ this.renderer = properties.renderer;
28
30
  this.geometricErrorMultiplier = properties.geometricErrorMultiplier? properties.geometricErrorMultiplier:1.0;
29
31
  this.tileset = new InstancedTile(properties);
30
32
  if (properties.static) {
@@ -4,8 +4,13 @@ import { v4 as uuidv4 } from "uuid";
4
4
  import * as path from "path-browserify";
5
5
  import * as _ from "lodash";
6
6
 
7
- const tempSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0, 1));
8
-
7
+ const tempSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0), 1);
8
+ const tempVec1 = new THREE.Vector3(0, 0, 0);
9
+ const tempVec2 = new THREE.Vector3(0, 0, 0);
10
+ const upVector = new THREE.Vector3(0, 1, 0);
11
+ const rendererSize = new THREE.Vector2();
12
+ const tempQuaternion = new THREE.Quaternion();
13
+ const tempMatrix = new THREE.Matrix4();
9
14
 
10
15
  class InstancedTile extends THREE.Object3D {
11
16
 
@@ -23,7 +28,8 @@ class InstancedTile extends THREE.Object3D {
23
28
  * meshCallback: function,
24
29
  * cameraOnLoad: camera,
25
30
  * parentTile: OGC3DTile,
26
- * onLoadCallback: function
31
+ * onLoadCallback: function,
32
+ * centerModel: Boolean
27
33
  * } properties
28
34
  */
29
35
  constructor(properties) {
@@ -76,7 +82,36 @@ class InstancedTile extends THREE.Object3D {
76
82
  //json = JSON.parse(JSON.stringify(json))
77
83
  const p = path.dirname(url);
78
84
  self.setup({ rootPath: p, json: json });
85
+ if (!!properties.centerModel) {
86
+ const tempSphere = new THREE.Sphere();
87
+ if (self.boundingVolume instanceof OBB) {
88
+ // box
89
+ tempSphere.copy(self.boundingVolume.sphere);
90
+ } else if (self.boundingVolume instanceof THREE.Sphere) {
91
+ //sphere
92
+ tempSphere.copy(self.boundingVolume);
93
+ }
94
+
95
+ //tempSphere.applyMatrix4(self.matrixWorld);
96
+ if (!!this.json.boundingVolume.region) {
97
+ self.transformWGS84ToCartesian(
98
+ (self.json.boundingVolume.region[0] + self.json.boundingVolume.region[2]) * 0.5,
99
+ (self.json.boundingVolume.region[1] + self.json.boundingVolume.region[3]) * 0.5,
100
+ (self.json.boundingVolume.region[4] + self.json.boundingVolume.region[5]) * 0.5,
101
+ tempVec1);
102
+ tempVec2.set(tempVec1.x, tempVec1.z, -tempVec1.y);
103
+
104
+ tempQuaternion.setFromUnitVectors(tempVec2.normalize(), upVector.normalize());
105
+ self.master.applyQuaternion(tempQuaternion);
106
+ self.master.updateWorldMatrix(false, false)
107
+ }
108
+ tempMatrix.makeTranslation(-tempSphere.center.x * self.scale.x, -tempSphere.center.y * self.scale.y, -tempSphere.center.z * self.scale.z);
109
+ //self.master.applyMatrix4(tempMatrix);
110
+ self.master.matrix.multiply(tempMatrix);
111
+ self.master.matrix.decompose( self.master.position, self.master.quaternion, self.master.scale );
112
+ }
79
113
  if (properties.onLoadCallback) properties.onLoadCallback(self);
114
+
80
115
  }
81
116
  self.tileLoader.get(self.abortController, properties.url, self.uuid, self);
82
117
 
@@ -132,7 +167,10 @@ class InstancedTile extends THREE.Object3D {
132
167
  this.boundingVolume = new OBB(this.json.boundingVolume.box);
133
168
  } else if (!!this.json.boundingVolume.region) {
134
169
  const region = this.json.boundingVolume.region;
135
- this.boundingVolume = new THREE.Box3(new THREE.Vector3(region[0], region[2], region[4]), new THREE.Vector3(region[1], region[3], region[5]));
170
+ this.transformWGS84ToCartesian(region[0], region[1], region[4], tempVec1);
171
+ this.transformWGS84ToCartesian(region[2], region[3], region[5], tempVec2);
172
+ tempVec1.lerp(tempVec2, 0.5);
173
+ this.boundingVolume = new THREE.Sphere(new THREE.Vector3(tempVec1.x, tempVec1.z, -tempVec1.y), tempVec1.distanceTo(tempVec2));
136
174
  } else if (!!this.json.boundingVolume.sphere) {
137
175
  const sphere = this.json.boundingVolume.sphere;
138
176
  this.boundingVolume = new THREE.Sphere(new THREE.Vector3(sphere[0], sphere[2], -sphere[1]), sphere[3]);
@@ -188,6 +226,8 @@ class InstancedTile extends THREE.Object3D {
188
226
 
189
227
  }
190
228
  }
229
+ self.matrixWorldNeedsUpdate = true;
230
+ self.updateWorldMatrix(true,true)
191
231
  }
192
232
 
193
233
  loadMesh(mesh) {
@@ -250,7 +290,7 @@ class InstancedTile extends THREE.Object3D {
250
290
  // If this tile does not have mesh content but it has children
251
291
  if (metric < 0 && self.hasMeshContent) return;
252
292
 
253
- if ((!self.hasMeshContent && self.rootPath) || (metric < self.geometricError && !!self.meshContent)) {
293
+ if ((!self.hasMeshContent && self.rootPath) || (metric < self.master.geometricErrorMultiplier * self.geometricError && !!self.meshContent)) {
254
294
  if (!!self.json && !!self.jsonChildren && self.childrenTiles.length != self.jsonChildren.length) {
255
295
  loadJsonChildren();
256
296
  return;
@@ -284,10 +324,10 @@ class InstancedTile extends THREE.Object3D {
284
324
  }
285
325
 
286
326
  // has children
287
- if (metric >= self.geometricError) { // Ideal LOD or before ideal lod
327
+ if (metric >= self.master.geometricErrorMultiplier * self.geometricError) { // Ideal LOD or before ideal lod
288
328
 
289
329
  self.changeContentVisibility(true);
290
- } else if (metric < self.geometricError) { // Ideal LOD is past this one
330
+ } else if (metric < self.master.geometricErrorMultiplier * self.geometricError) { // Ideal LOD is past this one
291
331
  // if children are visible and have been displayed, can be hidden
292
332
  let allChildrenReady = true;
293
333
  self.childrenTiles.every(child => {
@@ -311,7 +351,7 @@ class InstancedTile extends THREE.Object3D {
311
351
  updateNodeVisibility(metric);
312
352
  return;
313
353
  }
314
- if (metric >= self.geometricError) {
354
+ if (metric >= self.master.geometricErrorMultiplier * self.geometricError) {
315
355
  self.disposeChildren();
316
356
  updateNodeVisibility();
317
357
  return;
@@ -440,11 +480,9 @@ class InstancedTile extends THREE.Object3D {
440
480
  tempSphere.copy(this.boundingVolume);
441
481
  tempSphere.applyMatrix4(this.master.matrixWorld);
442
482
  if (!frustum.intersectsSphere(tempSphere)) return -1;
443
- } else if (this.boundingVolume instanceof THREE.Box3) {
444
- // Region
445
- // Region not supported
446
- //throw Error("Region bounding volume not supported");
447
- return -1;
483
+ } else {
484
+ console.error("unsupported shape");
485
+ return -1
448
486
  }
449
487
 
450
488
  /////// return metric based on geometric error and distance
@@ -455,8 +493,18 @@ class InstancedTile extends THREE.Object3D {
455
493
  return 0;
456
494
  }
457
495
  const scale = this.master.matrixWorld.getMaxScaleOnAxis();
458
- //return (((distance / Math.pow(scale, 2)) / 100) / this.master.geometricErrorMultiplier);
459
- return Math.pow(distance, 2) /(this.master.geometricErrorMultiplier*this.geometricError*Math.pow(scale,2.0)*35);
496
+
497
+ this.master.renderer.getDrawingBufferSize(rendererSize);
498
+ let s = rendererSize.y;
499
+ let fov = camera.fov;
500
+ if(camera.aspect < 1){
501
+ fov *= camera.aspect;
502
+ s = rendererSize.x;
503
+ }
504
+
505
+ let lambda = 2.0 * Math.tan(0.5 * fov * 0.01745329251994329576923690768489) * distance;
506
+
507
+ return (window.devicePixelRatio * 16 * lambda) / (s * scale);
460
508
  } else if (this.boundingVolume instanceof THREE.Box3) {
461
509
  // Region
462
510
  // Region not supported
@@ -495,8 +543,8 @@ class InstancedTile extends THREE.Object3D {
495
543
  tempSphere.applyMatrix4(this.master.matrixWorld);
496
544
  //if (!frustum.intersectsSphere(tempSphere)) return -1;
497
545
  }
498
- if (this.boundingVolume instanceof THREE.Box3) {
499
- return -1; // region not supported
546
+ else {
547
+ console.error("unsupported shape")
500
548
  }
501
549
  return Math.max(0, camera.position.distanceTo(tempSphere.center) - tempSphere.radius);
502
550
  }
@@ -505,5 +553,21 @@ class InstancedTile extends THREE.Object3D {
505
553
  const self = this;
506
554
  return self.master.matrixWorld;
507
555
  }
556
+
557
+ transformWGS84ToCartesian(lon, lat, h, sfct) {
558
+ const a = 6378137.0;
559
+ const e = 0.006694384442042;
560
+ const N = a / (Math.sqrt(1.0 - (e * Math.pow(Math.sin(lat), 2))));
561
+ const cosLat = Math.cos(lat);
562
+ const cosLon = Math.cos(lon);
563
+ const sinLat = Math.sin(lat);
564
+ const sinLon = Math.sin(lon);
565
+ const nPh = (N + h);
566
+ const x = nPh * cosLat * cosLon;
567
+ const y = nPh * cosLat * sinLon;
568
+ const z = (0.993305615557957 * N + h) * sinLat;
569
+
570
+ sfct.set(x, y, z);
571
+ }
508
572
  }
509
573
  export { InstancedTile };
@@ -1,6 +1,7 @@
1
1
  import * as THREE from 'three';
2
2
  import { InstancedMesh } from 'three';
3
3
 
4
+ const t = new THREE.Matrix4();
4
5
  class MeshTile{
5
6
  constructor(scene){
6
7
  const self = this;
@@ -60,7 +61,12 @@ class MeshTile{
60
61
  self.instancedTiles[i].meshContent = self.instancedMesh;
61
62
  if(self.instancedTiles[i].materialVisibility && !!self.instancedTiles[i].meshContent){
62
63
  self.instancedMesh.count++;
63
- self.instancedMesh.setMatrixAt(self.instancedMesh.count-1, self.reuseableMatrix.multiplyMatrices(self.instancedTiles[i].getWorldMatrix(), self.instancedMesh.baseMatrix) )
64
+ self.reuseableMatrix.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);
65
+ self.reuseableMatrix.multiply(self.instancedTiles[i].master.matrixWorld);
66
+ self.reuseableMatrix.multiply(self.instancedMesh.baseMatrix);
67
+ self.instancedMesh.setMatrixAt(self.instancedMesh.count-1, self.reuseableMatrix );
68
+ self.instancedMesh.getMatrixAt(0, t);
69
+ console.log()
64
70
  }
65
71
 
66
72
  }