fl-web-component 2.0.0-beta.9 → 2.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 (34) hide show
  1. package/README.md +5 -0
  2. package/dist/fl-web-component.common.js +34766 -1686
  3. package/dist/fl-web-component.common.js.map +1 -1
  4. package/dist/fl-web-component.css +1 -1
  5. package/package.json +4 -15
  6. package/packages/components/com-card/index.vue +1 -1
  7. package/packages/components/com-flcanvas/components/bspline.js +31 -34
  8. package/packages/components/com-flcanvas/components/entityFormatting.js +810 -823
  9. package/packages/components/com-flcanvas/components/round10.js +17 -17
  10. package/packages/components/com-flcanvas/index.vue +314 -333
  11. package/packages/components/com-formDialog/index.vue +6 -4
  12. package/packages/components/com-graphics/component/ann-tool.vue +263 -208
  13. package/packages/components/com-graphics/index.vue +374 -773
  14. package/packages/components/com-graphics/pid.vue +304 -295
  15. package/packages/components/com-table/column-default.vue +2 -3
  16. package/packages/components/com-table/column-dynamic.vue +7 -4
  17. package/packages/components/com-table/column.vue +1 -2
  18. package/packages/components/com-table/index.vue +6 -5
  19. package/packages/components/com-tabs/index.vue +1 -2
  20. package/packages/components/com-tiles/index.vue +134 -136
  21. package/packages/components/com-treeDynamic/index.vue +1 -1
  22. package/packages/utils/StreamLoader.js +95 -36
  23. package/packages/utils/StreamLoaderParser.worker.js +9 -14
  24. package/src/main.js +2 -8
  25. package/src/utils/cloud.js +28 -28
  26. package/src/utils/cursor.js +11 -9
  27. package/src/utils/flgltf-parser.js +257 -245
  28. package/src/utils/instance-parser.js +20 -22
  29. package/src/utils/mini-devtool.js +94 -39
  30. package/src/utils/threejs/measure-angle.js +51 -13
  31. package/src/utils/threejs/measure-area.js +44 -13
  32. package/src/utils/threejs/measure-distance.js +43 -12
  33. package/src/utils/threejs/rain-shader.js +10 -10
  34. package/src/utils/threejs/snow-shader.js +9 -9
@@ -12,10 +12,13 @@
12
12
  v-if="column.children && column.children.length > 0"
13
13
  :key="column.label"
14
14
  :columnOption="column"
15
- >
16
- </column-dynamic>
17
- <column-slot v-else :column="column" :column-option="columnOption.children" :key="column.id">
18
- </column-slot>
15
+ ></column-dynamic>
16
+ <column-slot
17
+ v-else
18
+ :column="column"
19
+ :column-option="columnOption.children"
20
+ :key="column.id"
21
+ ></column-slot>
19
22
  </template>
20
23
  </component>
21
24
  </template>
@@ -7,8 +7,7 @@
7
7
  v-if="column.children && column.children.length > 0"
8
8
  :columnOption="column"
9
9
  :key="column.label"
10
- >
11
- </column-dynamic>
10
+ ></column-dynamic>
12
11
  <column-slot v-else :column="column" :column-option="columnOption" :key="column.id">
13
12
  <template v-for="item in comTable.mainSlot" slot-scope="scope" :slot="item">
14
13
  <slot v-bind="scope" :name="item"></slot>
@@ -15,8 +15,9 @@
15
15
  size="small"
16
16
  @click="clearSelection"
17
17
  v-if="vaildData(tableOption.selectClearBtn, config.selectClearBtn) && tableOption.selection"
18
- >{{ '清 空' }}</el-button
19
18
  >
19
+ {{ '清 空' }}
20
+ </el-button>
20
21
  </el-tag>
21
22
  <!-- 表格主体 -->
22
23
  <el-table
@@ -57,7 +58,7 @@
57
58
  </column>
58
59
  </el-table>
59
60
  <!-- 分页 -->
60
- <table-page ref="tablePage"> </table-page>
61
+ <table-page ref="tablePage"></table-page>
61
62
  </div>
62
63
  </template>
63
64
  <script>
