前序
刚写完个新需求,记录一下:读取本地Excel文件,根据文件内信息,请求模型库模型,最后将加载的全部模型导出为一个整体。逻辑较为简单,主要是导出功能,第一次接触
实现思路
-
读取本地Excel
-
遍历Excel数组
-
全部加载完毕后,导出一个整体
代码步骤
读取本地Excel
import * as XLSX from 'xlsx';
// 前端文件导入解析成传递给服务器的数据
export let resolveFile = (event) => {
return new Promise((resolve, reject) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
// Assuming the first row contains headers
const headers = jsonData[0];
const dataRows = jsonData.slice(1);
// Convert data to objects with headers as keys
const formattedData = dataRows.map(row => {
const obj = {};
headers.forEach((header, i) => {
obj[header] = row[i];
});
return obj;
});
resolve(formattedData);
};
reader.readAsArrayBuffer(file);
})
}
这里注意的是, 《 * as XLSX》不使用这种引入方式,会有问题
遍历Excel数组
将Excel得到的数组传递给加载模型的模块
// 生成变电站
async JointSite() {
// 获取模型承载器
const container = document.querySelector('#JointModelContainer');
// 实例化模型器皿
this.jointModel = new JointModel(container);
// 递归渲染
this.renderWinery();
if(this.excelData.length) {
// 加载模型
await this.jointModel.loadJointModel(this.excelData);
}
},
使用for循环,请求模型库
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import instance from '../../global';
async function loadModel(singleModel) {
const loader = new GLTFLoader();
return new Promise((resolve, reject) => {
instance.get('api', {
params: {
filename: singleModel
},
responseType: "arraybuffer", // 转成二进制
})
.then((res) => {
// console.log('res:', res);
// 将二进制数据转换为Blob对象
const blob = new Blob([res.data]);
// 创建Blob URL
const url = URL.createObjectURL(blob);
loader.load(
url,
(gltf) => {
resolve(gltf);
},
undefined,
(error) => {
console.log(`Error loading GLB file`);
reject(error);
}
)
})
.catch((error) => {
console.log(`1层捕捉到了请求API错误↑(检查MinIO中是否存在该模型:${singleModel})`);
reject(error);
})
})
}
export { loadModel }
这里是循环以及处理每一个模型
for (let item = 0; item < staticSourceDatas.length; item++) {
console.log(staticSourceDatas[item]);
try {
// 从模型库请求模型
let gltf = await loadModel(staticSourceDatas[item].model_name);
if(gltf) {
scene.add(gltf?.scene);
this.render();
}
}
}
以上逻辑正确的话,在页面中可以看到模型依次加载/渲染的效果
scene.add(gltf?.scene); 是关键,将请求到的模型放置到一个场景下。这里注意的是:scene必须是私有变量。
全部加载完毕后,导出gltf
导出主代码
import { GLTFExporter } from 'three/addons/exporters/GLTFExporter.js';
function exportGLTF( input, callback ) {
const gltfExporter = new GLTFExporter();
const options = {
trs: params.trs,
onlyVisible: params.onlyVisible,
binary: params.binary,
maxTextureSize: params.maxTextureSize
};
gltfExporter.parse(
input,
function ( result ) {
if ( result instanceof ArrayBuffer ) {
saveArrayBuffer( result, 'scene.glb' );
} else {
const output = JSON.stringify( result, null, 2 );
saveString( output, 'scene.gltf' );
}
if (callback) {
callback(true); // 下载完成状态为 true
}
},
function ( error ) {
console.log( '文件导出解析过程中发生错误', error );
},
options
);
}
const link = document.createElement( 'a' );
link.style.display = 'none';
document.body.appendChild( link );
function save( blob, filename ) {
link.href = URL.createObjectURL( blob );
link.download = filename;
link.click();
// URL.revokeObjectURL( link.href );
}
function saveString( text, filename ) {
save( new Blob( [ text ], { type: 'text/plain' } ), filename );
}
function saveArrayBuffer( buffer, filename ) {
save( new Blob( [ buffer ], { type: 'application/octet-stream' } ), filename );
}
const params = {
trs: false,
onlyVisible: true,
binary: false,
maxTextureSize: 4096,
};
export { exportGLTF }
在上面代码中,我将下载的进度使用回调函数返回去了,那么就可以拿到下载完成?的状态
exportGLB() {
// 导出GLB
console.log('开始下载...');
return new Promise((resolve, reject) => {
exportGLTF(scene, (downState) => {
resolve(downState);
})
})
}
ok,最后在vue文件给个下载完成的提示
// 导出GLB
exportFileGLB() {
this.jointModel.exportGLB()
.then((res) => {
if(res) {
this.$message.success('导出成功');
} else {
this.$message.success('导出失败');
}
})
},
这些threeJs官方,都有示例:
three.js/examples/misc_exporter_gltf.html at master · mrdoob/three.js · GitHub
感兴趣的小伙伴,可以看一看 文中提到的KTX2Loader 和 MeshoptDecoder
这两个都是用来优化的点。拜~