threejs将stl文件格式类型转为drc压缩文件类型

前言

项目中通过添加文件后,将stl格式的模型文件加载到场景中,后续发现stl格式文件太大,普遍是十几兆,最后研究出将stl格式文件转为drc格式文件加载,场景加载模型的过程只需要几秒即可,接上来上代码

// 整个项目是vue3+js的项目,通过vite进行打包,使用的pinia来替代的vuex,因为vuex已经很久没更新最新版本了,pinia是尤大神推荐的库,小伙伴可以了解下,使用方法类似但是更为简便

// handleChange为input框中file类型的change事件,当选择文件后就会触发该change事件
handleChange(file) {
const uuid = info.uuid	// 此uuid是跟随的info,由后端提供
const mark = nanoid(1)	// 此nanoid是取代hat的一个获取随机字符串的库,只有几kb大小
// filePathTransform方法外部封装,返回的path为url名称,data为blob二进制格式的内容
const { path, data } = await filePathTransform(file, uuid, mark)
console.log(path, data)
}

// 接下来是封装的工具库,内部是基于threejs的
import * as THREE from 'three'
import { PLYLoader } from 'three/examples/jsm/loaders/PLYLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { DRACOExporter } from 'three/examples/jsm/exporters/DRACOExporter'
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader'

const lOADTYPE = {
    UNKNOWN: 0,
    DRC: 1,
    STL: 2,
    PLY: 3,
    MQ: 4,
    values: {
        0: { name: 'unknown', value: 0 },
        1: { name: 'drc', value: 1 },
        2: { name: 'stl', value: 2 },
        3: { name: 'ply', value: 3 },
        4: { name: 'mq', value: 4 },
    },
}

export async function filePathTransform(file, uuid, mark) {
    let path = ''
    let data = null
    const { name } = file
    const type = name.slice(name.lastIndexOf('.') + 1)
    // 通过type的文件后缀名判断类型,如果是drc的则直接转换,否则比如stl的则需要将data转为blob二进制类型
    if (type !== 'drc') {
        path = `${mark}/${uuid}/${mark}.drc`
        data = await transformBlob(file)
    } else {
        path = `${mark}/${uuid}/${mark}${type}`
        data = file
    }
    return { path, data }
}

// 通过DRACOExporter来进行file的文件压缩,注意要使用DRACOExporter的话,需要引入文件在public/libs下引入draco文件夹
//里面内置一些decoder的js文件,具体文件可以参照[添加链接描述](https://threejs.org/docs/index.html?q=DRA#examples/zh/loaders/DRACOLoader)
// 引入完文件夹后需要在vue根目录下的index.html中<script src="/libs/draco/draco_encoder.js"></script>引入好刚刚的文件,才可以正常使用decoder,否则会报错缺少deoderModules模块
// 这里的操作就将stl格式的文件通过draco压缩成了blob二进制格式的文件,loadModel的作用是获取该文件导出的mesh网格对象
export async function transformBlob(file) {
    const exporter = new DRACOExporter()
    const mesh = await loadModel(file)
    const result = exporter.parse(mesh, {
        exportColor: false,
        exportUvs: false,
    })
    const blob = new Blob([result], { type: 'application/octet-stream' })
    return blob
}

// 创建通过file创建的mesh网格对象
// URL.createObjectURL():静态方法会创建一个DOMSring,其中包含一个表示参数中给出的对象的URL。这个URL的生命周期和创建它窗口的document绑定,这个URL对象表示指定的File对象或Blob对象
export function loadModel(file) {
    let name = file
    let path = file
    if (file instanceof Blob) {
        name = file.name
        path = URL.createObjectURL(file)
    }
    // 通过文件name值获取到文件类型
    const loaderType = getFileType(name)
    // 通过文件类型获取到对应的loader文件加载器
    const loader = setLoaderType(loaderType)
    return new Promise((resolve) => {
        loader.load(path, (geometry) => {
            const material = new THREE.MeshStandardMaterial({
                side: THREE.DoubleSide,
                color: 0xffffff,
            })
            if (!geometry.isBufferGeometry) {
                const loaderGeometry = new THREE.BufferGeometry()
                loaderGeometry.fromGeometry(geometry)
                geometry = loaderGeometry
            }
            geometry.computeVertexNormals()

            const mesh = new THREE.Mesh(geometry, material)
            mesh.url = file
            resolve(mesh)
        })
    })
}

export function getFileType(name) {
    for (const typeIndex in lOADTYPE.values) {
        const typeName = lOADTYPE.values[typeIndex].name
        const str1 = `.${typeName}`
        const str2 = `.${typeName}?`
        if (name.endsWith(str1) || name.indexOf(str2) > 0) {
            return lOADTYPE.values[typeIndex].value
        }
    }
    return lOADTYPE.UNKNOWN
}

export function setLoaderType(loadType) {
    let loader = null
    switch (loadType) {
        case lOADTYPE.DRC:
        case lOADTYPE.MQ:
        	// DRACOLoader使用也需要引入libs的draco文件
            loader = new DRACOLoader()
            loader.setDecoderPath('/libs/draco/')
            loader.setDecoderConfig({ type: 'js' })
            break

        case lOADTYPE.STL:
            loader = new STLLoader()
            break
        case lOADTYPE.PLY:
            loader = new PLYLoader()
            break
        default:
            loader = null
    }
    return loader
}

通过以上步骤完成的path就是转换好的drc文件名称,data就是转换好的二进制blob数据格式,只需要将期一起传入服务器,然后取得其服务器的网址就能使用drc格式的图片,大小一般都从十几兆变为了几KB


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值