|
@@ -2,202 +2,75 @@ import * as THREE from 'three';
|
|
|
|
|
|
export class bdfDataRenderer {
|
|
export class bdfDataRenderer {
|
|
constructor(updateProgress, onComplete) {
|
|
constructor(updateProgress, onComplete) {
|
|
- this.updateProgress = updateProgress; // 进度更新回调
|
|
|
|
- this.onComplete = onComplete; // 渲染完成回调
|
|
|
|
|
|
+ this.updateProgress = updateProgress;
|
|
|
|
+ this.onComplete = onComplete;
|
|
|
|
+ this.meshGroup = new THREE.Group();
|
|
|
|
+
|
|
|
|
+ this.defaultMaterial = new THREE.MeshPhongMaterial({
|
|
|
|
+ color: 0x2194ce,
|
|
|
|
+ side: THREE.DoubleSide,
|
|
|
|
+ flatShading: true,
|
|
|
|
+ transparent: true,
|
|
|
|
+ opacity: 0.8
|
|
|
|
+ });
|
|
}
|
|
}
|
|
- render(bdfData, scene) {
|
|
|
|
- const { grids, cquadrs } = bdfData;
|
|
|
|
|
|
|
|
- // 渲染节点(分块加载)
|
|
|
|
- this.renderGridsInChunks(grids, scene);
|
|
|
|
|
|
+ async render(bdfData, scene) {
|
|
|
|
+ this.clearScene(scene);
|
|
|
|
+ scene.add(this.meshGroup);
|
|
|
|
|
|
- // 渲染四边形单元(分块加载)
|
|
|
|
- this.renderCquadrsInChunks(cquadrs, grids, scene);
|
|
|
|
- }
|
|
|
|
|
|
+ try {
|
|
|
|
+ await this.updateProgressAsync('开始渲染BDF模型...');
|
|
|
|
+
|
|
|
|
+ // 直接使用原始数据格式,不经过解析器转换
|
|
|
|
+ const { vertices, indices } = bdfData;
|
|
|
|
|
|
- /**
|
|
|
|
- * 分块渲染节点(grids)
|
|
|
|
- * @param {Array} grids - 节点数据
|
|
|
|
- * @param {THREE.Scene} scene - Three.js场景
|
|
|
|
- */
|
|
|
|
- renderGridsInChunks(grids, scene) {
|
|
|
|
- if (!grids || grids.length === 0) return;
|
|
|
|
-
|
|
|
|
- const chunkSize = 1000; // 每块渲染1000个节点
|
|
|
|
- let index = 0;
|
|
|
|
-
|
|
|
|
- // 创建高精度几何体和材质
|
|
|
|
- const highDetailGeometry = new THREE.SphereGeometry(0.5, 16, 16);
|
|
|
|
- const highDetailMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
|
|
|
|
-
|
|
|
|
- // 创建低精度几何体和材质
|
|
|
|
- const lowDetailGeometry = new THREE.SphereGeometry(0.5, 8, 8);
|
|
|
|
- const lowDetailMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
|
|
|
|
-
|
|
|
|
- // 创建 LOD 对象
|
|
|
|
- const lod = new THREE.LOD();
|
|
|
|
-
|
|
|
|
- // 创建高精度 InstancedMesh
|
|
|
|
- const highDetailInstancedMesh = new THREE.InstancedMesh(highDetailGeometry, highDetailMaterial, grids.length);
|
|
|
|
- const lowDetailInstancedMesh = new THREE.InstancedMesh(lowDetailGeometry, lowDetailMaterial, grids.length);
|
|
|
|
-
|
|
|
|
- // 将高精度和低精度 InstancedMesh 添加到 LOD
|
|
|
|
- lod.addLevel(highDetailInstancedMesh, 0); // 距离小于50时使用高精度
|
|
|
|
- lod.addLevel(lowDetailInstancedMesh, 50); // 距离大于50时使用低精度
|
|
|
|
-
|
|
|
|
- const matrix = new THREE.Matrix4(); // 用于设置每个实例的位置
|
|
|
|
-
|
|
|
|
- const renderChunk = () => {
|
|
|
|
- for (let i = 0; i < chunkSize && index < grids.length; i++, index++) {
|
|
|
|
- const grid = grids[index];
|
|
|
|
- const { x, y, z } = grid;
|
|
|
|
-
|
|
|
|
- // 设置实例的位置
|
|
|
|
- matrix.setPosition(x, y, z);
|
|
|
|
- highDetailInstancedMesh.setMatrixAt(index, matrix);
|
|
|
|
- lowDetailInstancedMesh.setMatrixAt(index, matrix);
|
|
|
|
|
|
+ await this.updateProgressAsync('创建几何体...');
|
|
|
|
+ const geometry = new THREE.BufferGeometry();
|
|
|
|
+
|
|
|
|
+ // 设置顶点属性(直接使用原始数组)
|
|
|
|
+ geometry.setAttribute(
|
|
|
|
+ 'position',
|
|
|
|
+ new THREE.BufferAttribute(new Float32Array(vertices), 3)
|
|
|
|
+ );
|
|
|
|
|
|
- // 更新进度
|
|
|
|
- if (this.updateProgress) {
|
|
|
|
- this.updateProgress(index, grids.length);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 打印当前进度
|
|
|
|
- console.log(`Rendering grids: ${index} / ${grids.length} (${((index / grids.length) * 100).toFixed(2)}%)`);
|
|
|
|
-
|
|
|
|
- // 如果还有数据未渲染,继续渲染下一块
|
|
|
|
- if (index < grids.length) {
|
|
|
|
- requestAnimationFrame(renderChunk);
|
|
|
|
- } else {
|
|
|
|
- console.log('Grids rendering completed!');
|
|
|
|
- if (this.onComplete) {
|
|
|
|
- this.onComplete(); // 调用渲染完成回调
|
|
|
|
- }
|
|
|
|
- highDetailInstancedMesh.instanceMatrix.needsUpdate = true; // 更新高精度实例化矩阵
|
|
|
|
- lowDetailInstancedMesh.instanceMatrix.needsUpdate = true; // 更新低精度实例化矩阵
|
|
|
|
- scene.add(lod); // 将 LOD 添加到场景中
|
|
|
|
|
|
+ // 设置索引(直接使用原始数组)
|
|
|
|
+ if (indices && indices.length > 0) {
|
|
|
|
+ geometry.setIndex(
|
|
|
|
+ new THREE.BufferAttribute(new Uint32Array(indices), 1)
|
|
|
|
+ );
|
|
}
|
|
}
|
|
- };
|
|
|
|
-
|
|
|
|
- // 开始渲染
|
|
|
|
- renderChunk();
|
|
|
|
|
|
+
|
|
|
|
+ await this.updateProgressAsync('优化几何体...');
|
|
|
|
+ geometry.computeVertexNormals();
|
|
|
|
+ geometry.computeBoundingSphere();
|
|
|
|
+
|
|
|
|
+ await this.updateProgressAsync('创建网格...');
|
|
|
|
+ const mesh = new THREE.Mesh(geometry, this.defaultMaterial);
|
|
|
|
+ this.meshGroup.add(mesh);
|
|
|
|
+
|
|
|
|
+ if (this.onComplete) this.onComplete();
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error('BDF渲染错误:', error);
|
|
|
|
+ if (this.onComplete) this.onComplete(error);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * 分块渲染四边形单元(CQUADR)
|
|
|
|
- * @param {Array} cquadrs - 四边形单元数据
|
|
|
|
- * @param {Array} grids - 节点数据
|
|
|
|
- * @param {THREE.Scene} scene - Three.js场景
|
|
|
|
- */
|
|
|
|
- renderCquadrsInChunks(cquadrs, grids, scene) {
|
|
|
|
- if (!cquadrs || cquadrs.length === 0) return;
|
|
|
|
-
|
|
|
|
- const chunkSize = 1000; // 每块渲染1000个四边形单元
|
|
|
|
- let index = 0;
|
|
|
|
-
|
|
|
|
- // 创建高精度几何体和材质
|
|
|
|
- const highDetailMaterial = new THREE.MeshBasicMaterial({
|
|
|
|
- color: 0x00ffff, // 绿色
|
|
|
|
- side: THREE.DoubleSide, // 双面渲染
|
|
|
|
- transparent: true,
|
|
|
|
- opacity: 0.7 // 半透明
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // 创建低精度几何体和材质
|
|
|
|
- const lowDetailMaterial = new THREE.MeshBasicMaterial({
|
|
|
|
- color: 0x00ffff, // 绿色
|
|
|
|
- side: THREE.DoubleSide, // 双面渲染
|
|
|
|
- transparent: true,
|
|
|
|
- opacity: 0.5 // 更低透明度
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // 创建 LOD 对象
|
|
|
|
- const lod = new THREE.LOD();
|
|
|
|
-
|
|
|
|
- // 创建合并的高精度几何体
|
|
|
|
- const highDetailGeometry = new THREE.BufferGeometry();
|
|
|
|
- const highDetailVertices = [];
|
|
|
|
- const highDetailIndices = [];
|
|
|
|
-
|
|
|
|
- // 创建合并的低精度几何体
|
|
|
|
- const lowDetailGeometry = new THREE.BufferGeometry();
|
|
|
|
- const lowDetailVertices = [];
|
|
|
|
- const lowDetailIndices = [];
|
|
|
|
-
|
|
|
|
- const renderChunk = () => {
|
|
|
|
- for (let i = 0; i < chunkSize && index < cquadrs.length; i++, index++) {
|
|
|
|
- const cquadr = cquadrs[index];
|
|
|
|
- const { nodeIds } = cquadr;
|
|
|
|
-
|
|
|
|
- // 获取四边形单元的四个节点
|
|
|
|
- const quadVertices = nodeIds.map((nodeId) => {
|
|
|
|
- const grid = grids.find((g) => g.id === nodeId);
|
|
|
|
- if (!grid) {
|
|
|
|
- console.warn(`Node ${nodeId} not found in grids`);
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
- return [grid.x, grid.y, grid.z];
|
|
|
|
- }).filter(Boolean); // 过滤掉无效节点
|
|
|
|
-
|
|
|
|
- // 如果节点数量不足4个,跳过渲染
|
|
|
|
- if (quadVertices.length < 4) {
|
|
|
|
- console.warn(`CQUADR with nodes ${nodeIds.join(', ')} has insufficient vertices`);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 将顶点添加到高精度和低精度几何体中
|
|
|
|
- const baseIndex = highDetailVertices.length / 3;
|
|
|
|
- quadVertices.forEach((vertex) => {
|
|
|
|
- highDetailVertices.push(...vertex);
|
|
|
|
- lowDetailVertices.push(...vertex);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // 添加四边形单元的索引
|
|
|
|
- highDetailIndices.push(baseIndex, baseIndex + 1, baseIndex + 2);
|
|
|
|
- highDetailIndices.push(baseIndex, baseIndex + 2, baseIndex + 3);
|
|
|
|
-
|
|
|
|
- lowDetailIndices.push(baseIndex, baseIndex + 1, baseIndex + 2);
|
|
|
|
- lowDetailIndices.push(baseIndex, baseIndex + 2, baseIndex + 3);
|
|
|
|
- }
|
|
|
|
- // 更新进度
|
|
|
|
- if (this.updateProgress) {
|
|
|
|
- this.updateProgress(index, cquadrs.length);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 打印当前进度
|
|
|
|
- console.log(`Rendering CQUADRs: ${index} / ${cquadrs.length} (${((index / cquadrs.length) * 100).toFixed(2)}%)`);
|
|
|
|
-
|
|
|
|
- // 如果还有数据未渲染,继续渲染下一块
|
|
|
|
- if (index < cquadrs.length) {
|
|
|
|
- requestAnimationFrame(renderChunk);
|
|
|
|
- } else {
|
|
|
|
- console.log('CQUADRs rendering completed!');
|
|
|
|
- if (this.onComplete) {
|
|
|
|
- this.onComplete(); // 调用渲染完成回调
|
|
|
|
- }
|
|
|
|
- // 设置高精度几何体的顶点和索引
|
|
|
|
- highDetailGeometry.setAttribute('position', new THREE.Float32BufferAttribute(highDetailVertices, 3));
|
|
|
|
- highDetailGeometry.setIndex(highDetailIndices);
|
|
|
|
-
|
|
|
|
- // 设置低精度几何体的顶点和索引
|
|
|
|
- lowDetailGeometry.setAttribute('position', new THREE.Float32BufferAttribute(lowDetailVertices, 3));
|
|
|
|
- lowDetailGeometry.setIndex(lowDetailIndices);
|
|
|
|
-
|
|
|
|
- // 创建高精度和低精度网格
|
|
|
|
- const highDetailMesh = new THREE.Mesh(highDetailGeometry, highDetailMaterial);
|
|
|
|
- const lowDetailMesh = new THREE.Mesh(lowDetailGeometry, lowDetailMaterial);
|
|
|
|
-
|
|
|
|
- // 将高精度和低精度网格添加到 LOD
|
|
|
|
- lod.addLevel(highDetailMesh, 0); // 距离小于50时使用高精度
|
|
|
|
- lod.addLevel(lowDetailMesh, 50); // 距离大于50时使用低精度
|
|
|
|
-
|
|
|
|
- // 将 LOD 添加到场景中
|
|
|
|
- scene.add(lod);
|
|
|
|
|
|
+ async updateProgressAsync(message) {
|
|
|
|
+ if (this.updateProgress) {
|
|
|
|
+ this.updateProgress(message);
|
|
|
|
+ await new Promise(resolve => requestAnimationFrame(resolve));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clearScene(scene) {
|
|
|
|
+ this.meshGroup.traverse(child => {
|
|
|
|
+ if (child.isMesh) {
|
|
|
|
+ child.geometry.dispose();
|
|
|
|
+ child.material.dispose();
|
|
}
|
|
}
|
|
- };
|
|
|
|
-
|
|
|
|
- // 开始渲染
|
|
|
|
- renderChunk();
|
|
|
|
|
|
+ });
|
|
|
|
+ scene.remove(this.meshGroup);
|
|
|
|
+ this.meshGroup = new THREE.Group();
|
|
}
|
|
}
|
|
}
|
|
}
|