zincjs 1.3.0 → 1.4.0-beta.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/build/zinc.frontend.js +2 -2
- package/build/zinc.js +302 -236
- package/build/zinc.js.map +1 -1
- package/package.json +1 -1
- package/src/geometryCSG.js +14 -14
- package/src/glyphsetCSG.js +2 -2
- package/src/loaders/GLTFToZincJSLoader.js +3 -2
- package/src/loaders/primitivesLoader.js +3 -1
- package/src/primitives/geometry.js +70 -54
- package/src/primitives/glyphset.js +6 -6
- package/src/primitives/lines.js +2 -1
- package/src/primitives/lod.js +378 -0
- package/src/primitives/marker.js +1 -0
- package/src/primitives/pointset.js +2 -1
- package/src/primitives/textureSlides.js +1 -1
- package/src/primitives/zincObject.js +132 -197
- package/src/region.js +10 -8
- package/src/scene.js +2 -2
- package/src/sceneExporter.js +1 -1
- package/src/sceneLoader.js +27 -36
- package/src/utilities.js +226 -145
- package/src/workers/geometryCSG.worker.js +4 -4
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
const THREE = require('three');
|
|
2
|
+
const updateMorphColorAttribute = require("../utilities").updateMorphColorAttribute;
|
|
3
|
+
const toBufferGeometry = require('../utilities').toBufferGeometry;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Provides an object which stores meshes at different levels based
|
|
7
|
+
* on specified distance.
|
|
8
|
+
* This object is ued by zincObject to provide mesh at different LODs.
|
|
9
|
+
* A layer is displayed when the distance from the camera is greater
|
|
10
|
+
* than its specified distance and closest compared to other layers.
|
|
11
|
+
* This is intended to be an internal object used only by Zinc Object.
|
|
12
|
+
*
|
|
13
|
+
* This object assumes the centroid and bounding box are consistent between
|
|
14
|
+
* different level of layers.
|
|
15
|
+
*
|
|
16
|
+
* @class
|
|
17
|
+
* @author Alan Wu
|
|
18
|
+
* @return {LOD}
|
|
19
|
+
*/
|
|
20
|
+
const LOD = function (parent) {
|
|
21
|
+
this.levels = [];
|
|
22
|
+
this._currentLevel = 0;
|
|
23
|
+
this._renderOrder = 1;
|
|
24
|
+
this._material = undefined;
|
|
25
|
+
this._secondaryMaterial = undefined;
|
|
26
|
+
this._loader = undefined;
|
|
27
|
+
//The owning Zinc Object
|
|
28
|
+
this._parent = parent;
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
* Add a level of LOD at the specified distance
|
|
33
|
+
*/
|
|
34
|
+
this.addLevel = (object, distanceIn) => {
|
|
35
|
+
if (object) {
|
|
36
|
+
const distance = Math.abs(distanceIn);
|
|
37
|
+
let l;
|
|
38
|
+
for (l = 0; l < this.levels.length; l++) {
|
|
39
|
+
if (distance < this.levels[l].distance) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const levelObject = {
|
|
44
|
+
distance: distance,
|
|
45
|
+
morph: object,
|
|
46
|
+
loaded: true,
|
|
47
|
+
loading: false,
|
|
48
|
+
url: "",
|
|
49
|
+
};
|
|
50
|
+
this.levels.splice(l, 0, levelObject);
|
|
51
|
+
object.renderOrder = this._renderOrder;
|
|
52
|
+
//this.add( object );
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* This is called once an ondemand level is loaded
|
|
58
|
+
*/
|
|
59
|
+
this.levelLoaded = (object, distanceIn) => {
|
|
60
|
+
if (object) {
|
|
61
|
+
const distance = Math.abs(distanceIn);
|
|
62
|
+
let l;
|
|
63
|
+
for (l = 0; l < this.levels.length; l++) {
|
|
64
|
+
if (distance === this.levels[l].distance) {
|
|
65
|
+
this._parent.group.add(object);
|
|
66
|
+
this.levels[l].morph = object;
|
|
67
|
+
this.levels[l].loaded = true;
|
|
68
|
+
this.levels[l].loading = false;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.addLevelFromURL = (loader, level, url, preload) => {
|
|
76
|
+
this._loader = loader;
|
|
77
|
+
const distance = this.calculateDistance(level);
|
|
78
|
+
const levelObject = {
|
|
79
|
+
distance: distance,
|
|
80
|
+
morph: undefined,
|
|
81
|
+
loaded: false,
|
|
82
|
+
loading: false,
|
|
83
|
+
url: url,
|
|
84
|
+
};
|
|
85
|
+
for (l = 0; l < this.levels.length; l++) {
|
|
86
|
+
if (distance < this.levels[l].distance) {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this.levels.splice(l, 0, levelObject);
|
|
91
|
+
if (preload) {
|
|
92
|
+
this.loadLevel(l);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//load the mesh at index, return true if morph is not ready
|
|
97
|
+
this.loadLevel = (index) => {
|
|
98
|
+
const level = this.levels[index];
|
|
99
|
+
if (!level.morph && !level.loaded &&
|
|
100
|
+
!level.loading) {
|
|
101
|
+
level.loading = true;
|
|
102
|
+
this._loader.load(level.url, this.lodLoader(level.distance),
|
|
103
|
+
undefined, undefined);
|
|
104
|
+
}
|
|
105
|
+
return (level.morph === undefined);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
this.calculateDistance = function (level) {
|
|
110
|
+
this._parent.getBoundingBox();
|
|
111
|
+
const radius = this._parent.radius;
|
|
112
|
+
let distance = 0;
|
|
113
|
+
if (level === "far") {
|
|
114
|
+
distance = radius * 4.5;
|
|
115
|
+
} else if (level === "medium") {
|
|
116
|
+
distance = radius * 2.5;
|
|
117
|
+
} else if (level === "close") {
|
|
118
|
+
distance = 0;
|
|
119
|
+
}
|
|
120
|
+
return distance;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Check if there are multiple levels.
|
|
125
|
+
*/
|
|
126
|
+
this.containsLevels = () => {
|
|
127
|
+
if (this.levels && this.levels.length > 1) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Check if material is transparent, create secondary mesh
|
|
135
|
+
* for better rendering if required.
|
|
136
|
+
*/
|
|
137
|
+
this.checkTransparentMesh = (animationGroup, transparentChanged) => {
|
|
138
|
+
const level = this.levels[this._currentLevel];
|
|
139
|
+
if (this._material) {
|
|
140
|
+
if (this._material.transparent) {
|
|
141
|
+
if (!this._secondaryMaterial) {
|
|
142
|
+
this._secondaryMaterial = this._material.clone();
|
|
143
|
+
this._secondaryMaterial.side = THREE.FrontSide;
|
|
144
|
+
}
|
|
145
|
+
this._secondaryMaterial.opacity = this._material.opacity;
|
|
146
|
+
// THREE.Mesh - for utilities purpose such as rendering
|
|
147
|
+
// transparent surfaces - one for front face and one for back face.
|
|
148
|
+
if (!level.secondaryMesh) {
|
|
149
|
+
level.secondaryMesh = new THREE.Mesh(level.morph.geometry,
|
|
150
|
+
this._secondaryMaterial);
|
|
151
|
+
level.secondaryMesh.renderOrder = level.morph.renderOrder + 1;
|
|
152
|
+
level.secondaryMesh.userData = level.morph.userData;
|
|
153
|
+
level.secondaryMesh.name = level.morph.name;
|
|
154
|
+
}
|
|
155
|
+
if (transparentChanged) {
|
|
156
|
+
this._material.side = THREE.BackSide;
|
|
157
|
+
this._material.needsUpdate = true;
|
|
158
|
+
level.morph.add(level.secondaryMesh);
|
|
159
|
+
animationGroup.add(level.secondaryMesh);
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
if (level.secondaryMesh) {
|
|
163
|
+
//Do not delete this mesh, remove it from
|
|
164
|
+
//rendering and animation group instead
|
|
165
|
+
level.morph.remove(level.secondaryMesh);
|
|
166
|
+
animationGroup.uncache(level.secondaryMesh);
|
|
167
|
+
animationGroup.remove(level.secondaryMesh);
|
|
168
|
+
}
|
|
169
|
+
this._material.side = THREE.DoubleSide;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.dispose = () => {
|
|
175
|
+
this.levels.forEach((level) => {
|
|
176
|
+
if (level.morph && level.morph.geometry) {
|
|
177
|
+
level.morph.geometry.dispose();
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
if (this._material) {
|
|
181
|
+
this._material.dispose();
|
|
182
|
+
}
|
|
183
|
+
if (this._secondaryMaterial) {
|
|
184
|
+
this._secondaryMaterial.dispose();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
this.getCurrentLevel = () => {
|
|
189
|
+
return this._currentLevel;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.getCurrentMorph = () => {
|
|
193
|
+
const level = this.levels[this._currentLevel];
|
|
194
|
+
if (level && level.morph) {
|
|
195
|
+
return level.morph;
|
|
196
|
+
}
|
|
197
|
+
return this._parent.morph;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Loader for lod object
|
|
202
|
+
*/
|
|
203
|
+
this.lodLoader = function (distance) {
|
|
204
|
+
return (geometryIn) => {
|
|
205
|
+
const material = this._material;
|
|
206
|
+
const options = {
|
|
207
|
+
localTimeEnabled: this._parent.timeEnabled,
|
|
208
|
+
localMorphColour: this._parent.morphColour,
|
|
209
|
+
}
|
|
210
|
+
const geometry = toBufferGeometry(geometryIn, options);
|
|
211
|
+
const mesh = new THREE.Mesh(geometry, material);
|
|
212
|
+
geometryIn.dispose();
|
|
213
|
+
this.levelLoaded(mesh, distance);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
this.updateMorphColorAttribute = (currentOnly) => {
|
|
218
|
+
//Multilayers - set all
|
|
219
|
+
if (this._material) {
|
|
220
|
+
if ((this._material.vertexColors == THREE.VertexColors) ||
|
|
221
|
+
(this._material.vertexColors == true)) {
|
|
222
|
+
if (currentOnly) {
|
|
223
|
+
const morph = this.getCurrentMorph();
|
|
224
|
+
updateMorphColorAttribute(morph.geometry, morph);
|
|
225
|
+
} else {
|
|
226
|
+
this.levels.forEach((level) => {
|
|
227
|
+
if (level.morph && level.morph.geometry) {
|
|
228
|
+
updateMorphColorAttribute(level.morph.geometry, level.morph);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
this.setColour = (colour) => {
|
|
237
|
+
this._material.color = colour;
|
|
238
|
+
if (this._secondaryMaterial) {
|
|
239
|
+
this._secondaryMaterial.color = colour;
|
|
240
|
+
}
|
|
241
|
+
updateGeometryColour();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
this.setFrustumCulled = (flag) => {
|
|
245
|
+
this.levels.forEach((level) => {
|
|
246
|
+
if (level.morph) {
|
|
247
|
+
level.morph.frustumCulled = flag;
|
|
248
|
+
}
|
|
249
|
+
if (level.secondaryMesh) {
|
|
250
|
+
level.secondaryMesh.frustumCulled = flag;
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
this.setMaterial = (material) => {
|
|
256
|
+
if (material) {
|
|
257
|
+
if (!this._material || (this._material.id !== material.id)) {
|
|
258
|
+
this._material = material;
|
|
259
|
+
if (this._secondaryMaterial) {
|
|
260
|
+
this._secondaryMaterial.dispose();
|
|
261
|
+
this._secondaryMaterial = material.clone()
|
|
262
|
+
this._secondaryMaterial.side = THREE.FrontSide;
|
|
263
|
+
}
|
|
264
|
+
this.levels.forEach((level) => {
|
|
265
|
+
if (level.morph) {
|
|
266
|
+
level.morph.material = this._material;
|
|
267
|
+
if (level.morph.geometry) {
|
|
268
|
+
level.morph.geometry.colorsNeedUpdate = true;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (level.secondaryMesh) {
|
|
272
|
+
level.secondaryMesh.material = this._secondaryMaterial;
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
this.setName = (name) => {
|
|
280
|
+
this.levels.forEach((level) => {
|
|
281
|
+
if (level.morph) {
|
|
282
|
+
level.morph.name = name;
|
|
283
|
+
}
|
|
284
|
+
if (level.secondaryMesh) {
|
|
285
|
+
level.secondaryMesh.name = name;
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
this.setRenderOrder = (order) => {
|
|
291
|
+
this._renderOrder = order;
|
|
292
|
+
this.levels.forEach((level) => {
|
|
293
|
+
if (level.morph) {
|
|
294
|
+
level.morph.renderOrder = order;
|
|
295
|
+
}
|
|
296
|
+
if (level.secondaryMesh) {
|
|
297
|
+
level.secondaryMesh.renderOrder = order;
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
this.setVertexColors = (vertexColors) => {
|
|
303
|
+
this._material.vertexColors = vertexColors;
|
|
304
|
+
updateGeometryColour();
|
|
305
|
+
if (this._secondaryMaterial) {
|
|
306
|
+
this._secondaryMaterial.vertexColors = vertexColors;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/* Update layers based on the */
|
|
311
|
+
this.update = (camera, center) => {
|
|
312
|
+
const levels = this.levels;
|
|
313
|
+
if (levels.length > 1) {
|
|
314
|
+
const distance = camera.cameraObject.position.distanceTo(center);
|
|
315
|
+
let visibleIndex = -1;
|
|
316
|
+
let optimalIndex = -1;
|
|
317
|
+
let i, l;
|
|
318
|
+
//Found a visible index that is within range of the LOD
|
|
319
|
+
for (i = 0, l = levels.length; i < l; i++) {
|
|
320
|
+
if (distance >= levels[i].distance) {
|
|
321
|
+
//Check if a level is loading
|
|
322
|
+
if (levels[i].morph) {
|
|
323
|
+
if (visibleIndex > -1 && levels[visibleIndex].morph) {
|
|
324
|
+
levels[visibleIndex].morph.visible = false;
|
|
325
|
+
}
|
|
326
|
+
visibleIndex = i;
|
|
327
|
+
levels[i].morph.visible = true;
|
|
328
|
+
optimalIndex = -1;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
optimalIndex = i;
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (optimalIndex > -1) {
|
|
338
|
+
this.loadLevel(optimalIndex);
|
|
339
|
+
}
|
|
340
|
+
for (; i < l; i++) {
|
|
341
|
+
if (levels[i].morph) {
|
|
342
|
+
//Set visibility of other morph to false
|
|
343
|
+
//and set the closest lod to true if
|
|
344
|
+
//none is found
|
|
345
|
+
if (visibleIndex > -1) {
|
|
346
|
+
levels[i].morph.visible = false;
|
|
347
|
+
} else {
|
|
348
|
+
levels[i].morph.visible = true;
|
|
349
|
+
visibleIndex = i;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
this._currentLevel = visibleIndex;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
this.toggleMarker = (marker, flag) => {
|
|
358
|
+
this.levels.forEach((level) => {
|
|
359
|
+
if (level.morph) {
|
|
360
|
+
if (flag) {
|
|
361
|
+
level.morph.add(marker);
|
|
362
|
+
} else {
|
|
363
|
+
level.morph.remove(marker);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
updateGeometryColour = () => {
|
|
370
|
+
this.levels.forEach((level) => {
|
|
371
|
+
if (level.morph && level.morph.geometry) {
|
|
372
|
+
level.morph.geometry.colorsNeedUpdate = true;
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
exports.LOD = LOD;
|
package/src/primitives/marker.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const THREE = require('three');
|
|
2
2
|
const Points = require('../three/Points').Points;
|
|
3
|
+
const toBufferGeometry = require('../utilities').toBufferGeometry;
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Provides an object which stores points and provides method which controls its position.
|
|
@@ -37,7 +38,7 @@ const Pointset = function () {
|
|
|
37
38
|
*/
|
|
38
39
|
this.createMesh = (geometryIn, materialIn, options) => {
|
|
39
40
|
if (geometryIn && materialIn) {
|
|
40
|
-
let geometry =
|
|
41
|
+
let geometry = toBufferGeometry(geometryIn, options);
|
|
41
42
|
const texture = getCircularTexture();
|
|
42
43
|
materialIn.map = texture;
|
|
43
44
|
let point = new Points(geometry, materialIn);
|
|
@@ -16,7 +16,7 @@ const TextureSlides = function (textureIn) {
|
|
|
16
16
|
this.isTextureSlides = true;
|
|
17
17
|
const textureSettings = [];
|
|
18
18
|
const idTextureMap = {};
|
|
19
|
-
this.
|
|
19
|
+
this.setMorph(new THREE.Group());
|
|
20
20
|
this.morph.userData = this;
|
|
21
21
|
const alpha = 1.0;
|
|
22
22
|
|