feat: LOD 网格分级——meshopt 解析期简化 + 按距离/级联选级

vendored meshoptimizer 1.2(submodule 环境故障改直接 vendor)。Mesh
多 LOD:各级索引连续拼进同一 index buffer(共享顶点,LodRange 区间
选择),解析期 meshopt_simplify 生成链(LOD0=原始,每级目标减半,
相对误差 1e-2,小网格复用上级);都在 worker 线程,加载零额外卡顿。

SceneRenderer 按 (mesh, LOD) 聚合 batch(lookup key = 指针<<8|lod):
主视图按屏占比近似 radius/dist 选级(阈值 10/20 倍半径);阴影级联
按级联序降级(越远越简)。Draw 按 batch.lod 选索引区间。

A/B 对比(100 背包 10×10,RTX 5060 Laptop,vsync off):
- 纯背包:LOD 开 93-95 fps / 关 90-107 fps —— 无显著差异
- 加 SunTemple:LOD 开 52-56 / 关 51-55 —— 无显著差异
结论:当前场景瓶颈不在顶点数(5060 顶点吞吐富余),LOD 基础设施
保留(几何复杂资产/低端 GPU/更大场景生效),帧率问题转向 Tracy
GPU 时间线定位真实瓶颈。

坑:LodRange 记录"LOD 不足复用最后一级"时 first 不得继续累加
(buffer 无重复数据,累加必越界——VUID-08798 抓的)。
This commit is contained in:
2026-09-24 20:53:19 +08:00
parent 34b593f734
commit 5bdfb53566
125 changed files with 67608 additions and 29 deletions
+240
View File
@@ -0,0 +1,240 @@
name: build
on:
push:
branches:
- 'master'
paths-ignore:
- '*.md'
pull_request:
paths-ignore:
- '*.md'
jobs:
unix:
strategy:
matrix:
os:
[
{ name: ubuntu, version: ubuntu-latest },
{ name: ubuntu-arm, version: ubuntu-24.04-arm },
{ name: ubuntu-clang, version: ubuntu-latest },
{ name: macos, version: macos-latest },
]
name: ${{matrix.os.name}}
runs-on: ${{matrix.os.version}}
env:
werror: 1
steps:
- uses: actions/checkout@v6
- name: work around ASLR+ASAN compatibility
run: sudo sysctl -w vm.mmap_rnd_bits=28
if: matrix.os.name == 'ubuntu'
- name: enable clang
run: echo CXX=clang++ >Makefile.config
if: matrix.os.name == 'ubuntu-clang'
- name: make test
run: |
make -j2 config=sanitize test
make -j2 config=debug test
make -j2 config=release test
make -j2 config=coverage test
make -j2 config=coverage-scalar test
- name: make gltfpack
run: make -j2 config=release gltfpack
- name: upload coverage
run: |
find . -type f -name '*.gcno' -exec gcov -p {} +
sed -i -e "s/#####\(.*\)\(\/\/ unreachable.*\)/ -\1\2/" *.gcov
bash <(curl -s https://codecov.io/bash) -f './src*.gcov' -X search -t ${{secrets.CODECOV_TOKEN}} -B ${{github.ref}}
if: matrix.os.name != 'ubuntu-clang'
windows:
strategy:
matrix:
arch:
[
{ name: windows, runner: windows-latest, arch: x64 },
{ name: windows-x86, runner: windows-latest, arch: Win32 },
{ name: windows-arm, runner: windows-11-arm, arch: ARM64 },
]
name: ${{matrix.arch.name}}
runs-on: ${{matrix.arch.runner}}
steps:
- uses: actions/checkout@v6
- name: cmake configure
run: cmake . -DMESHOPT_BUILD_DEMO=ON -DMESHOPT_BUILD_GLTFPACK=ON -DMESHOPT_WERROR=ON -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded$<$<CONFIG:Debug>:Debug>" -A ${{matrix.arch.arch}}
- name: cmake test
shell: bash # necessary for fail-fast
run: |
cmake --build . -- -property:Configuration=Debug -verbosity:minimal
Debug/meshoptdemo.exe demo/pirate.obj
cmake --build . -- -property:Configuration=Release -verbosity:minimal
Release/meshoptdemo.exe demo/pirate.obj
nodejs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '16'
- name: test decoder
run: node js/meshopt_decoder.test.js
- name: test simd decoder
run: node --experimental-wasm-simd js/meshopt_decoder.test.js
- name: test encoder
run: node js/meshopt_encoder.test.js
- name: test simplifier
run: node js/meshopt_simplifier.test.js
- name: test clusterizer
run: node js/meshopt_clusterizer.test.js
- name: test tangents
run: node js/meshopt_tangents.test.js
- name: check typescript declarations
run: npx --yes -p typescript@6 tsc --noEmit --moduleResolution node16 --module node16 --strict js/index.d.ts
- name: check es5
run: |
npm install -g es-check@7.2.1
npx es-check --module es5 js/meshopt_decoder.mjs js/meshopt_encoder.js js/meshopt_simplifier.js js/meshopt_clusterizer.js js/meshopt_tangents.js
npx es-check --module es2020 gltf/library.js
gltfpack:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v6
with:
repository: KhronosGroup/glTF-Sample-Assets
path: glTF-Sample-Assets
- name: work around ASLR+ASAN compatibility
run: sudo sysctl -w vm.mmap_rnd_bits=28
- name: make
run: make -j2 config=sanitize gltfpack
- name: test
run: find glTF-Sample-Assets -name '*.gltf' -or -name '*.glb' | xargs -P 2 -L 16 -d '\n' ./gltfpack -cc -test
- name: pack
run: find glTF-Sample-Assets -name '*.gltf' | grep -v '\-Draco/' | xargs -P 2 -L 16 -d '\n' -I '{}' ./gltfpack -i '{}' -o '{}pack.gltf'
- name: validate
run: |
curl -sL $VALIDATOR | tar xJ
find glTF-Sample-Assets -name '*.gltfpack.gltf' | xargs -P 2 -L 1 -d '\n' ./gltf_validator -r -a
env:
VALIDATOR: https://github.com/KhronosGroup/glTF-Validator/releases/download/2.0.0-dev.3.10/gltf_validator-2.0.0-dev.3.10-linux64.tar.xz
gltfpack-js:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '18'
- name: install wasi
run: |
curl -sL https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$VERSION/wasi-sdk-$VERSION.0-x86_64-linux.deb > wasi-sdk.deb
sudo dpkg -i wasi-sdk.deb
env:
VERSION: 32
- name: build
run: |
make -j2 -B gltf/library.wasm js
git status
- name: test
run: |
node gltf/cli.js -i demo/pirate.obj -o pirate.glb -v
node gltf/cli.js -i `pwd`/pirate.glb -o pirate-repack.glb -cc -v
wc -c pirate.glb pirate-repack.glb
node js/meshopt_decoder.test.js
node js/meshopt_encoder.test.js
node js/meshopt_simplifier.test.js
node js/meshopt_clusterizer.test.js
node js/meshopt_tangents.test.js
gltfpack-full:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v6
with:
repository: zeux/basis_universal
ref: gltfpack
path: basis_universal
- uses: actions/checkout@v6
with:
repository: webmproject/libwebp
ref: 1.6.0
path: libwebp
- name: cmake configure
run: cmake . -DMESHOPT_BUILD_GLTFPACK=ON -DMESHOPT_GLTFPACK_BASISU_PATH=basis_universal -DMESHOPT_GLTFPACK_LIBWEBP_PATH=libwebp
- name: cmake build
run: cmake --build . --target gltfpack -j 4
gltfpack-coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v6
with:
repository: zeux/basis_universal
ref: gltfpack
path: basis_universal
- uses: actions/checkout@v6
with:
repository: KhronosGroup/glTF-Sample-Assets
path: glTF-Sample-Assets
- name: build basisu
run: |
cd basis_universal
cmake . -D CMAKE_BUILD_TYPE=Debug
make -j4 basisu_encoder
- name: make
run: make -j2 config=coverage BASISU=basis_universal gltfpack
- name: test
run: |
find glTF-Sample-Assets -name '*.gltf' -or -name '*.glb' | xargs -P 2 -L 16 -d '\n' ./gltfpack -cc -test
./gltfpack -test demo/pirate.obj -si 0.5
./gltfpack -test demo/pirate.obj -si 0.5 -slb -se 0.02
./gltfpack -test demo/pirate.obj -si 0.1 -sa
./gltfpack -test demo/pirate.obj -noq
./gltfpack -test demo/pirate.obj -vp 16 -vt 16 -vn 16 -vc 16
./gltfpack -test demo/pirate.obj -vpf -vtf -vnf
./gltfpack -test demo/pirate.obj -vi -c
./gltfpack -test glTF-Sample-Assets/Models/ABeautifulGame/glTF/ABeautifulGame.gltf -mi -c
./gltfpack -test glTF-Sample-Assets/Models/ABeautifulGame/glTF/ABeautifulGame.gltf -kn -km -ke
./gltfpack -test glTF-Sample-Assets/Models/ABeautifulGame/glTF/ABeautifulGame.gltf -si 0.1 -sp
./gltfpack -test glTF-Sample-Assets/Models/ABeautifulGame/glTF/ABeautifulGame.gltf -si 0.1 -sv
./gltfpack -test glTF-Sample-Assets/Models/BoxTextured/glTF/BoxTextured.gltf -vpf -vtf -c
./gltfpack -test glTF-Sample-Assets/Models/BoxTextured/glTF/BoxTextured.gltf -vpf -vtf -cc
./gltfpack -test glTF-Sample-Assets/Models/BoxTextured/glTF/BoxTextured.gltf -tc
./gltfpack -test glTF-Sample-Assets/Models/BoxTextured/glTF/BoxTextured.gltf -tc -tq color 10 -tu normal,attrib -ts attrib 0.5 -tl color 512
./gltfpack -test glTF-Sample-Assets/Models/BoxTextured/glTF/BoxTextured.gltf -tr
./gltfpack -test glTF-Sample-Assets/Models/BoxTextured/glTF/BoxTextured.gltf -tc -ts 0.5 -tl 64
./gltfpack -test glTF-Sample-Assets/Models/BoxTextured/glTF/BoxTextured.gltf -tc color -tfy -tq 4 -tj 1
./gltfpack -test glTF-Sample-Assets/Models/CesiumMan/glTF/CesiumMan.gltf -tu -ts 0.6 -tp -ar 0
./gltfpack -test glTF-Sample-Assets/Models/CesiumMan/glTF/CesiumMan.gltf -gt -kv
./gltfpack -test glTF-Sample-Assets/Models/PrimitiveModeNormalsTest/glTF/PrimitiveModeNormalsTest.gltf -si 0.5
./gltfpack -test glTF-Sample-Assets/Models/VertexColorTest/glTF/VertexColorTest.gltf -si 0.5 -vc 12
./gltfpack -test glTF-Sample-Assets/Models/SimpleMeshes/glTF/SimpleMeshes.gltf -mm
./gltfpack -test glTF-Sample-Assets/Models/SimpleMeshes/glTF/SimpleMeshes.gltf -kn
echo newmtl Leather > demo/pirate.mtl
echo map_Kd leather.jpg >> demo/pirate.mtl
echo map_d leather.jpg >> demo/pirate.mtl
./gltfpack -test demo/pirate.obj
- name: test output
run: |
./gltfpack || true
./gltfpack -h || true
./gltfpack -i glTF-Sample-Assets/Models/BoxTextured/glTF/BoxTextured.gltf -o box.glb -vv -r box.json
./gltfpack -i glTF-Sample-Assets/Models/BoxTextured/glTF/BoxTextured.gltf -o box.gltf -cf
- name: upload coverage
run: |
find . -type f -name '*.gcno' -exec gcov -p {} +
sed -i -e "s/#####\(.*\)\(\/\/ unreachable.*\)/ -\1\2/" *.gcov
bash <(curl -s https://codecov.io/bash) -f './gltf*.gcov' -X search -t ${{secrets.CODECOV_TOKEN}} -B ${{github.ref}}
macos-iphone:
runs-on: macos-14
steps:
- uses: actions/checkout@v6
- name: make
run: make -j2 config=iphone
+33
View File
@@ -0,0 +1,33 @@
name: CIFuzz
on:
push:
branches:
- 'master'
paths-ignore:
- '*.md'
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'meshoptimizer'
dry-run: false
language: c++
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'meshoptimizer'
fuzz-seconds: 30
dry-run: false
language: c++
- name: Upload Crash
uses: actions/upload-artifact@v7
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
+77
View File
@@ -0,0 +1,77 @@
name: release
on:
push:
branches:
- 'master'
paths-ignore:
- '*.md'
jobs:
gltfpack:
strategy:
matrix:
os: [{ name: windows, version: windows-latest }, { name: ubuntu, version: ubuntu-22.04 }, { name: macos, version: macos-14 }]
name: gltfpack-${{matrix.os.name}}
runs-on: ${{matrix.os.version}}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v6
with:
repository: zeux/basis_universal
ref: gltfpack
path: basis_universal
- uses: actions/checkout@v6
with:
repository: webmproject/libwebp
ref: 1.6.0
path: libwebp
- name: cmake configure
run: cmake . -DMESHOPT_BUILD_GLTFPACK=ON -DMESHOPT_GLTFPACK_BASISU_PATH=basis_universal -D MESHOPT_GLTFPACK_LIBWEBP_PATH=libwebp -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded" -DCMAKE_BUILD_TYPE=Release
- name: cmake configure x64
run: cmake . -DSSE=ON -DBASISU_SSE=ON
if: matrix.os.name == 'ubuntu'
- name: cmake build
run: cmake --build . --target gltfpack --config Release -j 3
- uses: actions/upload-artifact@v7
with:
name: gltfpack-windows
path: Release/gltfpack.exe
if: matrix.os.name == 'windows'
- uses: actions/upload-artifact@v7
with:
name: gltfpack-${{matrix.os.name}}
path: gltfpack
if: matrix.os.name != 'windows'
nodejs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '18'
- name: install wasi
run: |
curl -sL https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$VERSION/wasi-sdk-$VERSION.0-x86_64-linux.deb > wasi-sdk.deb
sudo dpkg -i wasi-sdk.deb
env:
VERSION: 32
- name: build
run: |
make -j2 -B gltf/library.wasm js
git status
- name: npm pack
run: |
cp LICENSE.md gltf/
cp LICENSE.md js/
cd gltf && npm pack && cd ..
cd js && npm pack && cd ..
- uses: actions/upload-artifact@v7
with:
name: gltfpack-npm
path: gltf/gltfpack-*.tgz
- uses: actions/upload-artifact@v7
with:
name: meshoptimizer-npm
path: js/meshoptimizer-*.tgz