Aset 3D pada aplikasi web sering menjadi penyebab utama lonjakan First Contentful Paint (FCP) dan memory leak di WebGL context. Model 3D hasil ekspor dari software modeling atau visual web modeler sering membawa geometri unindexed, resolusi tekstur berlebih (misal 4K), serta struktur node yang tidak efisien. Memeriksa aset ini secara manual memperlambat proses deployment dan rawan human error.
Solusinya adalah mengintegrasikan CI/CD asset 3D web untuk menjalankan validasi integritas struktur file dan kompresi aset secara otomatis sebelum model masuk ke production storage atau repository statis.
Arsitektur Pipeline CI/CD untuk Asset 3D
Pipeline validasi dan optimasi aset 3D berjalan dalam alur berikut:
- Deteksi Berkas: Mengidentifikasi file
.gltfatau.glbyang berubah pada pull request. - Validasi Spesifikasi Khronos: Memeriksa integritas struktur file menggunakan
gltf-validatorresmi. Jika terjadi error sintaks, pipeline otomatis fail. - Optimasi Geometri & Tekstur: Menjalankan serangkaian transformasi dengan
@gltf-transform/cli, seperti deduping node, normalisasi ukuran tekstur, dan kompresi geometri. - Enforcement Performance Budget: Memverifikasi ukuran akhir berkas. Jika ukuran melebihi batas batas ambang yang ditentukan (misalnya 5 MB), PR check akan diblokir.
Tooling CLI Utama
Pipeline ini menggunakan dua utility berbasis Node.js:
- gltf-validator: Engine resmi dari Khronos Group untuk mendeteksi malformed glTF, missing buffer, invalid animation sampler, dan memory alignment issue.
- @gltf-transform/cli: Toolkit untuk mutasi non-destruktif: kompresi mesh (Draco atau Meshopt), konversi tekstur, instance de-duplication, dan pruning atribut yang tidak terpakai.
Draco vs Meshopt
Pilih algoritma kompresi berdasarkan kebutuhan runtime target:
- Draco (Google): Rasio kompresi sangat tinggi, ukuran berkas transfer minimal. Kelemahan: Beban dekompresi CPU di browser tinggi, decoding via Web Assembly membutuhkan waktu tambahan sebelum render awal.
- Meshopt (Meshoptimizer): Rasio kompresi sedikit lebih rendah dibanding Draco, namun dekompresi berjalan sangat cepat dengan instruksi SIMD di WASM/GPU. Cocok untuk aplikasi 3D interaktif yang menuntut frame rate tinggi saat inisiasi.
Implementasi GitHub Actions Workflow
Simpan konfigurasi pipeline berikut pada path .github/workflows/3d-asset-pipeline.yml:
name: 3D Asset CI/CD Pipeline
on:
pull_request:
paths:
- 'assets/**/*.glb'
- 'assets/**/*.gltf'
jobs:
validate-and-optimize:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install 3D Processing CLI Tools
run: |
npm install --global gltf-validator @gltf-transform/cli
- name: Identify Changed Models
id: files
run: |
# Ambil list file model yang ditambah atau diubah pada PR ini
CHANGED_FILES=$(git diff --name-only --diff-filter=d HEAD~1 HEAD | grep -E '\.(glb|gltf)$' || true)
echo "models=$CHANGED_FILES" >> $GITHUB_OUTPUT
- name: Run Integrity Validation
if: steps.files.outputs.models != ''
run: |
for file in ${{ steps.files.outputs.models }}; do
echo "Validating: $file"
gltf-validator -p -a -r "$file"
done
- name: Optimize Meshes and Textures
if: steps.files.outputs.models != ''
run: |
mkdir -p dist/assets
for file in ${{ steps.files.outputs.models }}; do
filename=$(basename "$file")
target_path="dist/assets/$filename"
echo "Optimizing: $file -> $target_path"
# Pipeline optimasi:
# 1. dedup: Hapus duplikat mesh/material
# 2. prune: Hapus accessor & vertex attributes yang tidak digunakan
# 3. resize: Batasi resolusi tekstur maksimal 2048x2048
# 4. meshopt: Kompresi mesh menggunakan meshoptimizer
gltf-transform optimize "$file" "$target_path" \
--compress meshopt \
--texture-size 2048
done
- name: Enforce Performance Budget
if: steps.files.outputs.models != ''
run: |
# Performance budget batas atas: 5 MB per model
MAX_SIZE_KB=5120
FAILED=0
for optimized_file in dist/assets/*; do
FILE_SIZE_KB=$(du -k "$optimized_file" | cut -f1)
echo "File: $optimized_file - Size: ${FILE_SIZE_KB} KB (Max: ${MAX_SIZE_KB} KB)"
if [ "$FILE_SIZE_KB" -gt "$MAX_SIZE_KB" ]; then
echo "::error file=$optimized_file::Model melebihi budget performa (${FILE_SIZE_KB} KB > ${MAX_SIZE_KB} KB)!"
FAILED=1
fi
done
if [ "$FAILED" -eq 1 ]; then
echo "Pull Request diblokir: Optimasi aset gagal memenuhi kriteria performa web."
exit 1
fi
- name: Upload Optimized Artifacts
if: steps.files.outputs.models != ''
uses: actions/upload-artifact@v4
with:
name: optimized-3d-assets
path: dist/assets/
Detail Langkah Optimasi
1. Deteksi Error Integrity
Command gltf-validator -p -a -r menghasilkan output status validasi dalam format JSON/teks. Flag -p memverifikasi pointer URI, flag -a memastikan seluruh buffer binari di-decode untuk mencari nilai NaN atau floating-point overflow pada vertex position.
2. Texture Downsampling
Beban GPU WebGL paling besar sering kali bukan polycount, melainkan VRAM yang dikonsumsi oleh tekstur uncompressed. Opsi --texture-size 2048 pada gltf-transform secara rekursif mereduksi resolusi diffuse, roughness, dan normal map ke resolusi maksimum 2048x2048, menjaga rasio aspek sembari menghemat memory footprint.
3. Performance Budget Blocker
Langkah budget check berfungsi sebagai quality gate. Menghentikan pipeline dengan status exit code 1 otomatis menandai status commit check PR menjadi failed di GitHub. Ini mencegah tim developer atau artis 3D me-merge model berukuran puluhan megabyte yang dapat merusak user experience di mobile browser.
Troubleshooting Masalah Umum
- Texture Degradation: Jika normal map terlihat rusak pasca kompresi, pastikan filtering map tidak diubah menjadi format lossy ekstrem. Tambahkan flag
--keep-materialsatau batasi kompresi tekstur ke format KTX2/Basis Universal untuk mempertahankan visual fidelity. - Missing Skinning/Bones: Flag
pruneterkadang menghapus skin node jika animator menggunakan empty bone helper. Gunakan parameter preserve bones jika model memiliki animasi skeletal rigging kompleks.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!