fl-web-component 0.1.1 → 1.0.1

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.
Files changed (78) hide show
  1. package/dist/fl-web-component.common.js +14751 -54489
  2. package/dist/fl-web-component.common.js.map +1 -1
  3. package/dist/fl-web-component.css +1 -1
  4. package/dist/fl-web-component.umd.js +14751 -54489
  5. package/dist/fl-web-component.umd.js.map +1 -1
  6. package/dist/fl-web-component.umd.min.js +3 -3
  7. package/dist/fl-web-component.umd.min.js.map +1 -1
  8. package/package.json +28 -5
  9. package/packages/components/button/index.vue +18 -17
  10. package/packages/components/com-card/card-page.vue +51 -49
  11. package/packages/components/com-card/index.vue +20 -21
  12. package/packages/components/com-dialogWrapper/index.vue +18 -21
  13. package/packages/components/com-flcanvas/components/bspline.js +91 -0
  14. package/packages/components/com-flcanvas/components/entityFormatting.js +503 -0
  15. package/packages/components/com-flcanvas/components/round10.js +24 -0
  16. package/packages/components/com-flcanvas/index.vue +259 -0
  17. package/packages/components/com-formDialog/index.vue +76 -75
  18. package/packages/components/com-graphics/index.vue +1057 -226
  19. package/packages/components/com-graphics/per-control.vue +109 -0
  20. package/packages/components/com-graphics/pid.vue +168 -0
  21. package/packages/components/com-page/index.vue +33 -33
  22. package/packages/components/com-selectTree/index.vue +61 -63
  23. package/packages/components/com-table/column-default.vue +9 -14
  24. package/packages/components/com-table/column-dynamic.vue +4 -8
  25. package/packages/components/com-table/column-menu.vue +8 -8
  26. package/packages/components/com-table/column-slot.vue +4 -4
  27. package/packages/components/com-table/column.vue +7 -15
  28. package/packages/components/com-table/config.js +9 -9
  29. package/packages/components/com-table/index.vue +35 -35
  30. package/packages/components/com-table/table-page.vue +17 -17
  31. package/packages/components/com-tabs/index.vue +19 -19
  32. package/packages/components/com-treeDynamic/index.vue +45 -45
  33. package/packages/components/model/api/index.js +59 -67
  34. package/packages/components/model/api/mock/detecttree.js +38 -38
  35. package/packages/components/model/api/mock/getmodel-line.js +15830 -79332
  36. package/packages/components/model/api/mock/init.js +1 -1
  37. package/packages/components/model/api/mock/pbstree.js +486 -495
  38. package/packages/components/model/components/TextOverTooltip/index.vue +3 -3
  39. package/packages/components/model/components/annotation-toolbar.vue +4 -19
  40. package/packages/components/model/components/check-proofing-model.vue +26 -29
  41. package/packages/components/model/components/clipping-type.vue +22 -14
  42. package/packages/components/model/components/com-dialogWrapper/index.vue +22 -25
  43. package/packages/components/model/components/detect-panel.vue +38 -26
  44. package/packages/components/model/components/detect-tree.vue +9 -24
  45. package/packages/components/model/components/firstPer-panel.vue +23 -25
  46. package/packages/components/model/components/header-button.vue +31 -107
  47. package/packages/components/model/components/imageViewer/index.vue +34 -35
  48. package/packages/components/model/components/import-model.vue +127 -127
  49. package/packages/components/model/components/location-panel.vue +25 -29
  50. package/packages/components/model/components/measure-type.vue +15 -15
  51. package/packages/components/model/components/pbs-tree.vue +139 -144
  52. package/packages/components/model/components/proof-config.vue +2 -10
  53. package/packages/components/model/components/proof-for-pc.vue +35 -32
  54. package/packages/components/model/components/proof-history.vue +136 -154
  55. package/packages/components/model/components/proof-panel-detail.vue +166 -165
  56. package/packages/components/model/components/proof-panel.vue +281 -205
  57. package/packages/components/model/components/proof-project-user.vue +13 -50
  58. package/packages/components/model/components/proof-publish.vue +130 -130
  59. package/packages/components/model/components/proof-role.vue +93 -124
  60. package/packages/components/model/components/props-panel.vue +63 -54
  61. package/packages/components/model/index.vue +3225 -3213
  62. package/packages/components/model/utils/annotation-tool.js +75 -82
  63. package/packages/components/model/utils/cursor.js +15 -10
  64. package/packages/components/model/utils/detect-v1.js +23 -35
  65. package/packages/components/model/utils/index.js +25 -25
  66. package/packages/components/model/utils/threejs/measure-angle.js +180 -180
  67. package/packages/components/model/utils/threejs/measure-area.js +196 -184
  68. package/packages/components/model/utils/threejs/measure-distance.js +154 -152
  69. package/packages/components/model/utils/threejs/measure-volume.js +64 -61
  70. package/src/assets/test.png +0 -0
  71. package/src/assets/worker.glb +0 -0
  72. package/src/main.js +11 -8
  73. package/src/utils/flgltf-parser.js +141 -0
  74. package/src/utils/instance-parser.js +402 -0
  75. package/src/utils/mock.js +84746 -0
  76. package/src/utils/threejs/measure-angle.js +240 -0
  77. package/src/utils/threejs/measure-area.js +249 -0
  78. package/src/utils/threejs/measure-distance.js +195 -0
@@ -1,240 +1,1071 @@
1
1
  <template>
2
- <div id="instructions">
3
- </div>
2
+ <div id="instructions"></div>
4
3
  </template>
5
4
  <script>
