前端3D场景模型压缩减面分享

前言

做3D场景相关项目的都知道,3D场景中常见的痛点,便是模型过大,面数过多,纹理太高清,节点层级过多等等,导致场景加载慢,渲染性能低,场景帧率低,如果模型开发的配合,可以让他们把模型优化下,如果不配合,那就只能另外想办法了。 这篇文章主要介绍怎么利用现有的开源库,对模型进行减面和压缩。因为我们主要使用GLTF格式模型,所以,本文技术只针对GLTF/GLB模型

减面压缩效果

  • 第一张图片是最大保留外观的同时,面数减少一半,
  • 第二张图是是不保留外观时减面,面数减少80%,
  • 第三张图是纹理压缩后,文件大小减80%

总之,效果显著,有兴趣可以在点击查看

技术分析

以上效果主要使用以下技术:

  1. Babylonjs 用于3D渲染展示
  2. glTF-Transform 用于读写操作gltf文件
  3. sharp 用于图片压缩
  4. meshoptimizer 用于网格减面

其中网格减面可以在客户端进行,纹理压缩只能在服务端进行,本文主要介绍在服务端使用

技术实现

先简单介绍gltf-transfrom的使用

javascript 复制代码
import { Document, NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import draco3d from 'draco3dgltf';

// 使用库内置的IO工具
const io = new NodeIO()
    .registerExtensions(ALL_EXTENSIONS)
    .registerDependencies({
        'draco3d.decoder': await draco3d.createDecoderModule(), // Optional.
        'draco3d.encoder': await draco3d.createEncoderModule(), // Optional.
    });

// 读取glb/gltf文件,2种格式模型读取方式一致,最终输出结果都是Document对象
// Document 是该库的核心数据类型,里面存储模型的所有数据,我们对模型的所有操作都将操作这个模型
const document = await io.read('path/to/model.glb');
const document = await io.read('path/to/model.gltf');

// 输出glb/gltf文件
// 1. 输出glb文件,这个很简单,只要
 await io.write("/path/ouput.glb", document);

// 2. 输出gltf 文件,输出gltf文件比较麻烦
 // 输出JSONDocument,这个对象包含 glTF 文件的原始 JSON 以及该文件引用的任何二进制或图像资源
 await io.writeJSON(document); --->JSONDocument
   然后我们需要分析这个json,输出对象内的图片,bin,以及.gltf到指定目录
   比如
   fs.writeFile("out.gltf",jSONDocument.json);
   fs.writeFile("out.bin",json.resources.bin)

上面主要介绍了gltf文件的读写,接下来,我们实现模型减面

javascript 复制代码
import { simplify, textureCompress, weld } from "@gltf-transform/functions";
import { MeshoptSimplifier } from "meshoptimizer";
  // 减面需要这2个主要参数,ratio是减面率,越低减面效果越好,error是误差率,越高,外观变形越严重
  const { ratio, error = 0.001} = options;
  
  //开始减面,我们拿上传读取出来的document,进行减面
  // weld主要是对顶点进行优化,尽可能提高减面质量
  await document.transform(
    weld({ tolerance: 0.0001 }),
    simplify({
      simplifier: MeshoptSimplifier,
      ratio: ratio,
      error
    })
  );

纹理压缩

javascript 复制代码
import sharp from "sharp";

  await document.transform(
      textureCompress({
        encoder: sharp,
        //最大纹理宽高,并保留纹理的宽高比
        resize: [1024, 1024],
        //纹理压缩质量,范围是1-100,可以不传
        quality: 50,
      })
    );

另外,这个库还提高的网格节点展平,合并等功能,可以自行查看和实现

Document操作后,输出到指定目录,就完成了对模型的减面和压缩操作

总结

本文主要介绍了GLTF文件的减面和纹理压缩操作,减面和压缩后,可以应用到LOD中,可提高场景的渲染效果, 具体代码以及文章开头的实现效果可以访问代码仓库查看。

相关推荐
爱学习的程序媛4 分钟前
【Web前端】JavaScript设计模式全解析
前端·javascript·设计模式·web
小码哥_常13 分钟前
从SharedPreferences到DataStore:Android存储进化之路
前端
老黑22 分钟前
开源工具 AIDA:给 AI 辅助开发加一个数据采集层,让 AI 从错误中自动学习(Glama 3A 认证)
前端·react.js·ai·nodejs·cursor·vibe coding·claude code
jessecyj37 分钟前
Spring boot整合quartz方法
java·前端·spring boot
苦瓜小生1 小时前
【前端】|【js手撕】经典高频面试题:手写实现function.call、apply、bind
java·前端·javascript
天若有情6731 小时前
前端HTML精讲03:页面性能优化+懒加载,搞定首屏加速
前端·性能优化·html
踩着两条虫1 小时前
AI驱动的Vue3应用开发平台深入探究(十):物料系统之内置组件库
android·前端·vue.js·人工智能·低代码·系统架构·rxjava
swipe2 小时前
AI 应用里的 Memory,不是“保存聊天记录”,而是管理上下文预算
前端·llm·agent
慧一居士2 小时前
nuxt3 项目和nuxt4 项目区别和对比
前端·vue.js
威联通安全存储2 小时前
破除“重前端、轻底层”的数字幻象:如何夯实工业数据的物理底座
前端·python