feat: rimuovi il plugin di compressione Draco per modelli GLB
This commit is contained in:
@@ -1,128 +0,0 @@
|
|||||||
// Comprime con Draco i modelli GLB in fase di build.
|
|
||||||
//
|
|
||||||
// Ogni src/assets/models/<percorso>.glb viene scritto compresso in <outDir>/assets/models/<percorso>.glb
|
|
||||||
// (stesso URL di prima). Nel browser li decomprime il DRACOLoader di three.js (vedi starter.js).
|
|
||||||
//
|
|
||||||
// La compressione è lenta, quindi i risultati sono in cache (node_modules/.cache/draco-models) e
|
|
||||||
// ricalcolati solo quando cambia il sorgente o le opzioni di compressione.
|
|
||||||
import crypto from 'node:crypto';
|
|
||||||
import fs from 'node:fs/promises';
|
|
||||||
import path from 'node:path';
|
|
||||||
import { NodeIO } from '@gltf-transform/core';
|
|
||||||
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
|
|
||||||
import { draco, weld } from '@gltf-transform/functions';
|
|
||||||
import draco3d from 'draco3dgltf';
|
|
||||||
|
|
||||||
// Bit di quantizzazione: valori più alti = più fedeltà e file più grandi.
|
|
||||||
// Le posizioni a 14 bit sono sotto il decimo di millimetro sulle dimensioni di un infisso.
|
|
||||||
const DRACO_OPTIONS = {
|
|
||||||
method: 'edgebreaker',
|
|
||||||
encodeSpeed: 5,
|
|
||||||
decodeSpeed: 5,
|
|
||||||
quantizePosition: 14,
|
|
||||||
quantizeNormal: 10,
|
|
||||||
quantizeTexcoord: 12,
|
|
||||||
quantizeColor: 8,
|
|
||||||
quantizeGeneric: 12,
|
|
||||||
};
|
|
||||||
const CACHE_VERSION = 1;
|
|
||||||
|
|
||||||
async function listGlb(dir, base = dir) {
|
|
||||||
const out = [];
|
|
||||||
for (const entry of await fs.readdir(dir, { withFileTypes: true })) {
|
|
||||||
const full = path.join(dir, entry.name);
|
|
||||||
if (entry.isDirectory()) out.push(...(await listGlb(full, base)));
|
|
||||||
else if (entry.name.toLowerCase().endsWith('.glb')) out.push(path.relative(base, full));
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removePlainGlb(dir) {
|
|
||||||
let entries;
|
|
||||||
try {
|
|
||||||
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
||||||
} catch {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const entry of entries) {
|
|
||||||
const full = path.join(dir, entry.name);
|
|
||||||
if (entry.isDirectory()) await removePlainGlb(full);
|
|
||||||
else if (entry.name.toLowerCase().endsWith('.glb')) await fs.rm(full);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function dracoModels({ modelsDir, cacheDir }) {
|
|
||||||
let outDir;
|
|
||||||
let ioPromise = null;
|
|
||||||
|
|
||||||
const getIO = () =>
|
|
||||||
(ioPromise ??= (async () =>
|
|
||||||
new NodeIO().registerExtensions(ALL_EXTENSIONS).registerDependencies({
|
|
||||||
'draco3d.encoder': await draco3d.createEncoderModule(),
|
|
||||||
'draco3d.decoder': await draco3d.createDecoderModule(),
|
|
||||||
}))());
|
|
||||||
|
|
||||||
async function compress(src) {
|
|
||||||
const io = await getIO();
|
|
||||||
const doc = await io.read(src);
|
|
||||||
// Draco lavora su primitive indicizzate: weld unisce solo i vertici identici in tutti gli
|
|
||||||
// attributi (posizione, normale, uv...), quindi non cambia l'aspetto del modello.
|
|
||||||
await doc.transform(weld(), draco(DRACO_OPTIONS));
|
|
||||||
return Buffer.from(await io.writeBinary(doc));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: 'kreios-draco-models',
|
|
||||||
apply: 'build',
|
|
||||||
|
|
||||||
configResolved(config) {
|
|
||||||
outDir = config.build.outDir;
|
|
||||||
},
|
|
||||||
|
|
||||||
// sequential: parte dopo il writeBundle di vite-plugin-static-copy.
|
|
||||||
writeBundle: {
|
|
||||||
sequential: true,
|
|
||||||
order: 'post',
|
|
||||||
async handler() {
|
|
||||||
// Nessun GLB non compresso deve finire online (es. file archiviati in assets/data).
|
|
||||||
await removePlainGlb(path.join(outDir, 'assets'));
|
|
||||||
await fs.mkdir(cacheDir, { recursive: true });
|
|
||||||
|
|
||||||
const files = await listGlb(modelsDir);
|
|
||||||
let compressed = 0;
|
|
||||||
let before = 0;
|
|
||||||
let after = 0;
|
|
||||||
|
|
||||||
for (const rel of files) {
|
|
||||||
const src = path.join(modelsDir, rel);
|
|
||||||
const data = await fs.readFile(src);
|
|
||||||
const hash = crypto
|
|
||||||
.createHash('sha256')
|
|
||||||
.update(JSON.stringify({ v: CACHE_VERSION, DRACO_OPTIONS }))
|
|
||||||
.update(data)
|
|
||||||
.digest('hex');
|
|
||||||
const cached = path.join(cacheDir, `${hash}.glb`);
|
|
||||||
|
|
||||||
let out = await fs.readFile(cached).catch(() => null);
|
|
||||||
if (!out) {
|
|
||||||
out = await compress(src);
|
|
||||||
await fs.writeFile(cached, out);
|
|
||||||
compressed++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dest = path.join(outDir, 'assets/models', rel);
|
|
||||||
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
||||||
await fs.writeFile(dest, out);
|
|
||||||
before += data.length;
|
|
||||||
after += out.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mb = (n) => (n / 1024 / 1024).toFixed(1);
|
|
||||||
console.log(
|
|
||||||
`[draco-models] ${files.length} modelli (${compressed} ricompressi): ` +
|
|
||||||
`${mb(before)} MB -> ${mb(after)} MB`,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user