6
- var [ renderer, scene, camera, cameraControls, loader, instructions,
7
- raycaster, mouse, labelRenderer
8
- ]= (function* (v) { while (true) yield v })(null)
9
- var [ lastTime, firstTime, fpsClock, timeStamp ] = (function* (v) { while (true) yield v })(0)
10
- import CameraControls from 'camera-controls'
11
- import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
12
- import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js'
13
- import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
14
- import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
15
- export default {
16
- name: 'Model',
17
- props: {
18
- data: {
19
- type: Array,
20
- default() {
21
- return []
22
- }
5
+ var [
6
+ renderer,
7
+ scene,
8
+ camera,
9
+ cameraControls,
10
+ instructions,
11
+ raycaster,
12
+ mouse,
13
+ labelRenderer,
14
+ lineTexture,
15
+ curve,
16
+ downRaycaster,
17
+ velocity,
18
+ direction,
19
+ clock,
20
+ pointControls,
21
+ threeMeasure,
22
+ modelGroup,
23
+ ] = (function* (v) {
24
+ while (true) yield v;
25
+ })(null);
26
+
27
+ var [lastTime, firstTime, fpsClock, timeStamp, progress] = (function* (v) {
28
+ while (true) yield v;
29
+ })(0);
30
+
31
+ var [
32
+ roaming,
33
+ firstPerSign,
34
+ canJump,
35
+ moveForward,
36
+ moveBackward,
37
+ moveLeft,
38
+ moveRight,
39
+ measureFlag,
40
+ ] = (function* (v) {
41
+ while (true) yield v;
42
+ })(false);
43
+
44
+ var [spaceUp] = (function* (v) {
45
+ while (true) yield v;
46
+ })(true);
47
+
48
+ var clippingPlanes = [];
49
+ var removeSpeed = 200,
50
+ upSpeed = 200; //控制器移动速度 , //控制跳起时的速度
51
+ var modelGroup;
52
+
53
+ // 绘制对象映射实例表
54
+ let drawObjMapInstance = {};
55
+ import CameraControls from 'camera-controls';
56
+ import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
57
+ import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
58
+ import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer';
59
+ import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';
60
+ import MeasureDistance from '@/utils/threejs/measure-distance.js';
61
+ import MeasureArea from '@/utils/threejs/measure-area.js';
62
+ import MeasureAngle from '@/utils/threejs/measure-angle.js';
63
+ import { parseData } from '@/utils/flgltf-parser';
64
+ import { handleInstancedMeshModel } from '@/utils/instance-parser';
65
+
66
+ export default {
67
+ name: 'FlModel',
68
+ props: {
69
+ data: {
70
+ type: Object,
71
+ default() {
72
+ return {};
73
+ },
74
+ },
23
75
  },
24
- glbUrl: {
25
- type: String,
26
- default() {
27
- return ''
28
- }
76
+ data() {
77
+ return {
78
+ roamConfig: {
79
+ loop: false,
80
+ speed: 0, // 最大值为3
81
+ },
82
+ };
29
83
  },
30
- },
31
- data() {
32
- return {}
33
- },
34
- created() {
35
- CameraControls.install({ THREE: this.THREE })
36
- fpsClock = new this.THREE.Clock()
37
- raycaster = new this.THREE.Raycaster()
38
- mouse = new this.THREE.Vector2()
39
- },
40
- mounted() {
41
- instructions = document.getElementById('instructions')
42
- this.initRender()
43
- this.initScene()
44
- this.initCamera()
45
- this.initControl()
46
- this.initLight()
47
- this.initLabelRender()
48
- loader = new GLTFLoader()
49
- loader.load('/example/worker.glb', (gltf) => {
50
- const personModel = gltf.scene
51
- scene.add(personModel)
52
- personModel.scale.set(0.1, 0.1, 0.1)
53
- })
54
- renderer.domElement.addEventListener('mouseup', this.mouseClick, false)
55
- renderer.domElement.addEventListener('mousedown',this.mouseDown, false)
56
- this.animate()
57
- },
58
- methods: {
59
- initRender() {
60
- renderer = new this.THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true })
61
- renderer.setPixelRatio(window.devicePixelRatio * 2)
62
- renderer.setSize(window.innerWidth, window.innerHeight)
63
- renderer.domElement.id = 'three-model'
64
- renderer.shadowMap.enabled = true
65
- // 暂时注释这句 还有worker里面的 这跟渲染出的模型浅或暗有关系
66
- renderer.outputEncoding = this.THREE.sRGBEncoding
67
- instructions.appendChild(renderer.domElement)
68
- renderer.autoClear = false
69
- renderer.autoClearColor = false
70
- renderer.autoClearDepth = false
71
- renderer.autoClearStencil = false
84
+ created() {
85
+ CameraControls.install({ THREE: this.THREE });
86
+ fpsClock = new this.THREE.Clock();
87
+ raycaster = new this.THREE.Raycaster();
88
+ mouse = new this.THREE.Vector2();
72
89
  },
73
- initScene() {
74
- scene = new this.THREE.Scene()
75
- // scene.userData.recordEntity = []
90
+ mounted() {
91
+ instructions = document.getElementById('instructions');
92
+ this.initRender();
93
+ this.initScene();
94
+ this.initCamera();
95
+ this.initControl();
96
+ this.initLight();
97
+ this.initLabelRender();
98
+ renderer.domElement.addEventListener('mouseup', this.mouseClick, false);
99
+ renderer.domElement.addEventListener('mousedown', this.mouseDown, false);
100
+ this.animate();
76
101
  },
77
- initCamera() {
78
- camera = new this.THREE.PerspectiveCamera(
79
- 45,
80
- window.innerWidth / window.innerHeight,
81
- 0.1,
82
- 1000
83
- )
84
- camera.position.set(0, 100, 150)
85
- },
86
- initControl() {
87
- // 初始化控件
88
- cameraControls = new CameraControls(camera, renderer.domElement)
89
- cameraControls.dollyToCursor = true
90
- cameraControls.smoothTime = 0.1
91
- cameraControls.draggingSmoothTime = 0.05
92
- cameraControls.truckSpeed = 2.0
93
- cameraControls.infinityDolly = true
94
- cameraControls.minDistance = 4
95
- },
96
- // 初始化光源
97
- initLight() {
98
- const pmremGenerator = new this.THREE.PMREMGenerator(renderer)
99
- scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture
100
- },
101
- // 初始化文字画布
102
- initLabelRender() {
103
- labelRenderer = new CSS2DRenderer()
104
- labelRenderer.setSize(instructions.offsetWidth, instructions.offsetHeight)
105
- labelRenderer.domElement.style.position = 'absolute'
106
- labelRenderer.domElement.style.top = '0px'
107
- labelRenderer.domElement.style.pointerEvents = 'none'
108
- instructions.appendChild(labelRenderer.domElement)
109
- },
110
- mouseDown() {
111
- firstTime = new Date().getTime()
112
- },
113
- mouseClick(event) {
114
- lastTime = new Date().getTime()
115
- if (lastTime - firstTime < 300) {
116
- mouse.x = (event.clientX / instructions.offsetWidth) * 2 - 1
117
- mouse.y = -(event.clientY / instructions.offsetHeight) * 2 + 1
118
- raycaster.setFromCamera(mouse, camera)
119
- const intersects = raycaster.intersectObjects(scene.children, true)
120
- console.log(intersects)
121
- if (event.button === 0) {
122
- this.$emit('leftClick', {
123
- objects: intersects.length > 0 ? [intersects[0]] : []
124
- })
125
- } else if (event.button === 2) {
126
- this.$emit('rightClick', {
127
- objects: intersects.length > 0 ? [intersects[0]] : [],
128
- position: { x: event.clientX, y: event.clientY }
129
- })
130
- }
131
- }
132
- },
133
- // 修改模型实体属性
134
- /**
135
- * 参数内容{
136
- * list: [{
137
- * name: '',实体的名字
138
- * attr: '', 属性名(color、visible(true / false)、opacity(0-1))
139
- * value: '', 需要修改的值
140
- * }] // 需要更改实体属性的数据
141
- * It can be a CSS-style string. For example:
142
- * 'rgb(250, 0,0)'
143
- * 'rgb(100%,0%,0%)'
144
- * 'hsl(0, 100%, 50%)'
145
- * '#ff0000'
146
- * '#f00'
147
- * 'red'
148
- * }
149
- */
150
- updateProperty(list) {
151
- for (let index = 0; index < list.length; index++) {
152
- let ele = list[index]
153
- let obj = scene.getObjectByName(ele.name)
154
- if (obj) {
155
- switch (ele.attr) {
156
- case 'color': obj.material.color = new this.THREE.Color(ele.value)
157
- break;
158
- case 'visible': obj.material.visible = ele.value
159
- break;
160
- case 'opacity':
161
- obj.material.opacity = ele.value
162
- obj.material.transparent = true
163
- break;
102
+ methods: {
103
+ initRender() {
104
+ renderer = new this.THREE.WebGLRenderer({
105
+ antialias: true,
106
+ alpha: true,
107
+ logarithmicDepthBuffer: true,
108
+ });
109
+ renderer.setPixelRatio(window.devicePixelRatio * 2);
110
+ renderer.setSize(window.innerWidth, window.innerHeight);
111
+ renderer.domElement.id = 'three-model';
112
+ renderer.shadowMap.enabled = true;
113
+ // 暂时注释这句 还有worker里面的 这跟渲染出的模型浅或暗有关系
114
+ renderer.outputEncoding = this.THREE.sRGBEncoding;
115
+ instructions.appendChild(renderer.domElement);
116
+ renderer.autoClear = false;
117
+ renderer.autoClearColor = false;
118
+ renderer.autoClearDepth = false;
119
+ renderer.autoClearStencil = false;
120
+ },
121
+ initScene() {
122
+ modelGroup = new this.THREE.Group();
123
+ scene = new this.THREE.Scene();
124
+ // scene.userData.recordEntity = []
125
+
126
+ // 适配客户端的坐标系,threejs坐标需绕x轴旋转90度
127
+ const mat4 = new this.THREE.Matrix4();
128
+ mat4.makeRotationX(-Math.PI / 2);
129
+ scene.applyMatrix4(mat4);
130
+ },
131
+ initCamera() {
132
+ camera = new this.THREE.PerspectiveCamera(
133
+ 45,
134
+ window.innerWidth / window.innerHeight,
135
+ 0.1,
136
+ 10000
137
+ );
138
+ camera.position.set(0, 100, 150);
139
+ },
140
+ initControl() {
141
+ // 初始化控件
142
+ cameraControls = new CameraControls(camera, renderer.domElement);
143
+ cameraControls.dollyToCursor = true;
144
+ cameraControls.smoothTime = 0.1;
145
+ cameraControls.draggingSmoothTime = 0.05;
146
+ cameraControls.truckSpeed = 2.0;
147
+ cameraControls.infinityDolly = true;
148
+ cameraControls.minDistance = 4;
149
+ },
150
+ // 初始化光源
151
+ initLight() {
152
+ const pmremGenerator = new this.THREE.PMREMGenerator(renderer);
153
+ scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
154
+ },
155
+ // 初始化文字画布
156
+ initLabelRender() {
157
+ labelRenderer = new CSS2DRenderer();
158
+ labelRenderer.setSize(instructions.offsetWidth, instructions.offsetHeight);
159
+ labelRenderer.domElement.style.position = 'absolute';
160
+ labelRenderer.domElement.style.top = '0px';
161
+ labelRenderer.domElement.style.pointerEvents = 'none';
162
+ instructions.appendChild(labelRenderer.domElement);
163
+ },
164
+ // 根据模型数据绘制模型实体 业务平台可调用此方法加载模型
165
+ /*
166
+ 参数:data 模型数据
167
+ color: '' 初始化模型的颜色 在业务方 有这个需求
168
+ */
169
+ drawModel(data, color = '') {
170
+ if (Object.keys(data).length === 0) {
171
+ return;
172
+ }
173
+ const { instances, drawObjs } = parseData(data);
174
+ if (instances.length > 0) {
175
+ modelGroup = handleInstancedMeshModel(instances, drawObjs, '', scene, color);
176
+ scene.add(modelGroup);
177
+ // this.compileShader();
178
+ cameraControls.fitToSphere(modelGroup, true);
179
+ cameraControls.saveState();
180
+ }
181
+ },
182
+ compileShader() {
183
+ scene.traverse(child => {
184
+ if (child.isMesh) {
185
+ child.material.onBeforeCompile = shader => {
186
+ const vertexShader = `
187
+ precision lowp float;
188
+ attribute float visible;
189
+ varying float vVisible;
190
+ void main() {
191
+ vVisible = visible;
192
+ `;
193
+ const fragmentShader = `
194
+ precision lowp float;
195
+ varying float vVisible;
196
+ void main() {
197
+ `;
198
+ const fragColor = `
199
+ #include <dithering_fragment>
200
+ if (vVisible > 0.0) {
201
+ gl_FragColor = vec4(outgoingLight, diffuseColor.a);
202
+ } else {
203
+ discard;
204
+ }
205
+ `;
206
+ shader.vertexShader = shader.vertexShader.replace('void main() {', vertexShader);
207
+ shader.fragmentShader = shader.fragmentShader.replace(
208
+ 'void main() {',
209
+ fragmentShader
210
+ );
211
+ shader.fragmentShader = shader.fragmentShader.replace(
212
+ '#include <dithering_fragment>',
213
+ fragColor
214
+ );
215
+ child.material.transparent = true;
216
+ };
217
+ }
218
+ });
219
+ },
220
+ mouseDown() {
221
+ firstTime = new Date().getTime();
222
+ },
223
+ mouseClick(event) {
224
+ // 在测量模式下,不进行事件暴露
225
+ if (!measureFlag) {
226
+ lastTime = new Date().getTime();
227
+ if (lastTime - firstTime < 300) {
228
+ mouse.x = (event.clientX / instructions.offsetWidth) * 2 - 1;
229
+ mouse.y = -(event.clientY / instructions.offsetHeight) * 2 + 1;
230
+ raycaster.setFromCamera(mouse, camera);
231
+ const intersects = raycaster.intersectObjects(scene.children, true);
232
+ let params = {}
233
+ let cameraData = {
234
+ position: {
235
+ x: cameraControls.camera.position.x,
236
+ y: cameraControls.camera.position.y,
237
+ z: cameraControls.camera.position.z,
238
+ },
239
+ lookAt: {
240
+ heading: cameraControls._target.x,
241
+ pitch: cameraControls._target.y,
242
+ roll: cameraControls._target.z,
243
+ },
244
+ };
245
+ if (intersects.length > 0) {
246
+ params = {
247
+ objects: [intersects[0].object],
248
+ mousePosition: { x: event.clientX, y: event.clientY },
249
+ camera: cameraData,
250
+ v3Position: {
251
+ x: intersects[0].point.x,
252
+ y: intersects[0].point.y,
253
+ z: intersects[0].point.z,
254
+ }
255
+ }
256
+ } else {
257
+ params = {
258
+ objects: [],
259
+ mousePosition: { x: event.clientX, y: event.clientY },
260
+ camera: cameraData,
261
+ v3Position: {
262
+ x: -1,
263
+ y: -1,
264
+ z: -1,
265
+ }
266
+ }
267
+ }
268
+ if (event.button === 0) {
269
+ this.$emit('leftClick', params);
270
+ } else if (event.button === 2) {
271
+ this.$emit('rightClick', params);
272
+ }
164
273
  }
165
- obj.material.needsUpdate = true
166
274
  }
167
- }
168
- },
169
- // 清除上一次的高亮
170
- // 需要清除高亮颜色的实体数据
171
- recoverColor(list) {
172
- for (let index = 0; index < list.length; index++) {
173
- let ele = list[index]
174
- let obj = scene.getObjectByName(ele)
275
+ },
276
+ // 窗口发生改变时, 更新渲染器与相机的大小
277
+ resize(width, height) {
278
+ if (camera) {
279
+ camera.aspect = width / height;
280
+ camera.updateProjectionMatrix();
281
+ renderer.setSize(width, height, true);
282
+ labelRenderer.setSize(width, height);
283
+ // this.timeRender()
284
+ // 这里也要更新测量
285
+ if (threeMeasure) {
286
+ threeMeasure.updateParams(width, height);
287
+ }
288
+ }
289
+ },
290
+ setModelCenter() {
291
+ // const box3 = new this.THREE.Box3();
292
+ // box3.setFromObject(modelGroup);
293
+ // const center = new this.THREE.Vector3();
294
+ // box3.getCenter(center);
295
+ // const size = box3.getSize(new this.THREE.Vector3());
296
+ // camera.position.set(center.x, center.y + size.y, center.z + size.z / 2);
297
+ // camera.lookAt(new this.THREE.Vector3(center.x, center.y, center.z));
298
+ // cameraControls.setLookAt(
299
+ // center.x,
300
+ // center.y + size.y,
301
+ // center.z + size.z / 2,
302
+ // center.x,
303
+ // center.y,
304
+ // center.z,
305
+ // true
306
+ // );
307
+ // cameraControls.update();
308
+ // camera.updateProjectionMatrix();
309
+ // cameraControls.saveState();
310
+ },
311
+ // 修改指定模型实体属性
312
+ /**
313
+ * 参数内容{
314
+ * list: [{
315
+ * name: '', // 实体的name值'
316
+ * attr: {
317
+ * 'color/visible/opacity': '颜色值/(true / false)/(0-1)'
318
+ * }, 需要修改属性的列表
319
+ * }] // 需要更改实体属性的数据
320
+ * It can be a CSS-style string. For example:
321
+ * 'rgb(250, 0,0)'
322
+ * 'rgb(100%,0%,0%)'
323
+ * 'hsl(0, 100%, 50%)'
324
+ * '#ff0000'
325
+ * '#f00'
326
+ * 'red'
327
+ * }
328
+ */
329
+ updateProperty(list) {
330
+ for (let index = 0; index < list.length; index++) {
331
+ let ele = list[index];
332
+ let targetObj = this.getObjectByName(ele.name);
333
+ for (const key in ele.attr) {
334
+ switch (key) {
335
+ case 'color':
336
+ targetObj.forEach(children => {
337
+ if (children.isMesh) {
338
+ children.setColorAt(
339
+ children.userData.instanceIndex,
340
+ new this.THREE.Color(ele.attr[key])
341
+ );
342
+ children.instanceColor.needsUpdate = true;
343
+ }
344
+ });
345
+ break;
346
+ case 'visible':
347
+ targetObj.forEach(children => {
348
+ const index = children.userData.instanceIndex;
349
+ children.geometry.attributes.visible.array[index] = ele.attr[key] ? 1.0 : 0.0;
350
+ children.geometry.attributes.visible.needsUpdate = true;
351
+ });
352
+ break;
353
+ case 'opacity':
354
+ obj.material.opacity = ele.attr[key];
355
+ obj.material.transparent = true;
356
+ break;
357
+ }
358
+ }
359
+ // obj.material.needsUpdate = true;
360
+ }
361
+ },
362
+ // 修改整体模型实体的属性
363
+ /*
364
+ {
365
+ attr: '', 需要修改属性名(color、visible(true / false)、opacity(0-1),
366
+ value: , 需要修改成的值
367
+ }
368
+ */
369
+ updateWholeProperty(params) {
370
+ if (scene) {
371
+ scene.traverse(obj => {
372
+ if (obj instanceof this.THREE.Mesh) {
373
+ switch (params.attr) {
374
+ case 'color':
375
+ obj.material.color = new this.THREE.Color(params.value);
376
+ break;
377
+ case 'visible':
378
+ obj.material.visible = params.value;
379
+ break;
380
+ case 'opacity':
381
+ obj.material.opacity = params.value;
382
+ obj.material.transparent = true;
383
+ break;
384
+ }
385
+ obj.material.needsUpdate = true;
386
+ }
387
+ });
388
+ }
389
+ },
390
+ // 清除上一次的属性修改操作 为了方便业务平台参数跟updateProperty方法的参数一样
391
+ resetProperty(list) {
392
+ for (let index = 0; index < list.length; index++) {
393
+ let ele = list[index];
394
+ let obj = this.getObjectByName(ele.name);
395
+ if (obj) {
396
+ for (const key in ele.attr) {
397
+ switch (key) {
398
+ case 'color':
399
+ obj.forEach(children => {
400
+ if (children.isMesh) {
401
+ children.setColorAt(
402
+ children.userData.instanceIndex,
403
+ children.material.userData.nColor
404
+ );
405
+ children.instanceColor.needsUpdate = true;
406
+ }
407
+ });
408
+ break;
409
+ }
410
+ }
411
+ }
412
+ }
413
+ },
414
+ // 定位到模型
415
+ locateModel(id) {
416
+ let obj = scene.getObjectByName(id);
175
417
  if (obj) {
176
- obj.material.color = obj.material.userData.nColor
177
- obj.material.needsUpdate = true
418
+ cameraControls.fitToSphere(obj.parent, true);
419
+ // cameraControls.fitToBox( obj, true);
178
420
  }
179
- }
180
- },
181
- // 相机定位
182
- /*
183
- 定位参数:x: 相机的x位置, y: 相机的y位置, z: 相机的z位置
184
- heading, pitch, roll
185
- 视点定位可直接使用此方法
186
- */
187
- cameraLocation(parmas) {
188
- cameraControls.setLookAt(
189
- parmas.x,
190
- parmas.y,
191
- parmas.z,
192
- parmas.heading,
193
- parmas.pitch,
194
- parmas.roll,
195
- true
196
- )
197
- cameraControls.update(0)
198
- },
199
- // 添加广告牌
200
- /*
201
- 参数{
202
- billboard: DOM节点
203
- name: 2d广告牌的名字,用来做清除用的
204
- x、y、z为广告牌的位置
205
- }
206
- */
207
- billboard(data) {
208
- const divLabel = new CSS2DObject(data.billboard)
209
- divLabel.name = data.labelClass // 这个是用来清除广告牌用的
210
- divLabel.position.set(data.x, data.y, data.z)
211
- scene.add(divLabel)
212
- },
213
- // 清除广告牌
214
- clearBillboard(name) {
215
- if (scene && scene.getObjectByName(name)) {
216
- let sprit = scene.getObjectByName(name)
217
- scene.remove(sprit)
218
- this.clearBillboard()
219
- }
220
- },
221
-
222
- animate() {
223
- const delta = fpsClock.getDelta()
224
- timeStamp += delta
225
- requestAnimationFrame(this.animate)
226
- cameraControls.enabled && cameraControls.update(timeStamp)
227
- labelRenderer.render(scene, camera)
228
- renderer.render( scene, camera )
421
+ },
422
+ // 相机定位
423
+ /*
424
+ 定位参数:x: 相机的x位置, y: 相机的y位置, z: 相机的z位置
425
+ heading, pitch, roll
426
+ 视点定位可直接使用此方法
427
+ */
428
+ cameraLocation(params) {
429
+ cameraControls.setLookAt(
430
+ params.x,
431
+ params.y,
432
+ params.z,
433
+ params.heading,
434
+ params.pitch,
435
+ params.roll,
436
+ true
437
+ );
438
+ cameraControls.update(0);
439
+ },
440
+ // 添加广告牌
441
+ /*
442
+ 参数:
443
+ {
444
+ billboard: DOM节点
445
+ name: 2d广告牌的名字,用来做清除用的
446
+ x、y、z为广告牌的位置
447
+ }
448
+ */
449
+ billboard(data) {
450
+ const divLabel = new CSS2DObject(data.billboard);
451
+ divLabel.name = data.labelClass; // 这个是用来清除广告牌用的
452
+ divLabel.position.set(data.x, data.y, data.z);
453
+ scene.add(divLabel);
454
+ return divLabel;
455
+ },
456
+ // 通过名字获取实体对象, 返回数组
457
+ getObjectByName(name) {
458
+ let object = [];
459
+ scene.traverse(item => {
460
+ if (item.name === name) {
461
+ object.push(item);
462
+ }
463
+ });
464
+ return object;
465
+ },
466
+ // 通过id获取实体对象, 返回查找到的对象
467
+ getObjectById(id) {
468
+ return scene.getObjectById(id);
469
+ },
470
+ // 通过id删除对象
471
+ removeObjectById(id) {
472
+ let array = this.getObjectByName(id);
473
+ array.forEach(item => {
474
+ if (item.name === id) {
475
+ item.material && item.material.dispose();
476
+ item.geometry && item.geometry.dispose();
477
+ if (item.isMesh) {
478
+ item.clear();
479
+ }
480
+ scene.remove(item);
481
+ }
482
+ });
483
+ },
484
+ // 通过名称删除对象
485
+ removeObjectByName(name) {
486
+ let array = this.getObjectByName(name);
487
+ array.forEach(item => {
488
+ if (item.name === name) {
489
+ item.material && item.material.dispose();
490
+ item.geometry && item.geometry.dispose();
491
+ if (item.isMesh) {
492
+ item.clear();
493
+ }
494
+ scene.remove(item);
495
+ }
496
+ });
497
+ },
498
+ // 绘制曲线
499
+ /*
500
+ 参数声明:Object
501
+ {
502
+ path: [{x:0, y: 0, z: 0}], 坐标点信息
503
+ color: '', // 线条的颜色
504
+ name: '', // 线条的名字, 用来清除时使用的
505
+ }
506
+ */
507
+ drawCurve(params) {
508
+ this.removeObjectByName(params.name);
509
+ const route = [];
510
+ params.path.forEach(element => {
511
+ route.push(new this.THREE.Vector3(element.x, element.y, element.z));
512
+ });
513
+ if (route.length > 1) {
514
+ curve = new this.THREE.CatmullRomCurve3(route);
515
+ const geometryLine = new this.THREE.BufferGeometry().setFromPoints(curve.getPoints(5000));
516
+ const materialLine = new this.THREE.LineBasicMaterial({
517
+ color: params.color,
518
+ depthTest: false,
519
+ transparent: true,
520
+ });
521
+ let line = new this.THREE.Line(geometryLine, materialLine);
522
+ line.name = params.name;
523
+ scene.add(line);
524
+ }
525
+ },
526
+ // 绘制贴图曲线
527
+ drawTextureCurve(params) {
528
+ this.removeObjectByName(params.name);
529
+ const route = [];
530
+ params.path.forEach(element => {
531
+ route.push(new this.THREE.Vector3(element.x, element.y, element.z));
532
+ });
533
+ // 画曲线
534
+ if (route.length > 1) {
535
+ // 曲线 作为路径
536
+ curve = new this.THREE.CatmullRomCurve3(route, false, 'catmullrom', 0);
537
+ const geometry = new this.THREE.TubeGeometry(curve, 5000, 0.5, 4);
538
+ //加载纹理
539
+ lineTexture = new this.THREE.TextureLoader().load('/static/arrow/arrow-right.png');
540
+ lineTexture.wrapS = this.THREE.RepeatWrapping;
541
+ lineTexture.wrapT = this.THREE.RepeatWrapping;
542
+ lineTexture.repeat.set(20, 1); //水平重复20次
543
+ lineTexture.needsUpdate = true;
544
+ lineTexture.offset.y = 0.5;
545
+ const material = new this.THREE.MeshBasicMaterial({
546
+ map: lineTexture,
547
+ side: this.THREE.BackSide, //显示背面
548
+ transparent: true,
549
+ });
550
+ let line = new this.THREE.Line(geometry, material);
551
+ line.name = params.name;
552
+ scene.add(line);
553
+ }
554
+ },
555
+ // 开启漫游
556
+ /*
557
+ 参数为Object
558
+ loop: true / false是否进行循环模型 默认是false
559
+ speed: number 漫游的速度,
560
+ path: [{x: 0, y: 0, z: 0}] 漫游的坐标位置点,
561
+ name: '', 路径的名称,用来清除用的
562
+ */
563
+ startRoam(params) {
564
+ progress = 0;
565
+ this.roamConfig = Object.assign(
566
+ {},
567
+ {
568
+ loop: params.loop,
569
+ speed: params.speed,
570
+ roamName: params.name,
571
+ }
572
+ );
573
+ this.drawTextureCurve({
574
+ name: params.name,
575
+ path: params.path,
576
+ });
577
+ clock = new this.THREE.Clock();
578
+ },
579
+ // 暂停漫游
580
+ pauseRoaming() {
581
+ this.$set(this.roamConfig, 'speed', 0);
582
+ },
583
+ // 结束/退出漫游
584
+ endRoam() {
585
+ roaming = false;
586
+ progress = 0;
587
+ this.removeObjectByName(this.roamConfig.roamName);
588
+ this.roamConfig = Object.assign(
589
+ {},
590
+ {
591
+ loop: false,
592
+ speed: 0,
593
+ roamName: '',
594
+ }
595
+ );
596
+ },
597
+ // 相机跟随轨道
598
+ cameraTrack() {
599
+ if (roaming) {
600
+ // renderEnabled = true
601
+ lineTexture.offset.x -= 0.05;
602
+ // 相机和控制器的偏移
603
+ let offset = 10 / curve.getLength();
604
+ if (progress <= 1 - offset) {
605
+ // this.timeRender()
606
+ const point = curve.getPointAt(progress);
607
+ const pointBox = curve.getPointAt(progress + offset);
608
+ camera.position.set(point.x, point.y + 5, point.z);
609
+ camera.lookAt(pointBox.x, pointBox.y + 5, pointBox.z);
610
+ cameraControls.setPosition(point.x, point.y + 5, point.z, false);
611
+ cameraControls.setTarget(pointBox.x, pointBox.y + 5, pointBox.z, false);
612
+ progress += this.roamConfig.speed / 300;
613
+ } else {
614
+ // 循环漫游
615
+ if (this.roamConfig.loop) {
616
+ progress = 0;
617
+ }
618
+ }
619
+ } else {
620
+ lineTexture = null;
621
+ this.roamConfig.progress = 0;
622
+ }
623
+ },
624
+ // 全局整体炸开
625
+ /**
626
+ * 参数val: 爆炸的值
627
+ */
628
+ globalBomb(val) {
629
+ if (scene.children.length === 0) return;
630
+ for (let i = 0; i < scene.children.length; i++) {
631
+ scene.children[i].traverse(item => {
632
+ if (!item.isMesh || !item.worldDir) return;
633
+ // 爆炸公式
634
+ this.computedBomb(item, val);
635
+ });
636
+ }
637
+ this.timeRender();
638
+ },
639
+ // 单个实体模型炸开
640
+ /*
641
+ 参数:
642
+ id: '',当前选中的实体对象的id
643
+ value: 0 - 100 整数
644
+ */
645
+ localBomb(id, value) {
646
+ let target = scene.getObjectById(id);
647
+ if (target) {
648
+ this.computedBomb(target, value);
649
+ }
650
+ },
651
+ computedBomb(object, val) {
652
+ let bombPosition = new this.THREE.Vector3()
653
+ .copy(object.userData.oldPs)
654
+ .add(new this.THREE.Vector3().copy(object.worldDir).multiplyScalar(val))
655
+ .add(new this.THREE.Vector3().copy(object.userData.position));
656
+ object.position.copy(bombPosition);
657
+ },
658
+ // 设置全局整体剖切
659
+ /*
660
+ 先开启模型全局剖切模式, 会返回剖切值的最大最小值
661
+ 剖切值变换时, 使用
662
+ */
663
+ setGlobalClipping() {
664
+ const box3 = new this.THREE.Box3().setFromObject(scene.children[0]);
665
+ let max = box3.max;
666
+ let min = box3.min;
667
+ const clippingPlanes = [
668
+ new this.THREE.Plane(new this.THREE.Vector3(-1, 0, 0), max.x),
669
+ new this.THREE.Plane(new this.THREE.Vector3(0, -1, 0), max.y),
670
+ new this.THREE.Plane(new this.THREE.Vector3(0, 0, -1), max.z),
671
+ ];
672
+ renderer.clippingPlanes = clippingPlanes;
673
+ return {
674
+ min: min,
675
+ max: max,
676
+ };
677
+ },
678
+ // 更新全局剖切的值
679
+ /*
680
+ 参数:Object
681
+ {x: 1, y: 0, z: 0} 可以传一个也可以传多个
682
+ */
683
+ updateGlobalCliValue(params) {
684
+ let axis = {
685
+ x: 0,
686
+ y: 1,
687
+ z: 2,
688
+ };
689
+ for (const key in params) {
690
+ renderer.clippingPlanes[axis[key]].constant = params[key];
691
+ }
692
+ // this.timeRender()
693
+ },
694
+ // 取消全局剖切
695
+ cancelGlobalClipping() {
696
+ renderer.clippingPlanes = Object.freeze([]);
697
+ },
698
+ // 单个实体的剖切/ 局部剖切 obj 实体对象
699
+ setLocalClipping(obj) {
700
+ renderer.localClippingEnabled = true;
701
+ // mesh的boundingBox 可以获取到该对象位置的最大最小值 但是在这里我们需要把y、z轴互换
702
+ const boundingBox = new this.THREE.Box3().copy(obj.geometry.boundingBox);
703
+ boundingBox.applyMatrix4(obj.matrixWorld);
704
+ clippingPlanes = [
705
+ new this.THREE.Plane(new this.THREE.Vector3(-1, 0, 0), Math.ceil(boundingBox.max.x)),
706
+ new this.THREE.Plane(new this.THREE.Vector3(0, -1, 0), Math.ceil(boundingBox.max.y)),
707
+ new this.THREE.Plane(new this.THREE.Vector3(0, 0, -1), Math.ceil(boundingBox.max.z)),
708
+ ];
709
+ obj.material.clippingPlanes = clippingPlanes;
710
+ obj.material.needsUpdate = true;
711
+ // 将局部剖切的对象记录下来
712
+ },
713
+ // 更新局部剖切的值
714
+ /*
715
+ 参数:Object
716
+ {x: 1, y: 0, z: 0} 可以传一个也可以传多个
717
+ */
718
+ updateLocalCliValue(params) {
719
+ let axis = {
720
+ x: 0,
721
+ y: 1,
722
+ z: 2,
723
+ };
724
+ for (const key in params) {
725
+ clippingPlanes[axis[key]].constant = params[key];
726
+ }
727
+ // this.timeRender()
728
+ },
729
+ // 取消局部/单个实体的剖切
730
+ cancelLocalClipping() {
731
+ clippingPlanes = Object.freeze([]);
732
+ },
733
+ // 开启第一视角
734
+ startFirstPer() {
735
+ clock = new this.THREE.Clock();
736
+ downRaycaster = new this.THREE.Raycaster(
737
+ new this.THREE.Vector3(),
738
+ new this.THREE.Vector3(0, -1, 0),
739
+ 0,
740
+ 10
741
+ );
742
+ velocity = new this.THREE.Vector3(); //移动速度变量
743
+ direction = new this.THREE.Vector3(); //移动的方向变量
744
+ firstPerSign = true;
745
+ this.initPointerLock();
746
+ },
747
+ // 页面是否锁定
748
+ initPointerLock() {
749
+ this.home();
750
+ setTimeout(() => {
751
+ pointControls = new PointerLockControls(camera, renderer.domElement);
752
+ pointControls.lock();
753
+ // 锁定
754
+ pointControls.addEventListener('lock', () => {
755
+ cameraControls.enabled = false;
756
+ window.addEventListener('keydown', this.onKeyDown, false);
757
+ window.addEventListener('keyup', this.onKeyUp, false);
758
+ renderer.domElement.removeEventListener('mouseup', this.mouseClick, false);
759
+ renderer.domElement.removeEventListener('mousedown', this.mouseDown, false);
760
+ });
761
+ // 解锁
762
+ pointControls.addEventListener('unlock', () => {
763
+ firstPerSign = false;
764
+ cameraControls.enabled = true;
765
+ // 返回初始视角
766
+ cameraControls.reset(true);
767
+ cameraControls.update(0);
768
+ setTimeout(() => {
769
+ window.removeEventListener('keydown', this.onKeyDown);
770
+ window.removeEventListener('keyup', this.onKeyUp);
771
+ renderer.domElement.addEventListener('mouseup', this.mouseClick, false);
772
+ renderer.domElement.addEventListener('mousedown', this.mouseDown, false);
773
+ // this.timeRender()
774
+ }, 0);
775
+ });
776
+ scene.add(pointControls.object);
777
+ }, 10);
778
+ },
779
+ // 第一视角运动
780
+ firstPerspective() {
781
+ if (!cameraControls.enabled && firstPerSign) {
782
+ // 获取到控制器对象
783
+ let control = pointControls.object;
784
+ // 获取刷新时间
785
+ let delta = clock.getDelta();
786
+ // velocity每次的速度,为了保证有过渡
787
+ velocity.x -= velocity.x * 10.0 * delta;
788
+ velocity.z -= velocity.z * 10.0 * delta;
789
+ velocity.y -= 9.8 * 100.0 * delta; // 默认下降的速度
790
+ // 获取当前按键的方向并获取朝哪个方向移动
791
+ direction.z = Number(moveForward) - Number(moveBackward);
792
+ direction.x = Number(moveRight) - Number(moveLeft);
793
+ // 将法向量的值归一化
794
+ direction.normalize();
795
+ if (moveForward || moveBackward) velocity.z -= direction.z * removeSpeed * delta;
796
+ if (moveLeft || moveRight) velocity.x -= direction.x * removeSpeed * delta;
797
+ // }
798
+ // 复制相机的位置
799
+ downRaycaster.ray.origin.copy(control.position);
800
+ // 获取相机靠下5的位置
801
+ downRaycaster.ray.origin.y += 5;
802
+ // 判断是否停留在了立方体上面
803
+ let intersections = downRaycaster.intersectObjects(scene.children, true);
804
+ var onObject = intersections.length > 0;
805
+ if (onObject === true) {
806
+ velocity.y = Math.max(0, velocity.y);
807
+ canJump = true;
808
+ }
809
+ // 根据速度值移动控制器
810
+ pointControls.moveRight(-velocity.x * delta);
811
+ pointControls.moveForward(-velocity.z * delta);
812
+ control.position.y += velocity.y * delta;
813
+ // 保证控制器的y轴在平面上
814
+ if (control.position.y < 3 - 0 / 10) {
815
+ velocity.y = -0 / 10;
816
+ control.position.y = 3 - 0 / 10;
817
+ canJump = true;
818
+ }
819
+ // this.timeRender()
820
+ }
821
+ },
822
+ // 键盘监听事件
823
+ onKeyDown(event) {
824
+ if (!event.keyCode) return;
825
+ // this.timeRender()
826
+ switch (event.keyCode) {
827
+ // 前进
828
+ case 38:
829
+ case 87:
830
+ moveForward = true;
831
+ break;
832
+ // 向左
833
+ case 37:
834
+ case 65:
835
+ moveLeft = true;
836
+ break;
837
+ // 后退
838
+ case 40:
839
+ case 83:
840
+ moveBackward = true;
841
+ break;
842
+ // 向右
843
+ case 39:
844
+ case 68:
845
+ moveRight = true;
846
+ break;
847
+ // 跳跃
848
+ case 32:
849
+ if (canJump && spaceUp) velocity.y += upSpeed;
850
+ canJump = false;
851
+ spaceUp = false;
852
+ break;
853
+ }
854
+ },
855
+ onKeyUp(event) {
856
+ if (!event.keyCode) return;
857
+ // this.timeRender()
858
+ switch (event.keyCode) {
859
+ // 前进
860
+ case 38:
861
+ case 87:
862
+ moveForward = false;
863
+ break;
864
+ // 向左
865
+ case 37:
866
+ case 65:
867
+ moveLeft = false;
868
+ break;
869
+ // 后退
870
+ case 40:
871
+ case 83:
872
+ moveBackward = false;
873
+ break;
874
+ // 向右
875
+ case 39:
876
+ case 68:
877
+ moveRight = false;
878
+ break;
879
+ // 跳跃
880
+ case 32:
881
+ spaceUp = true;
882
+ break;
883
+ }
884
+ },
885
+ // 返回主视角/恢复相机初始状态
886
+ home() {
887
+ // if (roaming) {
888
+ // this.disposeRoaming()
889
+ // }
890
+ cameraControls.reset(true);
891
+ cameraControls.update(0);
892
+ // this.timeRender()
893
+ },
894
+ // 测量
895
+ /*
896
+ 参数: type: '', distance、area、angle, 暂时只提供距离、面积、角度这三种方式
897
+ */
898
+ openMeasure(type) {
899
+ if (threeMeasure) {
900
+ threeMeasure.close();
901
+ threeMeasure = null;
902
+ }
903
+ measureFlag = true;
904
+ // renderEnabled = true
905
+ switch (type) {
906
+ case 'distance':
907
+ threeMeasure = new MeasureDistance.MeasureDistance(
908
+ renderer,
909
+ scene,
910
+ camera,
911
+ instructions.offsetWidth,
912
+ instructions.offsetHeight
913
+ );
914
+ threeMeasure.start();
915
+ break;
916
+ case 'area':
917
+ threeMeasure = new MeasureArea.MeasureArea(
918
+ renderer,
919
+ scene,
920
+ camera,
921
+ instructions.offsetWidth,
922
+ instructions.offsetHeight
923
+ );
924
+ threeMeasure.start();
925
+ break;
926
+ case 'angle':
927
+ threeMeasure = new MeasureAngle.MeasureAngle(
928
+ renderer,
929
+ scene,
930
+ camera,
931
+ instructions.offsetWidth,
932
+ instructions.offsetHeight
933
+ );
934
+ threeMeasure.start();
935
+ break;
936
+ }
937
+ },
938
+ // 关闭测量
939
+ closeMeasure() {
940
+ measureFlag = false;
941
+ if (threeMeasure) {
942
+ threeMeasure.close();
943
+ threeMeasure = null;
944
+ // this.timeRender()
945
+ }
946
+ },
947
+ // 开启平移
948
+ /*
949
+ 参数: object, 当前选中的对象, distance: {x: 0, y: 0, z: 0}, 平移的距离
950
+ */
951
+ translateMesh(object, distance) {
952
+ let translateMatrix = new this.THREE.Matrix4().makeTranslation(
953
+ distance.x,
954
+ distance.y,
955
+ distance.z
956
+ );
957
+ let translateMatrixInvert = new this.THREE.Matrix4().copy(translateMatrix).invert();
958
+ if (object.userData.translateMatrixInvert) {
959
+ object.applyMatrix4(object.userData.translateMatrixInvert);
960
+ }
961
+ object.userData.translateMatrixInvert = translateMatrixInvert;
962
+ object.applyMatrix4(translateMatrix);
963
+ object.userData.position = new this.THREE.Vector3().copy(object.position);
964
+ object.userData.translate = distance;
965
+ },
966
+ // 单个模型对象旋转
967
+ /*
968
+ 参数: object, 目标实体, degrees: {x: 0, y: 0, z: 0}, 旋转的数值(0-360)
969
+ */
970
+ rotateMesh(object, degrees) {
971
+ // 在矩阵的计算里 完成撤销操作是向量去乘以一个矩阵的逆矩阵
972
+ // 变化后的向量 = 原始向量 * 变化矩阵
973
+ // 逆矩阵 = 变化矩阵.inverse()
974
+ // 原始向量 = 变化后的向量 * 逆矩阵
975
+ let center = object.userData.center;
976
+ let v = new this.THREE.Vector3(center.x, center.y, center.z).negate();
977
+ let translateMatrix = new this.THREE.Matrix4().makeTranslation(v.x, v.y, v.z);
978
+ let rotateX = new this.THREE.Matrix4().makeRotationX(degrees.x * (Math.PI / 180));
979
+ let rotateY = new this.THREE.Matrix4().makeRotationY(degrees.y * (Math.PI / 180));
980
+ let rotateZ = new this.THREE.Matrix4().makeRotationZ(degrees.z * (Math.PI / 180));
981
+ let combineMatrix = new this.THREE.Matrix4()
982
+ .multiply(rotateX)
983
+ .multiply(rotateY)
984
+ .multiply(rotateZ);
985
+ object.applyMatrix4(translateMatrix);
986
+ let combineMatrixInvert = new this.THREE.Matrix4().copy(combineMatrix).invert();
987
+ if (object.userData.combineMatrixInvert) {
988
+ object.applyMatrix4(object.userData.combineMatrixInvert);
989
+ }
990
+ object.userData.combineMatrixInvert = combineMatrixInvert;
991
+ object.applyMatrix4(combineMatrix);
992
+ let translateM = new this.THREE.Matrix4().makeTranslation(center.x, center.y, center.z);
993
+ object.applyMatrix4(translateM);
994
+ object.userData.position = new this.THREE.Vector3().copy(object.position);
995
+ object.userData.rotate = degrees;
996
+ },
997
+ // 隔离
998
+ /*
999
+ 参数: object, 目标实体, params: {attr: 'visible/opacity', value: '(true/false)/(0-1)' 需要修改成的值},
1000
+ */
1001
+ isolate(object, params) {
1002
+ // 隔离 将目标实体以外的实体半透明掉或者隐藏掉
1003
+ scene.traverse(item => {
1004
+ if (item.isMesh && item.name !== object.name) {
1005
+ switch (params.attr) {
1006
+ case 'visible':
1007
+ object.material.visible = params.value;
1008
+ break;
1009
+ case 'opacity':
1010
+ object.material.opacity = params.value;
1011
+ object.material.transparent = true;
1012
+ break;
1013
+ }
1014
+ item.material.needsUpdate = true;
1015
+ }
1016
+ });
1017
+ },
1018
+ // 还原操作 将修改过的实体进行恢复
1019
+ restore() {
1020
+ scene.traverse(item => {
1021
+ if (item.isMesh) {
1022
+ item.material.opacity = 1.0;
1023
+ item.material.visible = true;
1024
+ item.material.transparent = true;
1025
+ item.material.color = item.material.userData.nColor;
1026
+ item.material.needsUpdate = true;
1027
+ item.userData.translate = {
1028
+ x: 0,
1029
+ y: 0,
1030
+ z: 0,
1031
+ };
1032
+ item.userData.rotate = {
1033
+ x: 0,
1034
+ y: 0,
1035
+ z: 0,
1036
+ };
1037
+ if (item.userData.translateMatrixInvert) {
1038
+ item.applyMatrix4(item.userData.translateMatrixInvert);
1039
+ item.userData.translateMatrixInvert = null;
1040
+ }
1041
+ if (item.userData.combineMatrixInvert) {
1042
+ this.rotateMesh(item, {
1043
+ x: 0,
1044
+ y: 0,
1045
+ z: 0,
1046
+ });
1047
+ item.userData.combineMatrixInvert = null;
1048
+ }
1049
+ }
1050
+ });
1051
+ },
1052
+ animate() {
1053
+ const delta = fpsClock.getDelta();
1054
+ timeStamp += delta;
1055
+ requestAnimationFrame(this.animate);
1056
+ cameraControls.enabled && cameraControls.update(timeStamp);
1057
+ this.cameraTrack();
1058
+ this.firstPerspective();
1059
+ labelRenderer.render(scene, camera);
1060
+ renderer.render(scene, camera);
1061
+ },
229
1062
  },
230
- },
231
-
232
- }
1063
+ };
233
1064
  </script>
234
1065
  <style lang="scss" scoped>
235
- #instructions{
236
- width: 100%;
237
- height: 100%;
238
- cursor: pointer;
239
- }
240
- </style>
1066
+ #instructions {
1067
+ width: 100%;
1068
+ height: 100%;
1069
+ cursor: pointer;
1070
+ }
1071
+ </style>