@mcolabs/threebox-plugin 4.0.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.
@@ -0,0 +1,298 @@
1
+ /**
2
+ * @author peterqliu / https://github.com/peterqliu
3
+ * @author jscastro / https://github.com/jscastro76
4
+ */
5
+ import * as THREE from 'three';
6
+ import utils from '../utils/utils.js';
7
+ import ThreeboxConstants from '../utils/constants.js';
8
+
9
+ function CameraSync(map, camera, world) {
10
+ // console.log("CameraSync constructor");
11
+ this.map = map;
12
+ this.camera = camera;
13
+ this.active = true;
14
+
15
+ this.camera.matrixAutoUpdate = false; // We're in charge of the camera now!
16
+
17
+ // Postion and configure the world group so we can scale it appropriately when the camera zooms
18
+ this.world = world || new THREE.Group();
19
+ this.world.position.x = this.world.position.y = ThreeboxConstants.WORLD_SIZE / 2
20
+ this.world.matrixAutoUpdate = false;
21
+
22
+ // set up basic camera state
23
+ this.state = {
24
+ translateCenter: new THREE.Matrix4().makeTranslation(ThreeboxConstants.WORLD_SIZE / 2, -ThreeboxConstants.WORLD_SIZE / 2, 0),
25
+ worldSizeRatio: ThreeboxConstants.TILE_SIZE / ThreeboxConstants.WORLD_SIZE,
26
+ worldSize: ThreeboxConstants.TILE_SIZE * this.map.transform.scale
27
+ };
28
+
29
+ // Listen for move events from the map and update the Three.js camera
30
+ let _this = this; // keep the function on _this
31
+ this.map
32
+ .on('move', function () {
33
+ _this.updateCamera();
34
+ })
35
+ .on('resize', function () {
36
+ _this.setupCamera();
37
+ })
38
+
39
+ this.setupCamera();
40
+ }
41
+
42
+ CameraSync.prototype = {
43
+ setupCamera: function () {
44
+ const t = this.map.transform;
45
+ this.camera.aspect = t.width / t.height; //bug fixed, if aspect is not reset raycast will fail on map resize
46
+ this.halfFov = t._fov / 2;
47
+ this.cameraToCenterDistance = 0.5 / Math.tan(this.halfFov) * t.height;
48
+ const maxPitch = t._maxPitch * Math.PI / 180;
49
+ this.acuteAngle = Math.PI / 2 - maxPitch;
50
+ this.updateCamera();
51
+ },
52
+
53
+ updateCamera: function (ev) {
54
+ if (!this.camera) {
55
+ console.log('nocamera')
56
+ return;
57
+ }
58
+
59
+ const t = this.map.transform;
60
+ this.camera.aspect = t.width / t.height; //bug fixed, if aspect is not reset raycast will fail on map resize
61
+ const offset = t.centerOffset || new THREE.Vector3(); //{ x: t.width / 2, y: t.height / 2 };
62
+ let farZ = 0;
63
+ let furthestDistance = 0;
64
+ this.halfFov = t._fov / 2;
65
+ const groundAngle = Math.PI / 2 + t._pitch;
66
+ const pitchAngle = Math.cos((Math.PI / 2) - t._pitch); //pitch seems to influence heavily the depth calculation and cannot be more than 60 = PI/3 < v1 and 85 > v2
67
+ this.cameraToCenterDistance = 0.5 / Math.tan(this.halfFov) * t.height;
68
+ let pixelsPerMeter = 1;
69
+ const worldSize = this.worldSize();
70
+
71
+ if (this.map.tb.mapboxVersion >= 2.0) {
72
+ // mapbox version >= 2.0
73
+ pixelsPerMeter = this.mercatorZfromAltitude(1, t.center.lat) * worldSize;
74
+ const fovAboveCenter = t._fov * (0.5 + t.centerOffset.y / t.height);
75
+
76
+ // Adjust distance to MSL by the minimum possible elevation visible on screen,
77
+ // this way the far plane is pushed further in the case of negative elevation.
78
+ const minElevationInPixels = t.elevation ? t.elevation.getMinElevationBelowMSL() * pixelsPerMeter : 0;
79
+ const cameraToSeaLevelDistance = ((t._camera.position[2] * worldSize) - minElevationInPixels) / Math.cos(t._pitch);
80
+ const topHalfSurfaceDistance = Math.sin(fovAboveCenter) * cameraToSeaLevelDistance / Math.sin(utils.clamp(Math.PI - groundAngle - fovAboveCenter, 0.01, Math.PI - 0.01));
81
+
82
+ // Calculate z distance of the farthest fragment that should be rendered.
83
+ furthestDistance = pitchAngle * topHalfSurfaceDistance + cameraToSeaLevelDistance;
84
+
85
+ // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`
86
+ const horizonDistance = cameraToSeaLevelDistance * (1 / t._horizonShift);
87
+ farZ = Math.min(furthestDistance * 1.01, horizonDistance);
88
+ } else {
89
+ // mapbox version < 2.0 or azure maps
90
+ // Furthest distance optimized by @jscastro76
91
+ const topHalfSurfaceDistance = Math.sin(this.halfFov) * this.cameraToCenterDistance / Math.sin(Math.PI - groundAngle - this.halfFov);
92
+
93
+ // Calculate z distance of the farthest fragment that should be rendered.
94
+ furthestDistance = pitchAngle * topHalfSurfaceDistance + this.cameraToCenterDistance;
95
+
96
+ // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`
97
+ farZ = furthestDistance * 1.01;
98
+ }
99
+ this.cameraTranslateZ = new THREE.Matrix4().makeTranslation(0, 0, this.cameraToCenterDistance);
100
+
101
+ // someday @ansis set further near plane to fix precision for deckgl,so we should fix it to use mapbox-gl v1.3+ correctly
102
+ // https://github.com/mapbox/mapbox-gl-js/commit/5cf6e5f523611bea61dae155db19a7cb19eb825c#diff-5dddfe9d7b5b4413ee54284bc1f7966d
103
+ const nz = (t.height / 50); //min near z as coded by @ansis
104
+ const nearZ = Math.max(nz * pitchAngle, nz); //on changes in the pitch nz could be too low
105
+
106
+ const h = t.height;
107
+ const w = t.width;
108
+ if (this.camera instanceof THREE.OrthographicCamera) {
109
+ this.camera.projectionMatrix = utils.makeOrthographicMatrix(w / - 2, w / 2, h / 2, h / - 2, nearZ, farZ);
110
+ } else {
111
+ this.camera.projectionMatrix = utils.makePerspectiveMatrix(t._fov, w / h, nearZ, farZ);
112
+ }
113
+ this.camera.projectionMatrix.elements[8] = -offset.x * 2 / t.width;
114
+ this.camera.projectionMatrix.elements[9] = offset.y * 2 / t.height;
115
+
116
+ // Unlike the Mapbox GL JS camera, separate camera translation and rotation out into its world matrix
117
+ // If this is applied directly to the projection matrix, it will work OK but break raycasting
118
+ let cameraWorldMatrix = this.calcCameraMatrix(t._pitch, t.angle);
119
+ // When terrain layers are included, height of 3D layers must be modified from t_camera.z * worldSize
120
+ if (t.elevation) cameraWorldMatrix.elements[14] = t._camera.position[2] * worldSize;
121
+ //this.camera.matrixWorld.elements is equivalent to t._camera._transform
122
+ this.camera.matrixWorld.copy(cameraWorldMatrix);
123
+
124
+ let zoomPow = t.scale * this.state.worldSizeRatio;
125
+ // Handle scaling and translation of objects in the map in the world's matrix transform, not the camera
126
+ let scale = new THREE.Matrix4;
127
+ let translateMap = new THREE.Matrix4;
128
+ let rotateMap = new THREE.Matrix4;
129
+
130
+ scale.makeScale(zoomPow, zoomPow, zoomPow);
131
+
132
+ let x = t.x || t.point.x;
133
+ let y = t.y || t.point.y;
134
+ translateMap.makeTranslation(-x, y, 0);
135
+ rotateMap.makeRotationZ(Math.PI);
136
+
137
+ this.world.matrix = new THREE.Matrix4()
138
+ .premultiply(rotateMap)
139
+ .premultiply(this.state.translateCenter)
140
+ .premultiply(scale)
141
+ .premultiply(translateMap)
142
+
143
+ // utils.prettyPrintMatrix(this.camera.projectionMatrix.elements);
144
+ this.map.fire('CameraSynced', { detail: { nearZ: nearZ, farZ: farZ, pitch: t._pitch, angle: t.angle, furthestDistance: furthestDistance, cameraToCenterDistance: this.cameraToCenterDistance, t: this.map.transform, tbProjMatrix: this.camera.projectionMatrix.elements, tbWorldMatrix: this.world.matrix.elements, cameraSyn: CameraSync } });
145
+
146
+ },
147
+
148
+ worldSize() {
149
+ let t = this.map.transform;
150
+ return t.tileSize * t.scale;
151
+ },
152
+
153
+ worldSizeFromZoom() {
154
+ let t = this.map.transform;
155
+ return Math.pow(2.0, t.zoom) * t.tileSize;
156
+ },
157
+
158
+ mercatorZfromAltitude(altitude, lat) {
159
+ return altitude / this.circumferenceAtLatitude(lat);
160
+ },
161
+
162
+ mercatorZfromZoom() {
163
+ return this.cameraToCenterDistance / this.worldSizeFromZoom();
164
+ },
165
+
166
+ circumferenceAtLatitude(latitude) {
167
+ return ThreeboxConstants.EARTH_CIRCUMFERENCE * Math.cos(latitude * Math.PI / 180);
168
+ },
169
+
170
+ calcCameraMatrix(pitch, angle, trz) {
171
+ const t = this.map.transform;
172
+ const _pitch = (pitch === undefined) ? t._pitch : pitch;
173
+ const _angle = (angle === undefined) ? t.angle : angle;
174
+ const _trz = (trz === undefined) ? this.cameraTranslateZ : trz;
175
+
176
+ return new THREE.Matrix4()
177
+ .premultiply(_trz)
178
+ .premultiply(new THREE.Matrix4().makeRotationX(_pitch))
179
+ .premultiply(new THREE.Matrix4().makeRotationZ(_angle));
180
+ },
181
+
182
+ updateCameraState() {
183
+ let t = this.map.transform;
184
+ if (!t.height) return;
185
+
186
+ // Set camera orientation and move it to a proper distance from the map
187
+ //t._camera.setPitchBearing(t._pitch, t.angle);
188
+
189
+ const dir = t._camera.forward();
190
+ const distance = t.cameraToCenterDistance;
191
+ const center = t.point;
192
+
193
+ // Use camera zoom (if terrain is enabled) to maintain constant altitude to sea level
194
+ const zoom = t._cameraZoom ? t._cameraZoom : t._zoom;
195
+ const altitude = this.mercatorZfromZoom(t);
196
+ const height = altitude - this.mercatorZfromAltitude(t._centerAltitude, t.center.lat);
197
+
198
+ // simplified version of: this._worldSizeFromZoom(this._zoomFromMercatorZ(height))
199
+ const updatedWorldSize = t.cameraToCenterDistance / height;
200
+ return [
201
+ center.x / this.worldSize() - (dir[0] * distance) / updatedWorldSize,
202
+ center.y / this.worldSize() - (dir[1] * distance) / updatedWorldSize,
203
+ this.mercatorZfromAltitude(t._centerAltitude, t._center.lat) + (-dir[2] * distance) / updatedWorldSize
204
+ ];
205
+
206
+ },
207
+
208
+ getWorldToCamera(worldSize, pixelsPerMeter) {
209
+ // transformation chain from world space to camera space:
210
+ // 1. Height value (z) of renderables is in meters. Scale z coordinate by pixelsPerMeter
211
+ // 2. Transform from pixel coordinates to camera space with cameraMatrix^-1
212
+ // 3. flip Y if required
213
+
214
+ // worldToCamera: flip * cam^-1 * zScale
215
+ // cameraToWorld: (flip * cam^-1 * zScale)^-1 => (zScale^-1 * cam * flip^-1)
216
+ let t = this.map.transform;
217
+ const matrix = new THREE.Matrix4();
218
+ const matrixT = new THREE.Matrix4();
219
+
220
+ // Compute inverse of camera matrix and post-multiply negated translation
221
+ const o = t._camera._orientation;
222
+ const p = t._camera.position;
223
+ const invPosition = new THREE.Vector3(p[0], p[1], p[2]);
224
+
225
+ const quat = new THREE.Quaternion();
226
+ quat.set(o[0], o[1], o[2], o[3]);
227
+ const invOrientation = quat.conjugate();
228
+ invPosition.multiplyScalar(-worldSize);
229
+
230
+ matrixT.makeTranslation(invPosition.x, invPosition.y, invPosition.z);
231
+ matrix
232
+ .makeRotationFromQuaternion(invOrientation)
233
+ .premultiply(matrixT);
234
+ //this would make the matrix exact to getWorldToCamera but breaks
235
+ //this.translate(matrix.elements, matrix.elements, invPosition);
236
+
237
+ // Pre-multiply y (2nd row)
238
+ matrix.elements[1] *= -1.0;
239
+ matrix.elements[5] *= -1.0;
240
+ matrix.elements[9] *= -1.0;
241
+ matrix.elements[13] *= -1.0;
242
+
243
+ // Post-multiply z (3rd column)
244
+ matrix.elements[8] *= pixelsPerMeter;
245
+ matrix.elements[9] *= pixelsPerMeter;
246
+ matrix.elements[10] *= pixelsPerMeter;
247
+ matrix.elements[11] *= pixelsPerMeter;
248
+ //console.log(matrix.elements);
249
+ return matrix;
250
+ },
251
+
252
+ translate(out, a, v) {
253
+ let x = v[0] || v.x,
254
+ y = v[1] || v.y,
255
+ z = v[2] || v.z;
256
+ let a00, a01, a02, a03;
257
+ let a10, a11, a12, a13;
258
+ let a20, a21, a22, a23;
259
+ if (a === out) {
260
+ out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
261
+ out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
262
+ out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
263
+ out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
264
+ } else {
265
+ a00 = a[0];
266
+ a01 = a[1];
267
+ a02 = a[2];
268
+ a03 = a[3];
269
+ a10 = a[4];
270
+ a11 = a[5];
271
+ a12 = a[6];
272
+ a13 = a[7];
273
+ a20 = a[8];
274
+ a21 = a[9];
275
+ a22 = a[10];
276
+ a23 = a[11];
277
+ out[0] = a00;
278
+ out[1] = a01;
279
+ out[2] = a02;
280
+ out[3] = a03;
281
+ out[4] = a10;
282
+ out[5] = a11;
283
+ out[6] = a12;
284
+ out[7] = a13;
285
+ out[8] = a20;
286
+ out[9] = a21;
287
+ out[10] = a22;
288
+ out[11] = a23;
289
+ out[12] = a00 * x + a10 * y + a20 * z + a[12];
290
+ out[13] = a01 * x + a11 * y + a21 * z + a[13];
291
+ out[14] = a02 * x + a12 * y + a22 * z + a[14];
292
+ out[15] = a03 * x + a13 * y + a23 * z + a[15];
293
+ }
294
+ return out;
295
+ }
296
+ }
297
+
298
+ export default CameraSync;
package/src/index.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Threebox - A Three.js plugin for Mapbox GL JS
3
+ *
4
+ * @author peterqliu / https://github.com/peterqliu
5
+ * @author jscastro / https://github.com/jscastro76
6
+ */
7
+
8
+ export { default as Threebox } from './Threebox.js';
@@ -0,0 +1,236 @@
1
+ /**
2
+ * @author mrdoob / http://mrdoob.com/
3
+ */
4
+
5
+ import * as THREE from 'three';
6
+
7
+ class CSS2DObject extends THREE.Object3D {
8
+
9
+ constructor(element) {
10
+
11
+ super();
12
+ this.element = element || document.createElement('div');
13
+ this.element.style.position = 'absolute';
14
+ this.element.style.userSelect = 'none';
15
+ this.element.setAttribute('draggable', false);
16
+
17
+ //[jscastro] some labels must be always visible
18
+ this.alwaysVisible = false;
19
+
20
+ //[jscastro] layer is needed to be rendered/hidden based on layer visibility
21
+ Object.defineProperty(this, 'layer', {
22
+ get() { return (this.parent && this.parent.parent ? this.parent.parent.layer : null) }
23
+ });
24
+
25
+ //[jscastro] implement dispose
26
+ this.dispose = function () {
27
+ this.remove();
28
+ this.element = null;
29
+ }
30
+ //[jscastro] implement explicit method
31
+ this.remove = function () {
32
+ if (this.element instanceof Element && this.element.parentNode !== null) {
33
+ this.element.parentNode.removeChild(this.element);
34
+ }
35
+ }
36
+
37
+ this.addEventListener('removed', function () {
38
+
39
+ this.remove();
40
+
41
+ });
42
+
43
+ }
44
+
45
+ copy(source, recursive) {
46
+
47
+ super.copy(source, recursive);
48
+ this.element = source.element.cloneNode(true);
49
+ return this;
50
+
51
+ }
52
+
53
+ }
54
+
55
+ CSS2DObject.prototype.isCSS2DObject = true;
56
+
57
+ const _vector = new THREE.Vector3();
58
+
59
+ const _viewMatrix = new THREE.Matrix4();
60
+
61
+ const _viewProjectionMatrix = new THREE.Matrix4();
62
+
63
+ const _a = new THREE.Vector3();
64
+
65
+ const _b = new THREE.Vector3();
66
+
67
+ class CSS2DRenderer {
68
+
69
+ constructor() {
70
+
71
+ const _this = this;
72
+
73
+ let _width, _height;
74
+
75
+ let _widthHalf, _heightHalf;
76
+
77
+ const cache = {
78
+ objects: new WeakMap(),
79
+ list: new Map()
80
+ };
81
+ this.cacheList = cache.list;
82
+ const domElement = document.createElement('div');
83
+ domElement.style.overflow = 'hidden';
84
+ this.domElement = domElement;
85
+
86
+ this.getSize = function () {
87
+
88
+ return {
89
+ width: _width,
90
+ height: _height
91
+ };
92
+
93
+ };
94
+
95
+ this.render = function (scene, camera) {
96
+
97
+ if (scene.autoUpdate === true) scene.updateMatrixWorld();
98
+ if (camera.parent === null) camera.updateMatrixWorld();
99
+
100
+ _viewMatrix.copy(camera.matrixWorldInverse);
101
+
102
+ _viewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, _viewMatrix);
103
+
104
+ renderObject(scene, scene, camera);
105
+ zOrder(scene);
106
+
107
+ };
108
+
109
+ this.setSize = function (width, height) {
110
+
111
+ _width = width;
112
+ _height = height;
113
+ _widthHalf = _width / 2;
114
+ _heightHalf = _height / 2;
115
+ domElement.style.width = width + 'px';
116
+ domElement.style.height = height + 'px';
117
+
118
+ };
119
+
120
+ function renderObject(object, scene, camera) {
121
+
122
+ if (object.isCSS2DObject) {
123
+
124
+ //[jscastro] optimize performance and don't update and remove the labels that are not visible
125
+ if (!object.visible) {
126
+ cache.objects.delete({ key: object.uuid });
127
+ cache.list.delete(object.uuid);
128
+ object.remove();
129
+ }
130
+ else {
131
+
132
+ object.onBeforeRender(_this, scene, camera);
133
+
134
+ _vector.setFromMatrixPosition(object.matrixWorld);
135
+
136
+ _vector.applyMatrix4(_viewProjectionMatrix);
137
+
138
+ const element = object.element;
139
+ var style;
140
+ if (/apple/i.test(navigator.vendor)) {
141
+
142
+ // https://github.com/mrdoob/three.js/issues/21415
143
+ style = 'translate(-50%,-50%) translate(' + Math.round(_vector.x * _widthHalf + _widthHalf) + 'px,' + Math.round(- _vector.y * _heightHalf + _heightHalf) + 'px)';
144
+
145
+ } else {
146
+
147
+ style = 'translate(-50%,-50%) translate(' + (_vector.x * _widthHalf + _widthHalf) + 'px,' + (- _vector.y * _heightHalf + _heightHalf) + 'px)';
148
+
149
+ }
150
+
151
+ element.style.WebkitTransform = style;
152
+ element.style.MozTransform = style;
153
+ element.style.oTransform = style;
154
+ element.style.transform = style;
155
+
156
+ element.style.display = object.visible && _vector.z >= - 1 && _vector.z <= 1 ? '' : 'none';
157
+
158
+ const objectData = {
159
+ distanceToCameraSquared: getDistanceToSquared(camera, object)
160
+ };
161
+
162
+ cache.objects.set({ key: object.uuid }, objectData);
163
+ cache.list.set(object.uuid, object);
164
+
165
+ if (element.parentNode !== domElement) {
166
+
167
+ domElement.appendChild(element);
168
+
169
+ }
170
+
171
+ object.onAfterRender(_this, scene, camera);
172
+
173
+ }
174
+ }
175
+
176
+ for (let i = 0, l = object.children.length; i < l; i++) {
177
+
178
+ renderObject(object.children[i], scene, camera);
179
+
180
+ }
181
+
182
+
183
+ }
184
+
185
+ function getDistanceToSquared(object1, object2) {
186
+
187
+ _a.setFromMatrixPosition(object1.matrixWorld);
188
+
189
+ _b.setFromMatrixPosition(object2.matrixWorld);
190
+
191
+ return _a.distanceToSquared(_b);
192
+
193
+ }
194
+
195
+ function filterAndFlatten(scene) {
196
+
197
+ const result = [];
198
+ scene.traverse(function (object) {
199
+
200
+ if (object.isCSS2DObject) result.push(object);
201
+
202
+ });
203
+ return result;
204
+
205
+ }
206
+
207
+ function zOrder(scene) {
208
+
209
+ const sorted = filterAndFlatten(scene).sort(function (a, b) {
210
+ //[jscastro] check the objects already exist in the cache
211
+ let cacheA = cache.objects.get({ key: a.uuid });
212
+ let cacheB = cache.objects.get({ key: b.uuid });
213
+
214
+ if (cacheA && cacheB) {
215
+ const distanceA = cacheA.distanceToCameraSquared;
216
+ const distanceB = cacheB.distanceToCameraSquared;
217
+ return distanceA - distanceB;
218
+ }
219
+
220
+ });
221
+
222
+ const zMax = sorted.length;
223
+
224
+ for (let i = 0, l = sorted.length; i < l; i++) {
225
+
226
+ sorted[i].element.style.zIndex = zMax - i;
227
+
228
+ }
229
+
230
+ }
231
+
232
+ }
233
+
234
+ }
235
+
236
+ export { CSS2DRenderer, CSS2DObject };
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @author jscastro / https://github.com/jscastro76
3
+ */
4
+
5
+ import { CSS2DRenderer } from './CSS2DRenderer.js';
6
+
7
+ function LabelRenderer(map) {
8
+
9
+ this.map = map;
10
+
11
+ this.renderer = new CSS2DRenderer();
12
+
13
+ this.renderer.setSize(this.map.getCanvas().clientWidth, this.map.getCanvas().clientHeight);
14
+ this.renderer.domElement.style.position = 'absolute';
15
+ this.renderer.domElement.id = 'labelCanvas'; //TODO: this value must come by parameter
16
+ this.renderer.domElement.style.top = 0;
17
+ this.renderer.domElement.style.zIndex = "0";
18
+ this.map.getCanvasContainer().appendChild(this.renderer.domElement);
19
+
20
+ this.scene, this.camera;
21
+
22
+ this.dispose = function () {
23
+ this.map.getCanvasContainer().removeChild(this.renderer.domElement)
24
+ this.renderer.domElement.remove();
25
+ this.renderer = {};
26
+ }
27
+
28
+ this.setSize = function (width, height) {
29
+ this.renderer.setSize(width, height);
30
+ }
31
+
32
+ this.map.on('resize', function () {
33
+ this.renderer.setSize(this.map.getCanvas().clientWidth, this.map.getCanvas().clientHeight);
34
+ }.bind(this));
35
+
36
+ this.state = {
37
+ reset: function () {
38
+ //TODO: Implement a good state reset, check out what is made in WebGlRenderer
39
+ }
40
+ }
41
+
42
+ this.render = async function (scene, camera) {
43
+ this.scene = scene;
44
+ this.camera = camera;
45
+ return new Promise((resolve) => { resolve(this.renderer.render(scene, camera)) });
46
+ }
47
+
48
+ //[jscastro] method to toggle Layer visibility
49
+ this.toggleLabels = async function (layerId, visible) {
50
+ return new Promise((resolve) => {
51
+ resolve(this.setVisibility(layerId, visible, this.scene, this.camera, this.renderer));
52
+ })
53
+ };
54
+
55
+ //[jscastro] method to set visibility
56
+ this.setVisibility = function (layerId, visible, scene, camera, renderer) {
57
+ var cache = this.renderer.cacheList;
58
+ cache.forEach(function (l) {
59
+ if (l.visible != visible && l.layer === layerId) {
60
+ if ((visible && l.alwaysVisible) || !visible) {
61
+ l.visible = visible;
62
+ renderer.renderObject(l, scene, camera);
63
+ }
64
+ }
65
+ });
66
+ };
67
+
68
+ }
69
+
70
+ export default LabelRenderer;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @author peterqliu / https://github.com/peterqliu
3
+ * @author jscastro / https://github.com/jscastro76
4
+ */
5
+ import Objects from './objects.js';
6
+ import utils from '../utils/utils.js';
7
+
8
+ function Object3D(opt) {
9
+ opt = utils._validate(opt, Objects.prototype._defaults.Object3D);
10
+ // [jscastro] full refactor of Object3D to behave exactly like 3D Models loadObj
11
+ let obj = opt.obj;
12
+ // [jscastro] options.rotation was wrongly used
13
+ const r = utils.types.rotation(opt.rotation, [0, 0, 0]);
14
+ const s = utils.types.scale(opt.scale, [1, 1, 1]);
15
+ obj.rotation.set(r[0], r[1], r[2]);
16
+ obj.scale.set(s[0], s[1], s[2]);
17
+ obj.name = "model";
18
+ let userScaleGroup = Objects.prototype._makeGroup(obj, opt);
19
+ opt.obj.name = "model";
20
+ Objects.prototype._addMethods(userScaleGroup);
21
+ //[jscastro] calculate automatically the pivotal center of the object
22
+ userScaleGroup.setAnchor(opt.anchor);
23
+ //[jscastro] override the center calculated if the object has adjustments
24
+ userScaleGroup.setCenter(opt.adjustment);
25
+ //[jscastro] if the object is excluded from raycasting
26
+ userScaleGroup.raycasted = opt.raycasted;
27
+ userScaleGroup.visibility = true;
28
+
29
+ return userScaleGroup
30
+ }
31
+
32
+ export default Object3D;