fl-web-component 1.4.7 → 1.4.9-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/README.md +1 -28
- package/dist/fl-web-component.common.1.js +2 -2
- package/dist/fl-web-component.common.1.js.map +1 -1
- package/dist/fl-web-component.common.2.js.map +1 -1
- package/dist/fl-web-component.common.js +77420 -47296
- package/dist/fl-web-component.common.js.map +1 -1
- package/dist/fl-web-component.css +1 -1
- package/package.json +12 -4
- package/packages/components/com-flcanvas/components/entityFormatting.js +9 -1
- package/packages/components/com-graphics/box.json +77 -0
- package/packages/components/com-graphics/component/ann-tool.vue +465 -0
- package/packages/components/com-graphics/index copy.vue +1679 -0
- package/packages/components/com-graphics/index.vue +3890 -301
- package/packages/components/com-graphics/pid.vue +210 -44
- package/packages/components/com-graphics/test.html +127 -0
- package/packages/components/com-tiles/index.vue +187 -0
- package/packages/utils/StreamLoader.js +1498 -0
- package/packages/utils/StreamLoaderParser.worker.js +595 -0
- package/patches/camera-controls+2.9.0.patch +63 -63
- package/src/main.js +9 -1
- package/src/static/ann-img/mark_circle@2x.png +0 -0
- package/src/static/ann-img/mark_clear@2x.png +0 -0
- package/src/static/ann-img/mark_cloud@2x.png +0 -0
- package/src/static/ann-img/mark_color@2x.png +0 -0
- package/src/static/ann-img/mark_eraser@2x.png +0 -0
- package/src/static/ann-img/mark_exit@2x.png +0 -0
- package/src/static/ann-img/mark_finish@2x.png +0 -0
- package/src/static/ann-img/mark_font@2x.png +0 -0
- package/src/static/ann-img/mark_polyline@2x.png +0 -0
- package/src/static/ann-img/mark_rectangle@2x.png +0 -0
- package/src/static/ann-img/mark_zoomin@2x.png +0 -0
- package/src/static/ann-img/mark_zoomout@2x.png +0 -0
- package/src/utils/cloud.js +110 -0
- package/src/utils/cursor.js +10 -0
- package/src/utils/flgltf-parser.js +245 -193
- package/src/utils/instance-parser.js +718 -170
- package/dist/fl-web-component.common.3.js +0 -7740
- package/dist/fl-web-component.common.3.js.map +0 -1
|
@@ -3,6 +3,7 @@ import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';
|
|
|
3
3
|
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js';
|
|
4
4
|
import helvetikerFont from 'three/examples/fonts/helvetiker_regular.typeface.json';
|
|
5
5
|
import { MeshLineGeometry, MeshLineMaterial } from 'meshline';
|
|
6
|
+
import StreamLoaderParserWorker from '../../packages/utils/StreamLoaderParser.worker.js';
|
|
6
7
|
|
|
7
8
|
const GEOM_TYPES = {
|
|
8
9
|
geom_3d: 53248,
|
|
@@ -38,13 +39,142 @@ const TextAlign = {
|
|
|
38
39
|
TextFit: 14,
|
|
39
40
|
};
|
|
40
41
|
|
|
42
|
+
// 图元加载模式
|
|
43
|
+
const PRIMITIVE_TYPE = {
|
|
44
|
+
full: 2, // 全量加载
|
|
45
|
+
onlyBounding: 1, // 仅加载边界框
|
|
46
|
+
};
|
|
47
|
+
|
|
41
48
|
let drawObjMapInstance = {};
|
|
49
|
+
// 使用Set来跟踪已处理的drawObject,避免重复创建group
|
|
50
|
+
// let processedDrawObjects = new Set();
|
|
51
|
+
let instanceToInstancedMeshMap = new Map();
|
|
52
|
+
let instancedMappingWorker = null;
|
|
53
|
+
let instancedMappingWorkerRequestId = 0;
|
|
54
|
+
const instancedMappingWorkerRequests = new Map();
|
|
55
|
+
|
|
56
|
+
function ensureInstancedMappingWorker() {
|
|
57
|
+
if (instancedMappingWorker) return instancedMappingWorker;
|
|
58
|
+
try {
|
|
59
|
+
instancedMappingWorker = new StreamLoaderParserWorker();
|
|
60
|
+
} catch (e) {
|
|
61
|
+
instancedMappingWorker = null;
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
instancedMappingWorker.addEventListener('message', e => {
|
|
65
|
+
const payload = e.data || {};
|
|
66
|
+
const pending = instancedMappingWorkerRequests.get(payload.id);
|
|
67
|
+
if (!pending) return;
|
|
68
|
+
instancedMappingWorkerRequests.delete(payload.id);
|
|
69
|
+
if (payload.type === 'success') {
|
|
70
|
+
pending.resolve(payload.result);
|
|
71
|
+
} else {
|
|
72
|
+
pending.reject(new Error(payload.error));
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return instancedMappingWorker;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function requestInstancedMapping(instances, drawObjs) {
|
|
79
|
+
const worker = ensureInstancedMappingWorker();
|
|
80
|
+
if (!worker) {
|
|
81
|
+
return Promise.reject(new Error('Worker is not initialized'));
|
|
82
|
+
}
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const id = instancedMappingWorkerRequestId++;
|
|
85
|
+
instancedMappingWorkerRequests.set(id, { resolve, reject });
|
|
86
|
+
worker.postMessage({
|
|
87
|
+
id,
|
|
88
|
+
type: 'buildInstancedMapping',
|
|
89
|
+
data: { instances, drawObjs },
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
42
94
|
/**
|
|
43
|
-
*
|
|
44
|
-
|
|
95
|
+
* 重置处理状态,用于新的批量加载会话
|
|
96
|
+
*/
|
|
97
|
+
function resetProcessingState() {
|
|
98
|
+
drawObjMapInstance = {};
|
|
99
|
+
// instanceToInstancedMeshMap.clear();
|
|
100
|
+
// processedDrawObjects.clear();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 获取已构建的绘制对象实例映射(用于根据 instanceId 查找其几何数据)
|
|
105
|
+
* @param {string} drawObjectId
|
|
106
|
+
* @returns {Object|undefined} 返回包含 MapMesh/MapInstance/lodLevel 的对象
|
|
107
|
+
*/
|
|
108
|
+
function getDrawObjectInstance(drawObjectId) {
|
|
109
|
+
return drawObjMapInstance[drawObjectId];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function mergeInstancedMappingResult(result) {
|
|
113
|
+
if (!result) return;
|
|
114
|
+
const { drawObjMapInstance: incomingMap, instanceToDrawObject } = result;
|
|
115
|
+
|
|
116
|
+
if (incomingMap) {
|
|
117
|
+
const keys = Object.keys(incomingMap);
|
|
118
|
+
for (let i = 0; i < keys.length; i++) {
|
|
119
|
+
const drawObjectId = keys[i];
|
|
120
|
+
const incoming = incomingMap[drawObjectId];
|
|
121
|
+
if (!incoming) continue;
|
|
122
|
+
const existing = drawObjMapInstance[drawObjectId];
|
|
123
|
+
if (!existing) {
|
|
124
|
+
drawObjMapInstance[drawObjectId] = {
|
|
125
|
+
MapInstance: Array.isArray(incoming.MapInstance) ? [...incoming.MapInstance] : [],
|
|
126
|
+
MapMesh: incoming.MapMesh,
|
|
127
|
+
};
|
|
128
|
+
} else {
|
|
129
|
+
if (!Array.isArray(existing.MapInstance)) existing.MapInstance = [];
|
|
130
|
+
const existingIds = new Set();
|
|
131
|
+
for (let j = 0; j < existing.MapInstance.length; j++) {
|
|
132
|
+
const item = existing.MapInstance[j];
|
|
133
|
+
if (item && item.instanceId != null) existingIds.add(item.instanceId);
|
|
134
|
+
}
|
|
135
|
+
const incomingInstances = Array.isArray(incoming.MapInstance) ? incoming.MapInstance : [];
|
|
136
|
+
for (let j = 0; j < incomingInstances.length; j++) {
|
|
137
|
+
const item = incomingInstances[j];
|
|
138
|
+
if (item && !existingIds.has(item.instanceId)) {
|
|
139
|
+
existing.MapInstance.push(item);
|
|
140
|
+
existingIds.add(item.instanceId);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (!existing.MapMesh && incoming.MapMesh) {
|
|
144
|
+
existing.MapMesh = incoming.MapMesh;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (Array.isArray(instanceToDrawObject)) {
|
|
151
|
+
for (let i = 0; i < instanceToDrawObject.length; i++) {
|
|
152
|
+
const item = instanceToDrawObject[i];
|
|
153
|
+
if (!item || item.instanceId == null) continue;
|
|
154
|
+
if (!instanceToInstancedMeshMap.get(item.instanceId)) {
|
|
155
|
+
instanceToInstancedMeshMap.set(item.instanceId, {
|
|
156
|
+
instanceId: item.instanceId,
|
|
157
|
+
drawObjectId: item.drawObjectId,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 处理 InstancedMesh 类型模型的核心方法(优化版本,支持批量处理)
|
|
166
|
+
* @param {Object} modelGroup - 模型组对象
|
|
167
|
+
* @param {Array} instances - 实例数组
|
|
45
168
|
* @param {Array} drawObjs - 绘制对象数组,包含几何数据
|
|
169
|
+
* @param {string} type - 类型
|
|
170
|
+
* @param {Object} scene - 场景对象
|
|
171
|
+
* @param {string} customColor - 自定义颜色
|
|
172
|
+
* @param {Object} meshNameConfig - 网格名称配置
|
|
173
|
+
* @param {string} customOpacity - 自定义透明度
|
|
174
|
+
* @param {Object} options - 选项配置
|
|
175
|
+
* @returns {Object} 模型组对象
|
|
46
176
|
*/
|
|
47
|
-
function handleInstancedMeshModel(
|
|
177
|
+
async function handleInstancedMeshModel(
|
|
48
178
|
modelGroup,
|
|
49
179
|
instances,
|
|
50
180
|
drawObjs,
|
|
@@ -52,125 +182,398 @@ function handleInstancedMeshModel(
|
|
|
52
182
|
scene,
|
|
53
183
|
customColor,
|
|
54
184
|
meshNameConfig,
|
|
55
|
-
customOpacity
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
185
|
+
customOpacity,
|
|
186
|
+
options = {}
|
|
187
|
+
)
|
|
188
|
+
{
|
|
189
|
+
// const getObjectByName = (name, passType = 'group') => {
|
|
190
|
+
// if (!scene) return [];
|
|
191
|
+
// const object = [];
|
|
192
|
+
// const instancedMeshProps = instanceToInstancedMeshMap.get(name);
|
|
193
|
+
// scene.traverse(item => {
|
|
194
|
+
// const tempName = instancedMeshProps ? instancedMeshProps.drawObjectId : name;
|
|
195
|
+
// if (item.name == tempName && item.type.toLowerCase() != passType.toLowerCase()) {
|
|
196
|
+
// object.push(item);
|
|
197
|
+
// }
|
|
198
|
+
// });
|
|
199
|
+
// return object;
|
|
200
|
+
// };
|
|
201
|
+
|
|
202
|
+
// 如果是新的加载会话,重置状态
|
|
203
|
+
if (options.resetState) {
|
|
204
|
+
resetProcessingState();
|
|
62
205
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
206
|
+
|
|
207
|
+
let mappingResult = null;
|
|
208
|
+
if (Array.isArray(instances) && instances.length) {
|
|
209
|
+
try {
|
|
210
|
+
mappingResult = await requestInstancedMapping(instances, drawObjs || []);
|
|
211
|
+
} catch (e) {
|
|
212
|
+
mappingResult = null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (mappingResult) {
|
|
217
|
+
mergeInstancedMappingResult(mappingResult);
|
|
218
|
+
} else {
|
|
219
|
+
const batchSize = options.batchSize || 50;
|
|
220
|
+
for (let i = 0; i < instances.length; i += batchSize) {
|
|
221
|
+
const batch = instances.slice(i, i + batchSize);
|
|
222
|
+
batch.forEach(instance => {
|
|
223
|
+
formatInstancedMap(instance, drawObjs);
|
|
74
224
|
});
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
for (let i = 0; i < instances.length; i++) {
|
|
228
|
+
const instance = instances[i];
|
|
229
|
+
const drawObjectId = instance.drawObject;
|
|
230
|
+
|
|
231
|
+
if (!instanceToInstancedMeshMap.get(instance.instanceId)) {
|
|
232
|
+
instanceToInstancedMeshMap.set(instance.instanceId, {
|
|
233
|
+
instanceId: instance.instanceId,
|
|
234
|
+
drawObjectId,
|
|
235
|
+
});
|
|
78
236
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 第二阶段:遍历所有实例进行处理(增量渲染优化)
|
|
241
|
+
// const processedInThisBatch = new Set();
|
|
242
|
+
|
|
243
|
+
// 预先建立映射表,避免在循环中频繁调用 getObjectByName
|
|
244
|
+
const existingGroupsMap = new Map();
|
|
245
|
+
if (modelGroup && modelGroup.children) {
|
|
246
|
+
modelGroup.children.forEach(child => {
|
|
247
|
+
if (child.name) {
|
|
248
|
+
existingGroupsMap.set(child.name, child);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const immediateUpdate = options.immediateUpdate || false;
|
|
254
|
+
|
|
255
|
+
for (let i = 0; i < instances.length; i++) {
|
|
256
|
+
const instance = instances[i];
|
|
257
|
+
const drawObjectId = instance.drawObject;
|
|
258
|
+
const instanceId = instance.instanceId;
|
|
259
|
+
|
|
260
|
+
// 检查该drawObject是否已经在本批次或之前处理过
|
|
261
|
+
// if (processedDrawObjects.has(drawObjectId) || processedInThisBatch.has(drawObjectId)) {
|
|
262
|
+
// continue; // 跳过已处理的drawObject
|
|
263
|
+
// }
|
|
264
|
+
|
|
265
|
+
const drawObjInstance = drawObjMapInstance[drawObjectId];
|
|
266
|
+
|
|
267
|
+
if (drawObjInstance?.MapMesh?.length > 0) {
|
|
268
|
+
// 检查modelGroup中是否已存在同名的group
|
|
269
|
+
// const existingGroup = getObjectByName(drawObjectId)[0];
|
|
270
|
+
const existingGroup = existingGroupsMap.get(drawObjectId);
|
|
271
|
+
|
|
272
|
+
if (!existingGroup) {
|
|
273
|
+
const group = createInstancedGroup(
|
|
274
|
+
drawObjInstance,
|
|
275
|
+
instance,
|
|
276
|
+
meshNameConfig,
|
|
277
|
+
customColor,
|
|
278
|
+
customOpacity,
|
|
279
|
+
options
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
if (group) {
|
|
283
|
+
// console.log('add(group)')
|
|
284
|
+
modelGroup.add(group);
|
|
285
|
+
if(immediateUpdate){
|
|
286
|
+
// 立即更新矩阵世界,确保位置正确
|
|
287
|
+
group.updateMatrixWorld(true);
|
|
103
288
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
289
|
+
|
|
290
|
+
// 更新映射表,以便后续循环能找到新添加的组
|
|
291
|
+
if (group.name) {
|
|
292
|
+
existingGroupsMap.set(group.name, group);
|
|
108
293
|
}
|
|
109
294
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
model.userData.primId = mesh.prmid;
|
|
117
|
-
model.name = meshName !== '' ? item.instanceId + meshName : item.instanceId;
|
|
118
|
-
|
|
119
|
-
model.userData.instanceMaps[item.instanceId] = {};
|
|
120
|
-
model.userData.instanceMaps[item.instanceId]['instanceIndex'] = index;
|
|
121
|
-
model.userData.instanceMaps[item.instanceId]['primId'] = mesh.prmid;
|
|
122
|
-
model.userData.instanceMaps[item.instanceId]['name'] = model.name;
|
|
123
|
-
|
|
124
|
-
const matrixVal = item.matrix?.val;
|
|
125
|
-
if (matrixVal) {
|
|
126
|
-
const m4 = new THREE.Matrix4();
|
|
127
|
-
const meshMatrix = new THREE.Matrix4();
|
|
128
|
-
const geomMatrix = new THREE.Matrix4();
|
|
129
|
-
// m4.setPosition(new THREE.Vector3(9999999, 9999999, 9999999)); // TODO 临时隐藏方案
|
|
130
|
-
meshMatrix.elements = item.matrix.val;
|
|
131
|
-
geomMatrix.elements = mesh.matrix.val;
|
|
132
|
-
|
|
133
|
-
// 处理文本居中对齐
|
|
134
|
-
if (isTextType(mesh.type)) {
|
|
135
|
-
const { points, alignType } = mesh;
|
|
136
|
-
const positionMatrix = new THREE.Matrix4();
|
|
137
|
-
|
|
138
|
-
const alignMatrix = createAlignedText(alignType, model.geometry);
|
|
139
|
-
|
|
140
|
-
positionMatrix.identity().makeTranslation(points[0], points[1], points[2]);
|
|
141
|
-
geomMatrix.multiply(alignMatrix).multiply(positionMatrix);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
m4.multiplyMatrices(meshMatrix, geomMatrix);
|
|
145
|
-
|
|
146
|
-
model.setMatrixAt(index, m4);
|
|
147
|
-
const copyMatrix = new THREE.Matrix4().copy(m4);
|
|
148
|
-
model.userData.copyMatrix = copyMatrix;
|
|
149
|
-
|
|
150
|
-
model.userData.instanceMaps[item.instanceId]['copyMatrix'] = copyMatrix;
|
|
151
|
-
}
|
|
152
|
-
// 需要先设置全部实例颜色,否则后续设置颜色无效
|
|
153
|
-
const { color } = mesh.prop;
|
|
154
|
-
const meshColor = customColor
|
|
155
|
-
? new THREE.Color(customColor)
|
|
156
|
-
: new THREE.Color(`rgb(${color[0]}, ${color[1]}, ${color[2]})`);
|
|
157
|
-
model.setColorAt(index, meshColor);
|
|
158
|
-
});
|
|
159
|
-
// 标记实例属性更新
|
|
160
|
-
if (model.instanceMatrix) model.instanceMatrix.needsUpdate = true;
|
|
161
|
-
if (model.instanceColor) model.instanceColor.needsUpdate = true;
|
|
162
|
-
// model.instanceColor.needsUpdate = true;
|
|
163
|
-
group.add(model);
|
|
164
|
-
});
|
|
165
|
-
modelGroup.add(group);
|
|
295
|
+
// 标记该drawObject已处理
|
|
296
|
+
// processedDrawObjects.add(drawObjectId);
|
|
297
|
+
// processedInThisBatch.add(drawObjectId);
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
appendInstanceToInstancedGroup(existingGroup, drawObjInstance, instance, customColor);
|
|
166
301
|
}
|
|
167
302
|
}
|
|
168
303
|
}
|
|
169
|
-
|
|
170
|
-
console.log(
|
|
171
|
-
return modelGroup;
|
|
172
|
-
|
|
173
|
-
|
|
304
|
+
|
|
305
|
+
// console.log(instanceToInstancedMeshMap)
|
|
306
|
+
// return modelGroup;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* 创建实例化组(从handleInstancedMeshModel中提取的逻辑)
|
|
311
|
+
* @param {Object} drawObj - 绘制对象数据
|
|
312
|
+
* @param {Object} instance - 实例数据
|
|
313
|
+
* @param {Object} meshNameConfig - 网格名称配置
|
|
314
|
+
* @param {string} customColor - 自定义颜色
|
|
315
|
+
* @param {string} customOpacity - 自定义透明度
|
|
316
|
+
* @param {Object} options - 选项配置
|
|
317
|
+
* @returns {THREE.Group} 创建的组对象
|
|
318
|
+
*/
|
|
319
|
+
function createInstancedGroup(
|
|
320
|
+
drawObj,
|
|
321
|
+
instance,
|
|
322
|
+
meshNameConfig,
|
|
323
|
+
customColor,
|
|
324
|
+
customOpacity,
|
|
325
|
+
options
|
|
326
|
+
) {
|
|
327
|
+
const group = new THREE.Group();
|
|
328
|
+
|
|
329
|
+
// 设置组的基本属性
|
|
330
|
+
for (const key in meshNameConfig) {
|
|
331
|
+
group.userData[key] = meshNameConfig[key];
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// 可配置的用户数据
|
|
335
|
+
for (const key in options.userData) {
|
|
336
|
+
group.userData[key] = options.userData[key];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// group.name = options.defineGroupPreName ? `${options.defineGroupPreName}:${instance.drawObject}` : instance.drawObject;
|
|
340
|
+
group.name = instance.drawObject;
|
|
341
|
+
group.userData.isInstancedMeshGroup = true;
|
|
342
|
+
group.userData.category = instance.category;
|
|
343
|
+
group.userData.instanceId = instance.drawObject;
|
|
344
|
+
|
|
345
|
+
// const instanceCount = drawObj.MapInstance.length;
|
|
346
|
+
const instanceCount = 100; // 预分配容量,动态增加实例
|
|
347
|
+
const activeInstanceCount = Array.isArray(drawObj.MapInstance) ? drawObj.MapInstance.length : 0;
|
|
348
|
+
|
|
349
|
+
// 处理每个网格
|
|
350
|
+
drawObj.MapMesh?.forEach(mesh => {
|
|
351
|
+
// console.log(mesh)
|
|
352
|
+
// console.log(instance)
|
|
353
|
+
// if(mesh.prop.color[0] == 0 && mesh.prop.color[1] == 142 && mesh.prop.color[2] == 142){
|
|
354
|
+
// return
|
|
355
|
+
// }
|
|
356
|
+
// customColor 是原本初始化整个模型颜色的 这里暂时放弃
|
|
357
|
+
// (mesh, instance.drawObject, instanceCount, customColor, customOpacity
|
|
358
|
+
let color = options.colorConfig.get(instance.instanceId)
|
|
359
|
+
|
|
360
|
+
const model = drawModel(mesh, instance.drawObject, instanceCount, color, customOpacity, {
|
|
361
|
+
// lodLevel: drawObj.lodLevel || 2,
|
|
362
|
+
activeInstanceCount,
|
|
363
|
+
...options
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
if (!model) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// 设置网格名称
|
|
371
|
+
let meshName = '';
|
|
372
|
+
for (const key in meshNameConfig) {
|
|
373
|
+
model.userData[key] = meshNameConfig[key];
|
|
374
|
+
// meshName += ':' + meshNameConfig[key];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// 批量设置实例矩阵和颜色(性能优化)
|
|
378
|
+
// setInstanceMatricesAndColors(model, drawObj, mesh, meshName, customColor, options);
|
|
379
|
+
setInstanceMatricesAndColors(model, drawObj, mesh, meshName, color, options);
|
|
380
|
+
|
|
381
|
+
group.add(model);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
return group;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* 批量设置实例矩阵和颜色(性能优化版本)
|
|
389
|
+
* @param {THREE.InstancedMesh} model - 实例化网格模型
|
|
390
|
+
* @param {Object} drawObj - 绘制对象数据
|
|
391
|
+
* @param {Object} mesh - 网格数据
|
|
392
|
+
* @param {string} meshName - 网格名称
|
|
393
|
+
* @param {string} customColor - 自定义颜色
|
|
394
|
+
*/
|
|
395
|
+
function setInstanceMatricesAndColors(model, drawObj, mesh, meshName, customColor, options) {
|
|
396
|
+
const instances = drawObj.MapInstance;
|
|
397
|
+
const { color } = mesh.prop;
|
|
398
|
+
|
|
399
|
+
// 预计算颜色
|
|
400
|
+
const meshColor = customColor
|
|
401
|
+
? new THREE.Color(customColor)
|
|
402
|
+
: new THREE.Color(`rgb(${color[0]}, ${color[1]}, ${color[2]})`);
|
|
403
|
+
|
|
404
|
+
// 批量处理实例
|
|
405
|
+
instances.forEach((item, index) => {
|
|
406
|
+
// 设置用户数据
|
|
407
|
+
model.userData.instanceIndex = index;
|
|
408
|
+
model.userData.instanceId = item.instanceId;
|
|
409
|
+
model.userData.primId = mesh.prmid;
|
|
410
|
+
// model.userData.lodLevel = drawObj.lodLevel || 2;
|
|
411
|
+
if (index == 0) {
|
|
412
|
+
model.name = meshName !== '' ? item.instanceId + meshName : item.instanceId;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
let instanceProps = {
|
|
416
|
+
instanceIndex: index, // 序号来定位到底是哪个instancedMesh
|
|
417
|
+
instancedMeshId: model.name, // 多个instancedMesh共用一个name,用于查找模型
|
|
418
|
+
instanceId: item.instanceId, // instancedMesh实际的modelId
|
|
419
|
+
primId: mesh.prmid,
|
|
420
|
+
// lodLevel: drawObj.lodLevel || 2,
|
|
421
|
+
};
|
|
422
|
+
if (!model.userData.instancesMap) {
|
|
423
|
+
model.userData.instancesMap = new Map([[item.instanceId, instanceProps]]);
|
|
424
|
+
} else {
|
|
425
|
+
model.userData.instancesMap.set(item.instanceId, instanceProps);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// const instancedMesh = instanceToInstancedMeshMap.get(item.instanceId);
|
|
429
|
+
|
|
430
|
+
// 处理矩阵变换
|
|
431
|
+
const matrixVal = item.matrix?.val;
|
|
432
|
+
if (matrixVal) {
|
|
433
|
+
const m4 = new THREE.Matrix4();
|
|
434
|
+
const meshMatrix = new THREE.Matrix4();
|
|
435
|
+
const geomMatrix = new THREE.Matrix4();
|
|
436
|
+
|
|
437
|
+
meshMatrix.fromArray(matrixVal);
|
|
438
|
+
geomMatrix.fromArray(new THREE.Matrix4().identity().elements);
|
|
439
|
+
|
|
440
|
+
// 处理文本居中对齐
|
|
441
|
+
const { points, alignType } = mesh;
|
|
442
|
+
if (isTextType(mesh.type)) {
|
|
443
|
+
const positionMatrix = new THREE.Matrix4();
|
|
444
|
+
const alignMatrix = createAlignedText(alignType, model.geometry);
|
|
445
|
+
positionMatrix.identity().makeTranslation(points[0], points[1], points[2]);
|
|
446
|
+
geomMatrix.multiply(alignMatrix).multiply(positionMatrix);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
m4.multiplyMatrices(meshMatrix, geomMatrix);
|
|
450
|
+
model.setMatrixAt(index, m4);
|
|
451
|
+
|
|
452
|
+
const copyMatrix = new THREE.Matrix4().copy(m4);
|
|
453
|
+
model.userData.copyMatrix = copyMatrix;
|
|
454
|
+
|
|
455
|
+
const temp = model.userData.instancesMap.get(item.instanceId);
|
|
456
|
+
temp.copyMatrix = copyMatrix;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// 设置颜色
|
|
460
|
+
model.setColorAt(index, meshColor);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
// 标记需要更新
|
|
464
|
+
if (model.instanceMatrix) {
|
|
465
|
+
model.instanceMatrix.needsUpdate = true;
|
|
466
|
+
}
|
|
467
|
+
if (model.instanceColor) {
|
|
468
|
+
model.instanceColor.needsUpdate = true;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (Array.isArray(instances)) {
|
|
472
|
+
const capacity =
|
|
473
|
+
model.instanceMatrix && typeof model.instanceMatrix.count === 'number'
|
|
474
|
+
? model.instanceMatrix.count
|
|
475
|
+
: model.count;
|
|
476
|
+
model.count = Math.min(instances.length, capacity);
|
|
477
|
+
model.userData.instanceCapacity = capacity;
|
|
478
|
+
model.userData.instanceCount = model.count;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function appendInstanceToInstancedGroup(group, drawObj, instance, customColor) {
|
|
483
|
+
if (!group || !drawObj || !instance) return;
|
|
484
|
+
const meshes = Array.isArray(drawObj.MapMesh) ? drawObj.MapMesh : [];
|
|
485
|
+
if (meshes.length === 0) return;
|
|
486
|
+
const meshByPrimId = new Map();
|
|
487
|
+
for (let i = 0; i < meshes.length; i++) {
|
|
488
|
+
const m = meshes[i];
|
|
489
|
+
if (m && m.prmid !== undefined) meshByPrimId.set(m.prmid, m);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const children = Array.isArray(group.children) ? group.children : [];
|
|
493
|
+
for (let i = 0; i < children.length; i++) {
|
|
494
|
+
const obj = children[i];
|
|
495
|
+
if (!obj || !obj.isInstancedMesh) continue;
|
|
496
|
+
const primId = obj.userData ? obj.userData.primId : undefined;
|
|
497
|
+
const mesh = meshByPrimId.get(primId);
|
|
498
|
+
if (!mesh) continue;
|
|
499
|
+
appendInstanceToInstancedMesh(obj, drawObj, mesh, instance, customColor);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function appendInstanceToInstancedMesh(model, drawObj, mesh, instance, customColor) {
|
|
504
|
+
if (!model || !model.isInstancedMesh) return;
|
|
505
|
+
if (!instance || !instance.instanceId) return;
|
|
506
|
+
|
|
507
|
+
const capacity =
|
|
508
|
+
model.instanceMatrix && typeof model.instanceMatrix.count === 'number'
|
|
509
|
+
? model.instanceMatrix.count
|
|
510
|
+
: model.count;
|
|
511
|
+
const currentCount = typeof model.count === 'number' ? model.count : 0;
|
|
512
|
+
if (currentCount >= capacity) return;
|
|
513
|
+
|
|
514
|
+
if (!model.userData) model.userData = {};
|
|
515
|
+
if (!model.userData.instancesMap) model.userData.instancesMap = new Map();
|
|
516
|
+
if (model.userData.instancesMap.has(instance.instanceId)) return;
|
|
517
|
+
|
|
518
|
+
const rawColor = mesh && mesh.prop ? mesh.prop.color : undefined;
|
|
519
|
+
const colorArr = Array.isArray(rawColor)
|
|
520
|
+
? rawColor
|
|
521
|
+
: typeof rawColor === 'string'
|
|
522
|
+
? rawColor.split(',')
|
|
523
|
+
: [255, 255, 255];
|
|
524
|
+
const meshColor = customColor
|
|
525
|
+
? new THREE.Color(customColor)
|
|
526
|
+
: new THREE.Color(`rgb(${colorArr[0]}, ${colorArr[1]}, ${colorArr[2]})`);
|
|
527
|
+
|
|
528
|
+
const matrixVal = instance.matrix?.val;
|
|
529
|
+
if (!matrixVal || !mesh || !mesh.matrix || !mesh.matrix.val) return;
|
|
530
|
+
|
|
531
|
+
const m4 = new THREE.Matrix4();
|
|
532
|
+
const meshMatrix = new THREE.Matrix4();
|
|
533
|
+
const geomMatrix = new THREE.Matrix4();
|
|
534
|
+
|
|
535
|
+
meshMatrix.fromArray(instance.matrix.val);
|
|
536
|
+
geomMatrix.fromArray(new THREE.Matrix4().identity().elements);
|
|
537
|
+
|
|
538
|
+
const { points, alignType } = mesh;
|
|
539
|
+
if (isTextType(mesh.type)) {
|
|
540
|
+
const positionMatrix = new THREE.Matrix4();
|
|
541
|
+
const alignMatrix = createAlignedText(alignType, model.geometry);
|
|
542
|
+
positionMatrix.identity().makeTranslation(points[0], points[1], points[2]);
|
|
543
|
+
geomMatrix.multiply(alignMatrix).multiply(positionMatrix);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
m4.multiplyMatrices(meshMatrix, geomMatrix);
|
|
547
|
+
model.setMatrixAt(currentCount, m4);
|
|
548
|
+
if (model.instanceMatrix) model.instanceMatrix.needsUpdate = true;
|
|
549
|
+
|
|
550
|
+
const copyMatrix = new THREE.Matrix4().copy(m4);
|
|
551
|
+
model.userData.copyMatrix = copyMatrix;
|
|
552
|
+
const instanceProps = {
|
|
553
|
+
instanceIndex: currentCount,
|
|
554
|
+
instancedMeshId: model.name,
|
|
555
|
+
instanceId: instance.instanceId,
|
|
556
|
+
primId: mesh.prmid,
|
|
557
|
+
// lodLevel: drawObj.lodLevel || 2,
|
|
558
|
+
copyMatrix,
|
|
559
|
+
};
|
|
560
|
+
model.userData.instancesMap.set(instance.instanceId, instanceProps);
|
|
561
|
+
|
|
562
|
+
model.setColorAt(currentCount, meshColor);
|
|
563
|
+
if (model.instanceColor) model.instanceColor.needsUpdate = true;
|
|
564
|
+
|
|
565
|
+
const opacityAttr =
|
|
566
|
+
model.geometry && model.geometry.getAttribute
|
|
567
|
+
? model.geometry.getAttribute('opacity')
|
|
568
|
+
: undefined;
|
|
569
|
+
if (opacityAttr && opacityAttr.array && currentCount < opacityAttr.array.length) {
|
|
570
|
+
opacityAttr.array[currentCount] = opacityAttr.array[0] !== undefined ? opacityAttr.array[0] : 1;
|
|
571
|
+
opacityAttr.needsUpdate = true;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
model.count = currentCount + 1;
|
|
575
|
+
model.userData.instanceCapacity = capacity;
|
|
576
|
+
model.userData.instanceCount = model.count;
|
|
174
577
|
}
|
|
175
578
|
|
|
176
579
|
/**
|
|
@@ -200,9 +603,17 @@ function formatInstancedMap(instance, drawObjs) {
|
|
|
200
603
|
|
|
201
604
|
// 关联绘制对象的几何数据
|
|
202
605
|
drawObjs.forEach(item => {
|
|
203
|
-
|
|
606
|
+
let hasMesh = false;
|
|
607
|
+
if (item && Array.isArray(item.geoms)) {
|
|
608
|
+
const found = item.geoms.some(g => g.prmid === drawObject);
|
|
609
|
+
if (found) {
|
|
610
|
+
hasMesh = true;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
if (hasMesh) {
|
|
204
614
|
// 将几何数据映射到对应的绘制对象
|
|
205
615
|
drawObjMapInstance[drawObject].MapMesh = item.geoms;
|
|
616
|
+
// drawObjMapInstance[drawObject].lodLevel = item.lodLevel || 2;
|
|
206
617
|
}
|
|
207
618
|
});
|
|
208
619
|
}
|
|
@@ -227,14 +638,14 @@ function formatDrawObjs(data) {
|
|
|
227
638
|
* @param {Number} instanceCount - 实例化渲染的数量(用于InstancedMesh)
|
|
228
639
|
* @returns {THREE.Object3D} 返回创建的3D模型对象
|
|
229
640
|
*/
|
|
230
|
-
function drawModel(geom, instanceName, instanceCount, nColor, nOpacity) {
|
|
641
|
+
function drawModel(geom, instanceName, instanceCount, nColor, nOpacity, options = {}) {
|
|
231
642
|
let model;
|
|
232
643
|
// 处理二维几何体(普通2D图形和特殊2D图形)
|
|
233
644
|
if (geom.type == GEOM_TYPES.geom_2d || geom.type == GEOM_TYPES.geom_2d_others) {
|
|
234
|
-
model = draw2Dmodel(geom, instanceName, instanceCount); // TODO 该类型调试中
|
|
645
|
+
model = draw2Dmodel(geom, instanceName, instanceCount, options); // TODO 该类型调试中
|
|
235
646
|
// 处理二维文本类型
|
|
236
647
|
} else if (isTextType(geom.type)) {
|
|
237
|
-
model = drawText(geom, instanceName, instanceCount);
|
|
648
|
+
model = drawText(geom, instanceName, instanceCount, options);
|
|
238
649
|
// 处理各种曲线类型(圆形、圆弧、椭圆、椭圆弧)
|
|
239
650
|
} else if (
|
|
240
651
|
geom.type == GEOM_TYPES.geom_2d_circle ||
|
|
@@ -242,10 +653,10 @@ function drawModel(geom, instanceName, instanceCount, nColor, nOpacity) {
|
|
|
242
653
|
geom.type == GEOM_TYPES.geom_2d_ellipse ||
|
|
243
654
|
geom.type == GEOM_TYPES.geom_2d_ellipseArc
|
|
244
655
|
) {
|
|
245
|
-
model = drawCurves(geom, instanceName, instanceCount); // TODO 该类型调试中
|
|
656
|
+
model = drawCurves(geom, instanceName, instanceCount, options); // TODO 该类型调试中
|
|
246
657
|
// 处理三维几何体(普通3D模型和OBJ模型)
|
|
247
658
|
} else if (geom.type == GEOM_TYPES.geom_3d || geom.type == GEOM_TYPES.geom_3d_obj) {
|
|
248
|
-
model = draw3Dmodel(geom, instanceName, instanceCount, nColor, nOpacity);
|
|
659
|
+
model = draw3Dmodel(geom, instanceName, instanceCount, nColor, nOpacity, options);
|
|
249
660
|
}
|
|
250
661
|
return model;
|
|
251
662
|
}
|
|
@@ -271,7 +682,7 @@ function isTextType(type) {
|
|
|
271
682
|
* @param {String} instanceName- 曲线实例的名称
|
|
272
683
|
* @return {Object}- 包含曲线模型和曲线信息的对象
|
|
273
684
|
*/
|
|
274
|
-
function drawCurves(geom, instanceName, instanceCount) {
|
|
685
|
+
function drawCurves(geom, instanceName, instanceCount, options = {}) {
|
|
275
686
|
let { points, normals } = geom;
|
|
276
687
|
let aX = points[0];
|
|
277
688
|
let aY = points[1];
|
|
@@ -311,7 +722,8 @@ function drawCurves(geom, instanceName, instanceCount) {
|
|
|
311
722
|
normals,
|
|
312
723
|
},
|
|
313
724
|
instanceName,
|
|
314
|
-
instanceCount
|
|
725
|
+
instanceCount,
|
|
726
|
+
options
|
|
315
727
|
);
|
|
316
728
|
// model.rotation.x = -Math.PI / 2;
|
|
317
729
|
// model.position.set(aX, aY, aZ);
|
|
@@ -329,7 +741,18 @@ function drawCurves(geom, instanceName, instanceCount) {
|
|
|
329
741
|
* @param {Number} instanceCount - 需要创建的实例数量
|
|
330
742
|
* @returns {THREE.InstancedMesh} - 返回创建的三维实例化网格对象
|
|
331
743
|
*/
|
|
332
|
-
function draw3Dmodel(
|
|
744
|
+
function draw3Dmodel(
|
|
745
|
+
geom,
|
|
746
|
+
instanceName,
|
|
747
|
+
instanceCount,
|
|
748
|
+
nColor,
|
|
749
|
+
nOpacity,
|
|
750
|
+
options = {},
|
|
751
|
+
targetMesh = undefined
|
|
752
|
+
) {
|
|
753
|
+
// const { lodLevel } = options;
|
|
754
|
+
|
|
755
|
+
|
|
333
756
|
// 解构几何数据中的自定义几何体和材质
|
|
334
757
|
const {
|
|
335
758
|
geometry: customGeometry,
|
|
@@ -337,87 +760,203 @@ function draw3Dmodel(geom, instanceName, instanceCount, nColor, nOpacity) {
|
|
|
337
760
|
triangles,
|
|
338
761
|
points,
|
|
339
762
|
normals,
|
|
340
|
-
prop,
|
|
763
|
+
prop = {},
|
|
764
|
+
max,
|
|
765
|
+
min,
|
|
766
|
+
type,
|
|
341
767
|
} = geom;
|
|
342
|
-
// 使用自定义几何体或创建新的缓冲几何体
|
|
343
|
-
const geometry = customGeometry || new THREE.BufferGeometry();
|
|
344
768
|
|
|
769
|
+
// 如果传入了现有 mesh,则进行几何体切换(不重新创建 Mesh)
|
|
770
|
+
// if (targetMesh && targetMesh.isInstancedMesh) {
|
|
771
|
+
// // 计算透明度,若现有材质已设置则沿用
|
|
772
|
+
// let opacityFromMat = (targetMesh.material && targetMesh.material.userData && targetMesh.material.userData.nOpacity) ? targetMesh.material.userData.nOpacity : undefined;
|
|
773
|
+
// let colors = Array.isArray(prop.color) ? prop.color : (typeof prop.color === 'string' ? prop.color.split(',') : [255, 255, 255, 1]);
|
|
774
|
+
// let fallbackOpacity = colors[3] !== undefined ? colors[3] : 1;
|
|
775
|
+
// const opacity = opacityFromMat !== undefined ? opacityFromMat : (nOpacity !== undefined ? nOpacity : fallbackOpacity);
|
|
776
|
+
|
|
777
|
+
// // 根据目标 lodLevel 切换几何体
|
|
778
|
+
// if (lodLevel === PRIMITIVE_TYPE.full) {
|
|
779
|
+
// const bufGeo = new THREE.BufferGeometry();
|
|
780
|
+
// // 设置索引
|
|
781
|
+
// if (triangles && triangles.length) {
|
|
782
|
+
// bufGeo.setIndex(triangles);
|
|
783
|
+
// } else {
|
|
784
|
+
// bufGeo.setIndex(null);
|
|
785
|
+
// }
|
|
786
|
+
// // 设置位置
|
|
787
|
+
// if (points && points.length) {
|
|
788
|
+
// const position = new Float32Array(points);
|
|
789
|
+
// bufGeo.setAttribute('position', new THREE.BufferAttribute(position, 3));
|
|
790
|
+
// }
|
|
791
|
+
// // 设置法线或计算
|
|
792
|
+
// if (normals && normals.length) {
|
|
793
|
+
// const normal = new Float32Array(normals);
|
|
794
|
+
// bufGeo.setAttribute('normal', new THREE.BufferAttribute(normal, 3));
|
|
795
|
+
// } else {
|
|
796
|
+
// bufGeo.computeVertexNormals();
|
|
797
|
+
// }
|
|
798
|
+
|
|
799
|
+
// // 绑定实例透明度属性
|
|
800
|
+
// const opacities = new Float32Array(instanceCount);
|
|
801
|
+
// for (let i = 0; i < instanceCount; i++) opacities[i] = opacity;
|
|
802
|
+
// bufGeo.setAttribute('opacity', new THREE.InstancedBufferAttribute(opacities, 1));
|
|
803
|
+
|
|
804
|
+
// // 包围体
|
|
805
|
+
// bufGeo.computeBoundingBox();
|
|
806
|
+
// bufGeo.computeBoundingSphere();
|
|
807
|
+
|
|
808
|
+
// // 替换旧几何体
|
|
809
|
+
// if (targetMesh.geometry) targetMesh.geometry.dispose();
|
|
810
|
+
// targetMesh.geometry = bufGeo;
|
|
811
|
+
// targetMesh.userData.lodLevel = PRIMITIVE_TYPE.full;
|
|
812
|
+
// return; // 更新完成,无需返回新mesh
|
|
813
|
+
// }
|
|
814
|
+
|
|
815
|
+
// if (lodLevel === PRIMITIVE_TYPE.onlyBounding) {
|
|
816
|
+
// // 使用 min/max 或从现有几何体计算包围盒
|
|
817
|
+
// let bbox;
|
|
818
|
+
// if (Array.isArray(min) && Array.isArray(max) && min.length === 3 && max.length === 3) {
|
|
819
|
+
// bbox = { min: { x: min[0], y: min[1], z: min[2] }, max: { x: max[0], y: max[1], z: max[2] } };
|
|
820
|
+
// } else {
|
|
821
|
+
// // 从现有几何体计算
|
|
822
|
+
// const geo = targetMesh.geometry;
|
|
823
|
+
// geo.computeBoundingBox();
|
|
824
|
+
// const bb = geo.boundingBox;
|
|
825
|
+
// bbox = { min: bb.min, max: bb.max };
|
|
826
|
+
// }
|
|
827
|
+
// const width = Math.max(0.0001, bbox.max.x - bbox.min.x);
|
|
828
|
+
// const height = Math.max(0.0001, bbox.max.y - bbox.min.y);
|
|
829
|
+
// const depth = Math.max(0.0001, bbox.max.z - bbox.min.z);
|
|
830
|
+
// const cx = (bbox.min.x + bbox.max.x) / 2;
|
|
831
|
+
// const cy = (bbox.min.y + bbox.max.y) / 2;
|
|
832
|
+
// const cz = (bbox.min.z + bbox.max.z) / 2;
|
|
833
|
+
// const bboxGeometry = new THREE.BoxGeometry(width, height, depth);
|
|
834
|
+
// bboxGeometry.translate(cx, cy, cz);
|
|
835
|
+
|
|
836
|
+
// // 绑定实例透明度属性(保持现有透明度)
|
|
837
|
+
// const opacities = new Float32Array(instanceCount);
|
|
838
|
+
// for (let i = 0; i < instanceCount; i++) opacities[i] = opacity;
|
|
839
|
+
// bboxGeometry.setAttribute('opacity', new THREE.InstancedBufferAttribute(opacities, 1));
|
|
840
|
+
|
|
841
|
+
// if (targetMesh.geometry) targetMesh.geometry.dispose();
|
|
842
|
+
// targetMesh.geometry = bboxGeometry;
|
|
843
|
+
// targetMesh.userData.lodLevel = PRIMITIVE_TYPE.onlyBounding;
|
|
844
|
+
// return; // 更新完成,无需返回新mesh
|
|
845
|
+
// }
|
|
846
|
+
|
|
847
|
+
// // 其它模式不处理
|
|
848
|
+
// return;
|
|
849
|
+
// }
|
|
850
|
+
|
|
851
|
+
// 未传入现有 mesh:按原逻辑创建新 InstancedMesh
|
|
852
|
+
let geometry = customGeometry || new THREE.BufferGeometry();
|
|
853
|
+
// if (lodLevel == PRIMITIVE_TYPE.onlyBounding) {
|
|
854
|
+
// if (Array.isArray(min) && Array.isArray(max) && min.length === 3 && max.length === 3) {
|
|
855
|
+
// const width = Math.max(0.0001, max[0] - min[0]);
|
|
856
|
+
// const height = Math.max(0.0001, max[1] - min[1]);
|
|
857
|
+
// const depth = Math.max(0.0001, max[2] - min[2]);
|
|
858
|
+
// const cx = (min[0] + max[0]) / 2;
|
|
859
|
+
// const cy = (min[1] + max[1]) / 2;
|
|
860
|
+
// const cz = (min[2] + max[2]) / 2;
|
|
861
|
+
// const bboxGeometry = new THREE.BoxGeometry(width, height, depth);
|
|
862
|
+
// bboxGeometry.translate(cx, cy, cz);
|
|
863
|
+
// geometry = bboxGeometry;
|
|
864
|
+
// }
|
|
865
|
+
// } else {
|
|
866
|
+
// if (triangles && triangles.length) {
|
|
867
|
+
// geometry.setIndex(triangles);
|
|
868
|
+
// }
|
|
869
|
+
// if (points && points.length) {
|
|
870
|
+
// const position = new Float32Array(points);
|
|
871
|
+
// geometry.setAttribute('position', new THREE.BufferAttribute(position, 3));
|
|
872
|
+
// }
|
|
873
|
+
// if (normals && normals.length) {
|
|
874
|
+
// const normal = new Float32Array(normals);
|
|
875
|
+
// geometry.setAttribute('normal', new THREE.BufferAttribute(normal, 3));
|
|
876
|
+
// }
|
|
877
|
+
// }
|
|
878
|
+
|
|
879
|
+
// triangle int16Array 索引时,需要转换为 uint16Array
|
|
345
880
|
if(!customGeometry){
|
|
346
|
-
// 设置三角形索引数据
|
|
347
881
|
if (triangles && triangles.length) {
|
|
348
|
-
geometry.setIndex(triangles);
|
|
882
|
+
geometry.setIndex(triangles instanceof Int16Array ? Array.from(triangles.buffer) : triangles);
|
|
349
883
|
}
|
|
350
|
-
|
|
351
|
-
// 设置顶点位置数据
|
|
352
884
|
if (points && points.length) {
|
|
353
885
|
const position = new Float32Array(points);
|
|
354
886
|
geometry.setAttribute('position', new THREE.BufferAttribute(position, 3));
|
|
355
887
|
}
|
|
356
|
-
|
|
357
|
-
// 设置顶点法线数据
|
|
358
888
|
if (normals && normals.length) {
|
|
359
889
|
const normal = new Float32Array(normals);
|
|
360
890
|
geometry.setAttribute('normal', new THREE.BufferAttribute(normal, 3));
|
|
361
891
|
}
|
|
362
892
|
}
|
|
363
|
-
|
|
893
|
+
|
|
364
894
|
const { color, transparent } = prop;
|
|
365
895
|
let material, mesh, colors, opacity;
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
896
|
+
if (Array.isArray(color) && color.length) {
|
|
897
|
+
colors = color;
|
|
898
|
+
opacity = colors[3] || 1;
|
|
899
|
+
} else if (typeof color === 'string') {
|
|
900
|
+
colors = color.split(',');
|
|
901
|
+
opacity = colors[3] || 1;
|
|
902
|
+
} else {
|
|
903
|
+
colors = [255, 255, 255];
|
|
904
|
+
opacity = 1;
|
|
905
|
+
}
|
|
376
906
|
|
|
377
907
|
// 处理transparent透明度
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
908
|
+
opacity = 1 - transparent;
|
|
909
|
+
|
|
910
|
+
const finalOpacity = nOpacity !== '' ? nOpacity : opacity;
|
|
911
|
+
|
|
912
|
+
// 判断是否全透明
|
|
913
|
+
const isTransparent = finalOpacity < 1.0;
|
|
381
914
|
|
|
382
|
-
// 使用自定义材质或创建标准材质(默认参数配置)
|
|
383
915
|
let materialOptions = {
|
|
384
916
|
userData: {
|
|
385
917
|
nColor: nColor
|
|
386
918
|
? new THREE.Color(nColor)
|
|
387
919
|
: new THREE.Color(`rgb(${colors[0]}, ${colors[1]}, ${colors[2]})`),
|
|
388
|
-
nOpacity:
|
|
920
|
+
nOpacity: finalOpacity,
|
|
921
|
+
// 这里记录模型原本的颜色 做颜色配置时 恢复原本的颜色用的
|
|
922
|
+
oColor: new THREE.Color(`rgb(${colors[0]}, ${colors[1]}, ${colors[2]})`)
|
|
389
923
|
},
|
|
924
|
+
// side: THREE.DoubleSide,
|
|
925
|
+
// transparent: true,
|
|
926
|
+
// forceSinglePass: true,
|
|
390
927
|
side: THREE.DoubleSide,
|
|
391
|
-
transparent: true,
|
|
928
|
+
transparent: true,
|
|
929
|
+
opacity: finalOpacity,
|
|
930
|
+
depthWrite: true,
|
|
931
|
+
forceSinglePass: true,
|
|
392
932
|
};
|
|
393
933
|
|
|
394
934
|
customMaterial && Object.assign(customMaterial, materialOptions);
|
|
395
|
-
|
|
396
935
|
material =
|
|
397
936
|
customMaterial ||
|
|
398
937
|
new THREE.MeshStandardMaterial({
|
|
399
938
|
...materialOptions,
|
|
400
939
|
roughness: 0.6,
|
|
401
940
|
metalness: 0.5,
|
|
402
|
-
envMapIntensity: 1,
|
|
403
|
-
// wireframe: true
|
|
941
|
+
envMapIntensity: 1,
|
|
404
942
|
});
|
|
405
943
|
|
|
406
|
-
|
|
407
|
-
|
|
944
|
+
const activeInstanceCount = Math.max(
|
|
945
|
+
0,
|
|
946
|
+
Math.min(
|
|
947
|
+
instanceCount,
|
|
948
|
+
typeof options.activeInstanceCount === 'number' ? options.activeInstanceCount : instanceCount
|
|
949
|
+
)
|
|
950
|
+
);
|
|
408
951
|
|
|
409
|
-
|
|
952
|
+
const opacities = new Float32Array(instanceCount);
|
|
410
953
|
for (let i = 0; i < instanceCount; i++) {
|
|
411
954
|
opacities[i] = opacity;
|
|
412
955
|
}
|
|
413
|
-
|
|
414
|
-
// 创建实例属性并绑定到 InstancedMesh
|
|
415
956
|
geometry.setAttribute('opacity', new THREE.InstancedBufferAttribute(opacities, 1));
|
|
416
957
|
|
|
417
|
-
// 自定义着色器逻辑
|
|
418
958
|
if (!customMaterial) {
|
|
419
959
|
material.onBeforeCompile = shader => {
|
|
420
|
-
// 添加顶点着色器输入
|
|
421
960
|
shader.vertexShader = `
|
|
422
961
|
in float opacity; // 实例透明度属性
|
|
423
962
|
out float vAlpha;
|
|
@@ -429,8 +968,6 @@ function draw3Dmodel(geom, instanceName, instanceCount, nColor, nOpacity) {
|
|
|
429
968
|
vAlpha = opacity; // 传递透明度到片段着色器
|
|
430
969
|
`
|
|
431
970
|
);
|
|
432
|
-
|
|
433
|
-
// 修改片段着色器
|
|
434
971
|
shader.fragmentShader = `
|
|
435
972
|
in float vAlpha;
|
|
436
973
|
${shader.fragmentShader}
|
|
@@ -443,6 +980,7 @@ function draw3Dmodel(geom, instanceName, instanceCount, nColor, nOpacity) {
|
|
|
443
980
|
);
|
|
444
981
|
};
|
|
445
982
|
}
|
|
983
|
+
|
|
446
984
|
// 针对 MeshLineMaterial 开启实例化支持
|
|
447
985
|
if (material.type === 'MeshLineMaterial') {
|
|
448
986
|
material.defines = material.defines || {};
|
|
@@ -459,13 +997,14 @@ function draw3Dmodel(geom, instanceName, instanceCount, nColor, nOpacity) {
|
|
|
459
997
|
}
|
|
460
998
|
|
|
461
999
|
mesh = new THREE.InstancedMesh(geometry, material, instanceCount);
|
|
462
|
-
|
|
1000
|
+
mesh.count = activeInstanceCount;
|
|
463
1001
|
const { visible } = prop;
|
|
464
|
-
mesh.visible = visible;
|
|
1002
|
+
mesh.visible = visible !== undefined ? visible : true;
|
|
465
1003
|
mesh.userData.drawObjectId = instanceName;
|
|
466
|
-
mesh.userData.is3D =
|
|
467
|
-
|
|
468
|
-
|
|
1004
|
+
mesh.userData.is3D = type == GEOM_TYPES.geom_3d || type == GEOM_TYPES.geom_3d_obj;
|
|
1005
|
+
mesh.userData.transparent = isTransparent;
|
|
1006
|
+
mesh.userData.instanceCapacity = instanceCount;
|
|
1007
|
+
mesh.userData.instanceCount = activeInstanceCount;
|
|
469
1008
|
return mesh;
|
|
470
1009
|
}
|
|
471
1010
|
|
|
@@ -476,7 +1015,7 @@ function draw3Dmodel(geom, instanceName, instanceCount, nColor, nOpacity) {
|
|
|
476
1015
|
* @param {String} instanceName - 模型实例的名称
|
|
477
1016
|
* @returns {Object} - 包含所有 2D 模型的组对象
|
|
478
1017
|
*/
|
|
479
|
-
function draw2Dmodel(geom, instanceName, instanceCount) {
|
|
1018
|
+
function draw2Dmodel(geom, instanceName, instanceCount, options = {}) {
|
|
480
1019
|
const points = geom.points;
|
|
481
1020
|
const normals = geom.normals;
|
|
482
1021
|
const geometry = new THREE.BufferGeometry();
|
|
@@ -508,7 +1047,8 @@ function draw2Dmodel(geom, instanceName, instanceCount) {
|
|
|
508
1047
|
material,
|
|
509
1048
|
},
|
|
510
1049
|
instanceName,
|
|
511
|
-
instanceCount
|
|
1050
|
+
instanceCount,
|
|
1051
|
+
options
|
|
512
1052
|
);
|
|
513
1053
|
// mesh.raycast = raycast;
|
|
514
1054
|
|
|
@@ -519,7 +1059,7 @@ function draw2Dmodel(geom, instanceName, instanceCount) {
|
|
|
519
1059
|
}
|
|
520
1060
|
|
|
521
1061
|
// drawText 方法,用于渲染 2D 或 3D 文字
|
|
522
|
-
function drawText(geom, instanceName, instanceCount) {
|
|
1062
|
+
function drawText(geom, instanceName, instanceCount, options = {}) {
|
|
523
1063
|
const { prop, text, points, normals } = geom;
|
|
524
1064
|
const { color, linewidth, fontsize, fontname, rotate, italic, widthscale } = prop;
|
|
525
1065
|
|
|
@@ -546,7 +1086,8 @@ function drawText(geom, instanceName, instanceCount) {
|
|
|
546
1086
|
normals,
|
|
547
1087
|
},
|
|
548
1088
|
instanceName,
|
|
549
|
-
instanceCount
|
|
1089
|
+
instanceCount,
|
|
1090
|
+
options
|
|
550
1091
|
);
|
|
551
1092
|
|
|
552
1093
|
// 创建平移矩阵并应用
|
|
@@ -648,4 +1189,11 @@ function createAlignedText(align = TextAlign.TextLeftBottom, geometry) {
|
|
|
648
1189
|
return alignMatrix;
|
|
649
1190
|
}
|
|
650
1191
|
|
|
651
|
-
export {
|
|
1192
|
+
export {
|
|
1193
|
+
handleInstancedMeshModel,
|
|
1194
|
+
resetProcessingState,
|
|
1195
|
+
PRIMITIVE_TYPE,
|
|
1196
|
+
draw3Dmodel,
|
|
1197
|
+
getDrawObjectInstance,
|
|
1198
|
+
instanceToInstancedMeshMap,
|
|
1199
|
+
};
|