@@ -121,7 +122,7 @@ export default {
121
122
  mainSlot() {
122
123
  let result = [];
123
124
 
124
- this.propOption.forEach((item) => {
125
+ this.propOption.forEach(item => {
125
126
  if (this.$scopedSlots[item.prop]) result.push(item.prop);
126
127
  });
127
128
 
@@ -134,7 +135,7 @@ export default {
134
135
  let result = [];
135
136
  function findProp(list = []) {
136
137
  if (!Array.isArray(list)) return;
137
- list.forEach((ele) => {
138
+ list.forEach(ele => {
138
139
  if (Array.isArray(ele.children)) findProp(ele.children);
139
140
  else result.push(ele);
140
141
  });
@@ -273,7 +274,7 @@ export default {
273
274
  sortable.create(el, {
274
275
  animation: 500,
275
276
  delay: 0,
276
- onEnd: (evt) => callback(evt),
277
+ onEnd: evt => callback(evt),
277
278
  });
278
279
  },
279
280
  },
@@ -11,8 +11,7 @@
11
11
  :label="column.label"
12
12
  v-for="(column, index) in columnOption"
13
13
  :key="index"
14
- >
15
- </el-tab-pane>
14
+ ></el-tab-pane>
16
15
  </el-tabs>
17
16
  </template>
18
17
 
@@ -5,17 +5,18 @@
5
5
  import CameraControls from 'camera-controls';
6
6
  import { TilesRenderer } from '3d-tiles-renderer';
7
7
  import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
8
- var instructions, renderer, cameraControls, scene, camera, renderTarget, tilesRenderer
9
- var timeStamp = 0, animateId, singleFrameTime = 1 / 30, frameCount = 0
10
- var needsRerender = false
8
+ var instructions, renderer, cameraControls, scene, camera, renderTarget, tilesRenderer;
9
+ var animateId,
10
+ singleFrameTime = 1 / 30,
11
+ frameCount = 0;
12
+ var needsRerender = false;
11
13
  var [fpsClock, timeStamp] = (function* (v) {
12
14
  while (true) yield v;
13
15
  })(0);
14
16
  export default {
15
17
  name: 'FlTiles',
16
18
  data() {
17
- return {
18
- }
19
+ return {};
19
20
  },
20
21
  created() {
21
22
  CameraControls.install({ THREE: this.THREE });
@@ -36,152 +37,149 @@ export default {
36
37
  this.initLight();
37
38
  this.init3tiles();
38
39
  cameraControls.addEventListener('wake', () => {
39
- console.log(cameraControls._camera.position)
40
- })
40
+ console.log(cameraControls._camera.position);
41
+ });
41
42
  this.animate();
42
43
  },
43
44
  methods: {
44
- initRender() {
45
- renderer = new this.THREE.WebGLRenderer({
46
- antialias: true,
47
- logarithmicDepthBuffer: true,
48
- });
49
- renderer.setPixelRatio(window.devicePixelRatio * 2);
50
- renderer.setSize(window.innerWidth, window.innerHeight);
51
- renderer.domElement.id = 'three-model';
52
- renderer.shadowMap.enabled = true;
53
- instructions.appendChild(renderer.domElement);
54
- },
55
- initScene() {
56
- scene = new this.THREE.Scene();
57
- scene.background = new this.THREE.Color(0xffffff)
58
- },
59
- initCamera() {
60
- camera = new this.THREE.PerspectiveCamera(
61
- 45,
62
- window.innerWidth / window.innerHeight,
63
- 0.1,
64
- 10000000
65
- );
66
- camera.position.set(
67
- 0,
68
- 10,
69
- 105.524230957031
70
- );
71
- },
72
- initControl() {
73
- // 初始化控件
74
- cameraControls = new CameraControls(camera, renderer.domElement);
75
- cameraControls.dollyToCursor = true;
76
- cameraControls.smoothTime = 0.1;
77
- cameraControls.draggingSmoothTime = 0.05;
78
- cameraControls.truckSpeed = 2.0;
79
- cameraControls.infinityDolly = true;
80
- cameraControls.minDistance = 4;
81
- },
82
- // 初始化光源
83
- initLight() {
84
- const pmremGenerator = new this.THREE.PMREMGenerator(renderer);
85
- scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
86
- },
87
- init3tiles() {
88
- // 这个文件需要放到public文件夹下 Tile_+003_+003/Tile_+003_+003
89
- tilesRenderer = new TilesRenderer('/tiles/tileset.json')
90
- tilesRenderer.setCamera(camera);
91
- tilesRenderer.setResolutionFromRenderer(camera, renderer)
92
- scene.add(tilesRenderer.group);
93
-
94
- setTimeout(() => (
95
- needsRerender = true
96
- ), 1000)
97
- },
98
- // 添加一个标志,等待一帧让TilesRenderer初步解析JSON
99
- debugTileset() {
100
- if (tilesRenderer.root && frameCount++ < 10) { // 检查前几帧
101
- console.log('[调试] TilesRenderer根节点:', tilesRenderer.root);
102
-
103
- // 1. 尝试获取根节点的包围盒 (通常很大,是整个世界范围)
104
- if (tilesRenderer.root.boundingVolume) {
105
- console.log('[调试] 根节点包围盒:', tilesRenderer.root.boundingVolume);
106
- // 如果是BOX类型,可以获取其中心
107
- if (tilesRenderer.root.boundingVolume.box) {
108
- const box = tilesRenderer.root.boundingVolume.box;
109
- // box: [中心x, 中心y, 中心z, x轴半长, y轴半长, z轴半长]
110
- console.log(`[调试] 根节点包围盒中心: [${box[0]}, ${box[1]}, ${box[2]}]`);
111
- }
112
- }
113
-
114
- // 2. 检查第一个子节点(中间节点)
115
- if (tilesRenderer.root.children && tilesRenderer.root.children[0]) {
116
- const firstChild = tilesRenderer.root.children[0];
117
- console.log('[调试] 第一个子节点:', firstChild);
118
- if (firstChild.boundingVolume) {
119
- console.log('[调试] 第一个子节点包围盒:', firstChild.boundingVolume);
120
- }
121
- }
122
-
123
- // 3. 如果中间节点还有children,继续往下找
124
- if (tilesRenderer.root.children &&
125
- tilesRenderer.root.children[0] &&
126
- tilesRenderer.root.children[0].children &&
127
- tilesRenderer.root.children[0].children[0]) {
128
- const deepestChild = tilesRenderer.root.children[0].children[0];
129
- console.log('[调试] 更深层的子节点:', deepestChild);
130
- if (deepestChild.content) {
131
- console.log('[调试] 首个Content URI:', deepestChild.content.uri);
132
- }
133
- }
45
+ initRender() {
46
+ renderer = new this.THREE.WebGLRenderer({
47
+ antialias: true,
48
+ logarithmicDepthBuffer: true,
49
+ });
50
+ renderer.setPixelRatio(window.devicePixelRatio * 2);
51
+ renderer.setSize(window.innerWidth, window.innerHeight);
52
+ renderer.domElement.id = 'three-model';
53
+ renderer.shadowMap.enabled = true;
54
+ instructions.appendChild(renderer.domElement);
55
+ },
56
+ initScene() {
57
+ scene = new this.THREE.Scene();
58
+ scene.background = new this.THREE.Color(0xffffff);
59
+ },
60
+ initCamera() {
61
+ camera = new this.THREE.PerspectiveCamera(
62
+ 45,
63
+ window.innerWidth / window.innerHeight,
64
+ 0.1,
65
+ 10000000
66
+ );
67
+ camera.position.set(0, 10, 105.524230957031);
68
+ },
69
+ initControl() {
70
+ // 初始化控件
71
+ cameraControls = new CameraControls(camera, renderer.domElement);
72
+ cameraControls.dollyToCursor = true;
73
+ cameraControls.smoothTime = 0.1;
74
+ cameraControls.draggingSmoothTime = 0.05;
75
+ cameraControls.truckSpeed = 2.0;
76
+ cameraControls.infinityDolly = true;
77
+ cameraControls.minDistance = 4;
78
+ },
79
+ // 初始化光源
80
+ initLight() {
81
+ const pmremGenerator = new this.THREE.PMREMGenerator(renderer);
82
+ scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
83
+ },
84
+ init3tiles() {
85
+ // 这个文件需要放到public文件夹下 Tile_+003_+003/Tile_+003_+003
86
+ tilesRenderer = new TilesRenderer('/tiles/tileset.json');
87
+ tilesRenderer.setCamera(camera);
88
+ tilesRenderer.setResolutionFromRenderer(camera, renderer);
89
+ scene.add(tilesRenderer.group);
90
+
91
+ setTimeout(() => (needsRerender = true), 1000);
92
+ },
93
+ // 添加一个标志,等待一帧让TilesRenderer初步解析JSON
94
+ debugTileset() {
95
+ if (tilesRenderer.root && frameCount++ < 10) {
96
+ // 检查前几帧
97
+ console.log('[调试] TilesRenderer根节点:', tilesRenderer.root);
98
+
99
+ // 1. 尝试获取根节点的包围盒 (通常很大,是整个世界范围)
100
+ if (tilesRenderer.root.boundingVolume) {
101
+ console.log('[调试] 根节点包围盒:', tilesRenderer.root.boundingVolume);
102
+ // 如果是BOX类型,可以获取其中心
103
+ if (tilesRenderer.root.boundingVolume.box) {
104
+ const box = tilesRenderer.root.boundingVolume.box;
105
+ // box: [中心x, 中心y, 中心z, x轴半长, y轴半长, z轴半长]
106
+ console.log(`[调试] 根节点包围盒中心: [${box[0]}, ${box[1]}, ${box[2]}]`);
134
107
  }
135
- },
136
- animate() {
137
- // const delta = fpsClock.getDelta();
138
- // timeStamp += delta;
139
- // requestAnimationFrame(this.animate)
140
- // if (needsRerender) {
108
+ }
141
109
 
142
- // needsRerender = false;
143
- // let box = new this.THREE.Box3()
144
-
145
- // if (tilesRenderer.getBoundingBox(box)) {
110
+ // 2. 检查第一个子节点(中间节点)
111
+ if (tilesRenderer.root.children && tilesRenderer.root.children[0]) {
112
+ const firstChild = tilesRenderer.root.children[0];
113
+ console.log('[调试] 第一个子节点:', firstChild);
114
+ if (firstChild.boundingVolume) {
115
+ console.log('[调试] 第一个子节点包围盒:', firstChild.boundingVolume);
116
+ }
117
+ }
146
118
 
147
- // box.getCenter(tilesRenderer.group.position);
119
+ // 3. 如果中间节点还有children,继续往下找
120
+ if (
121
+ tilesRenderer.root.children &&
122
+ tilesRenderer.root.children[0] &&
123
+ tilesRenderer.root.children[0].children &&
124
+ tilesRenderer.root.children[0].children[0]
125
+ ) {
126
+ const deepestChild = tilesRenderer.root.children[0].children[0];
127
+ console.log('[调试] 更深层的子节点:', deepestChild);
128
+ if (deepestChild.content) {
129
+ console.log('[调试] 首个Content URI:', deepestChild.content.uri);
130
+ }
131
+ }
132
+ }
133
+ },
134
+ animate() {
135
+ // const delta = fpsClock.getDelta();
136
+ // timeStamp += delta;
137
+ // requestAnimationFrame(this.animate)
138
+ // if (needsRerender) {
139
+
140
+ // needsRerender = false;
141
+ // let box = new this.THREE.Box3()
142
+
143
+ // if (tilesRenderer.getBoundingBox(box)) {
148
144
 
149
- // tilesRenderer.group.position.multiplyScalar(-1);
145
+ // box.getCenter(tilesRenderer.group.position);
150
146
 
151
- // }
147
+ // tilesRenderer.group.position.multiplyScalar(-1);
152
148
 
153
- // tilesRenderer.update();
149
+ // }
154
150
 
155
- // }
156
- // cameraControls.update(timeStamp)
157
- // tilesRenderer.update();
158
- // renderer.render(scene, camera);
159
- const delta = fpsClock.getDelta();
160
- timeStamp += delta;
161
- animateId = requestAnimationFrame(this.animate);
162
- if (timeStamp > singleFrameTime) {
163
- if (needsRerender) {
164
- needsRerender = false
165
- let box = new this.THREE.Box3()
166
- if (tilesRenderer.getBoundingBox(box)) {
167
- box.getCenter(tilesRenderer.group.position)
168
- tilesRenderer.group.position.multiplyScalar(-1)
169
- }
151
+ // tilesRenderer.update();
152
+
153
+ // }
154
+ // cameraControls.update(timeStamp)
155
+ // tilesRenderer.update();
156
+ // renderer.render(scene, camera);
157
+ const delta = fpsClock.getDelta();
158
+ timeStamp += delta;
159
+ animateId = requestAnimationFrame(this.animate);
160
+ if (timeStamp > singleFrameTime) {
161
+ if (needsRerender) {
162
+ needsRerender = false;
163
+ let box = new this.THREE.Box3();
164
+ if (tilesRenderer.getBoundingBox(box)) {
165
+ box.getCenter(tilesRenderer.group.position);
166
+ tilesRenderer.group.position.multiplyScalar(-1);
170
167
  }
171
- cameraControls.update(timeStamp);
172
- // this.debugTileset();
173
- tilesRenderer.update();
174
- renderer.render(scene, camera);
175
- timeStamp = timeStamp % singleFrameTime;
176
168
  }
177
- },
178
- }
179
- }
169
+ cameraControls.update(timeStamp);
170
+ // this.debugTileset();
171
+ tilesRenderer.update();
172
+ renderer.render(scene, camera);
173
+ timeStamp = timeStamp % singleFrameTime;
174
+ }
175
+ },
176
+ },
177
+ };
180
178
  </script>
181
179
  <style lang="scss" scoped>
182
- #three-box{
180
+ #three-box {
183
181
  width: 100%;
184
182
  height: 100%;
185
183
  overflow: hidden;
186
184
  }
187
- </style>
185
+ </style>
@@ -44,7 +44,7 @@
44
44
  <span :title="node.label" class="title_tree">{{ node.label }}</span>
45
45
  </span>
46
46
  <span class="tree_operation" style="display: inline-block; width: 80px; text-align: right">
47
- <slot v-if="treeNodeHandle" class="fr_text" :data="data"> 操作按钮 </slot>
47
+ <slot v-if="treeNodeHandle" class="fr_text" :data="data">操作按钮</slot>
48
48
  </span>
49
49
  </span>
50
50
  </el-tree>
@@ -93,6 +93,46 @@ export class StreamLoader {
93
93
  }
94
94
  }
95
95
 
96
+ /**
97
+ * 将合并材质数据覆盖到原材质数据中(仅覆盖 merge 中明确提供的字段)
98
+ * 规则:mergeMaterialData 中 id 在 materialData 出现过的,覆盖其 color/transp
99
+ * 注意:应在 _applyPrefixId(materialData, 'id') 之前调用(使用原始 id 对比)
100
+ * @param {Array<Object>|Object|null} materialData
101
+ * @param {Array<Object>|Object|null} mergeMaterialData
102
+ * @returns {Array<Object>|Object|null} materialData(原地修改后返回)
103
+ */
104
+ _mergeMaterialDataOverrides(materialData, mergeMaterialData) {
105
+ if (!materialData || !mergeMaterialData) return materialData;
106
+
107
+ const materials = Array.isArray(materialData) ? materialData : [materialData];
108
+ const merges = Array.isArray(mergeMaterialData) ? mergeMaterialData : [mergeMaterialData];
109
+ if (materials.length === 0 || merges.length === 0) return materialData;
110
+
111
+ const mergeById = new Map();
112
+ for (let i = 0; i < merges.length; i++) {
113
+ const m = merges[i];
114
+ if (!m || m.id == null) continue;
115
+ mergeById.set(String(m.id), m);
116
+ }
117
+ if (mergeById.size === 0) return materialData;
118
+
119
+ for (let i = 0; i < materials.length; i++) {
120
+ const mat = materials[i];
121
+ if (!mat || mat.id == null) continue;
122
+ const merge = mergeById.get(String(mat.id));
123
+ if (!merge) continue;
124
+
125
+ if (merge.color !== undefined) {
126
+ mat.color = merge.color;
127
+ }
128
+ if (merge.transp !== undefined) {
129
+ mat.transp = merge.transp;
130
+ }
131
+ }
132
+
133
+ return materialData;
134
+ }
135
+
96
136
  workerRequest(type, data, transferable = []) {
97
137
  if (!this.worker) {
98
138
  return Promise.reject(new Error('Worker is not initialized'));
@@ -175,13 +215,7 @@ export class StreamLoader {
175
215
  const meshesToProcess = batchMeshes.slice(batchStart, batchStart + batchSize);
176
216
  const primitivesToProcess = batchPrimitives.slice(batchStart, batchStart + batchSize);
177
217
  batchStart += batchSize;
178
- this.processBatchData(
179
- meshesToProcess,
180
- primitivesToProcess,
181
- list,
182
- range,
183
- abortSignal
184
- );
218
+ this.processBatchData(meshesToProcess, primitivesToProcess, list, range, abortSignal);
185
219
  }
186
220
 
187
221
  if (batchMeshes.length - batchStart > 0) {
@@ -192,13 +226,7 @@ export class StreamLoader {
192
226
  const meshesToProcess = batchMeshes.slice(batchStart);
193
227
  const primitivesToProcess = batchPrimitives.slice(batchStart);
194
228
  batchStart = batchMeshes.length;
195
- this.processBatchData(
196
- meshesToProcess,
197
- primitivesToProcess,
198
- list,
199
- range,
200
- abortSignal
201
- );
229
+ this.processBatchData(meshesToProcess, primitivesToProcess, list, range, abortSignal);
202
230
  }
203
231
  break;
204
232
  }
@@ -228,13 +256,7 @@ export class StreamLoader {
228
256
  const meshesToProcess = batchMeshes.slice(batchStart, batchStart + batchSize);
229
257
  const primitivesToProcess = batchPrimitives.slice(batchStart, batchStart + batchSize);
230
258
  batchStart += batchSize;
231
- this.processBatchData(
232
- meshesToProcess,
233
- primitivesToProcess,
234
- list,
235
- range,
236
- abortSignal
237
- );
259
+ this.processBatchData(meshesToProcess, primitivesToProcess, list, range, abortSignal);
238
260
  }
239
261
 
240
262
  if (batchStart >= batchSize * 4) {
@@ -258,7 +280,6 @@ export class StreamLoader {
258
280
  let expectingPrimitive = true;
259
281
  let isFullProps = true;
260
282
 
261
-
262
283
  while (true) {
263
284
  await ensureNotAborted();
264
285
 
@@ -440,7 +461,7 @@ export class StreamLoader {
440
461
  throw new DOMException('Request was aborted', 'AbortError');
441
462
  }
442
463
  params.requestId = requestId;
443
- params.projectId = this.projectId
464
+ params.projectId = this.projectId;
444
465
  let res;
445
466
  if (this.modelApi && typeof this.modelApi.getPrimitivesByRangeStream === 'function') {
446
467
  res = await this.modelApi.getPrimitivesByRangeStream(params, internalController.signal);
@@ -510,6 +531,20 @@ export class StreamLoader {
510
531
  }
511
532
  }
512
533
 
534
+ async getPrimitivesByMergeMaterial(params) {
535
+ try {
536
+ if (!this.modelApi || typeof this.modelApi.getPrimitivesByMergeMaterial !== 'function') {
537
+ return null;
538
+ }
539
+
540
+ const res = await this.modelApi.getPrimitivesByMergeMaterial(params);
541
+ return res || null;
542
+ } catch (error) {
543
+ // mergeMaterial 是可选能力:接口异常时降级为不合并
544
+ return null;
545
+ }
546
+ }
547
+
513
548
  createAbortableRequest(requestKey = null) {
514
549
  const requestId = requestKey || `req_${++this.requestCounter}`;
515
550
 
@@ -814,7 +849,10 @@ export class StreamLoader {
814
849
  const key = keyOrder[i];
815
850
  const typeCode = dataTypeString[i];
816
851
  const typeInfo = typeMap[typeCode];
817
- const uint8Array = primitive.isCompressed === 1 || primitive.isCompressed === undefined ? gunzipSync(primitive[key]) : primitive[key];
852
+ const uint8Array =
853
+ primitive.isCompressed === 1 || primitive.isCompressed === undefined
854
+ ? gunzipSync(primitive[key])
855
+ : primitive[key];
818
856
  if (!typeInfo || !uint8Array) {
819
857
  console.warn(`无法找到键 "${key}" 或其类型定义,已跳过。`);
820
858
  parsedResult[key] = [];
@@ -1152,7 +1190,14 @@ export class StreamLoader {
1152
1190
  const { mesh, primitives: parsed } = await this.parseBufferData(buffer);
1153
1191
  primitives = parsed;
1154
1192
 
1155
- await this.renderModelData(mesh, primitives, params.folderInfo, null, onComplete, params.immediateUpdate ?? true);
1193
+ await this.renderModelData(
1194
+ mesh,
1195
+ primitives,
1196
+ params.folderInfo,
1197
+ null,
1198
+ onComplete,
1199
+ params.immediateUpdate ?? true
1200
+ );
1156
1201
 
1157
1202
  return { primitives, mesh };
1158
1203
  } catch (err) {
@@ -1202,7 +1247,7 @@ export class StreamLoader {
1202
1247
  // 其他
1203
1248
  // ----------------------------------------------------------------
1204
1249
 
1205
- async getSceneBox({id, projectId = this.projectId}) {
1250
+ async getSceneBox({ id, projectId = this.projectId }) {
1206
1251
  const res = await this.modelApi.getSceneBox({ id, projectId });
1207
1252
  if (res && res[0]) {
1208
1253
  this.sceneBox = res[0];
@@ -1212,7 +1257,7 @@ export class StreamLoader {
1212
1257
  }
1213
1258
  }
1214
1259
 
1215
- async getBox({id, projectId = this.projectId || 0}) {
1260
+ async getBox({ id, projectId = this.projectId || 0 }) {
1216
1261
  // 1. 尝试从 IndexedDB 读取
1217
1262
  const cached = await this._getFromDB(id, projectId);
1218
1263
  if (cached) {
@@ -1354,11 +1399,12 @@ export class StreamLoader {
1354
1399
  }
1355
1400
  }
1356
1401
 
1357
- updateModelRegistry(item, materialData, sceneBox, boxIndex) {
1402
+ updateModelRegistry(item, materialData, mergeMaterialData, sceneBox, boxIndex) {
1358
1403
  if (item && item.id) {
1359
1404
  this.modelRegistry.set(item.id, {
1360
1405
  item,
1361
1406
  materialData,
1407
+ mergeMaterialData,
1362
1408
  sceneBox,
1363
1409
  boxIndex,
1364
1410
  });
@@ -1402,12 +1448,22 @@ export class StreamLoader {
1402
1448
 
1403
1449
  async processModelItem(item, options = {}) {
1404
1450
  try {
1405
- if(typeof item.id !== 'string'){
1406
- item.id = "" + item.id;
1451
+ if (typeof item.id !== 'string') {
1452
+ item.id = '' + item.id;
1407
1453
  }
1408
1454
 
1409
1455
  // 获取材质数据
1410
- const materialData = await this.getPrimitivesByMaterial({ id: item.id, projectId: this.projectId });
1456
+ const materialData = await this.getPrimitivesByMaterial({
1457
+ id: item.id,
1458
+ projectId: this.projectId,
1459
+ });
1460
+
1461
+ // 获取合并材质数据
1462
+ const mergeMaterialData = await this.getPrimitivesByMergeMaterial({
1463
+ id: item.id,
1464
+ projectId: this.projectId,
1465
+ });
1466
+ this._applyPrefixId(mergeMaterialData, 'id');
1411
1467
  this._applyPrefixId(materialData, 'id');
1412
1468
 
1413
1469
  // 获取场景包围盒
@@ -1418,11 +1474,14 @@ export class StreamLoader {
1418
1474
  const boxIndex = await this.getBox({ id: item.id, projectId: this.projectId });
1419
1475
  this.boxIndex = boxIndex;
1420
1476
 
1421
- const modelResourceMapObj = { materialData, item };
1477
+ // mergeMaterialData 覆盖到 materialData(按 id 覆盖 color/transp)
1478
+ this._mergeMaterialDataOverrides(boxIndex, mergeMaterialData);
1479
+
1480
+ const modelResourceMapObj = { materialData, mergeMaterialData, item };
1422
1481
 
1423
1482
  // 设置当前模型到注册表
1424
- this.updateModelRegistry(item, materialData, sceneBox, boxIndex);
1425
- console.log('modelRegistry', this.modelRegistry)
1483
+ this.updateModelRegistry(item, materialData, mergeMaterialData, sceneBox, boxIndex);
1484
+ console.log('modelRegistry', this.modelRegistry);
1426
1485
 
1427
1486
  return { modelResourceMap: modelResourceMapObj, sceneBox, boxIndex, item };
1428
1487
  } catch (error) {
@@ -1448,7 +1507,7 @@ export class StreamLoader {
1448
1507
  resolve(null);
1449
1508
  };
1450
1509
  request.onsuccess = () => resolve(request.result);
1451
- request.onupgradeneeded = (event) => {
1510
+ request.onupgradeneeded = event => {
1452
1511
  const db = event.target.result;
1453
1512
  if (!db.objectStoreNames.contains('boxCache')) {
1454
1513
  db.createObjectStore('boxCache');
@@ -1462,7 +1521,7 @@ export class StreamLoader {
1462
1521
  try {
1463
1522
  const db = await this._initDB();
1464
1523
  if (!db) return null;
1465
- return new Promise((resolve) => {
1524
+ return new Promise(resolve => {
1466
1525
  const transaction = db.transaction(['boxCache'], 'readonly');
1467
1526
  const store = transaction.objectStore('boxCache');
1468
1527
  const request = store.get(`${projectId}:${id}`);