feat: faster models

This commit is contained in:
TrèsAbhi committed 2024-10-29 16:21:44 -05:00
1 parent 0f29145ab0
commit e05f02099d
8 files changed
+77 -34

No files matched your search

BIN
View File
Binary file not shown.
+1 -1
View File
@@ -9,7 +9,7 @@
"packages/*" "packages/*"
], ],
"scripts": { "scripts": {
"build:assets": "bun --filter=@blitzkit/scripts run build:assets", "build:assets": "cd packages/scripts && bun run build:assets",
"build:averages": "bun --filter=@blitzkit/scripts run build:averages", "build:averages": "bun --filter=@blitzkit/scripts run build:averages",
"build:bot": "rm -rf dist/bot && mkdir -p dist/bot/prisma && bun build src/index.ts src/workers/bot.ts src/workers/render.ts --outdir dist/bot --target=bun --splitting --sourcemap=inline --external sharp && cp -R src/lang dist/bot/lang && prisma generate && cp prisma/schema.prisma dist/bot/prisma/schema.prisma && cp -R node_modules/prisma/*.node dist/bot/prisma && cd dist/bot && bun init -y && bun add sharp", "build:bot": "rm -rf dist/bot && mkdir -p dist/bot/prisma && bun build src/index.ts src/workers/bot.ts src/workers/render.ts --outdir dist/bot --target=bun --splitting --sourcemap=inline --external sharp && cp -R src/lang dist/bot/lang && prisma generate && cp prisma/schema.prisma dist/bot/prisma/schema.prisma && cp -R node_modules/prisma/*.node dist/bot/prisma && cd dist/bot && bun init -y && bun add sharp",
"build:website": "bun build:prisma && bun --filter=@blitzkit/website run build", "build:website": "bun build:prisma && bun --filter=@blitzkit/website run build",
+12 -8
View File
@@ -9,17 +9,21 @@
"setup:patches": "bun src/applyPatches.ts" "setup:patches": "bun src/applyPatches.ts"
}, },
"dependencies": { "dependencies": {
"progress": "^2.0.3",
"@gltf-transform/core": "^3.10.1",
"decompress": "^4.2.1",
"csv-parse": "^5.5.6",
"googleapis": "^134.0.0",
"@blitzkit/core": "workspace:*", "@blitzkit/core": "workspace:*",
"fast-xml-parser": "^4.4.1" "@gltf-transform/core": "^4.0.10",
"@gltf-transform/extensions": "^4.0.10",
"@gltf-transform/functions": "^4.0.10",
"csv-parse": "^5.5.6",
"decompress": "^4.2.1",
"draco3dgltf": "^1.5.7",
"fast-xml-parser": "^4.4.1",
"googleapis": "^134.0.0",
"progress": "^2.0.3"
}, },
"devDependencies": { "devDependencies": {
"@types/decompress": "^4.2.7", "@types/decompress": "^4.2.7",
"@types/progress": "^2.0.7", "@types/draco3dgltf": "^1.4.3",
"@types/lodash": "^4.17.7" "@types/lodash": "^4.17.7",
"@types/progress": "^2.0.7"
} }
} }
@@ -1,5 +1,7 @@
import { toUniqueId } from '@blitzkit/core'; import { toUniqueId } from '@blitzkit/core';
import { NodeIO } from '@gltf-transform/core'; import { NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import draco3d from 'draco3dgltf';
import { readdir } from 'fs/promises'; import { readdir } from 'fs/promises';
import { extractModel } from '../core/blitz/extractModel'; import { extractModel } from '../core/blitz/extractModel';
import { readXMLDVPL } from '../core/blitz/readXMLDVPL'; import { readXMLDVPL } from '../core/blitz/readXMLDVPL';
@@ -13,7 +15,12 @@ import { TankParameters } from './tankIcons';
export async function tankModels() { export async function tankModels() {
console.log('Building tank models...'); console.log('Building tank models...');
const nodeIO = new NodeIO(); const nodeIO = new NodeIO()
.registerExtensions(ALL_EXTENSIONS)
.registerDependencies({
'draco3d.decoder': await draco3d.createDecoderModule(),
'draco3d.encoder': await draco3d.createEncoderModule(),
});
const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then( const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then(
(nations) => nations.filter((nation) => nation !== 'common'), (nations) => nations.filter((nation) => nation !== 'common'),
); );
@@ -32,6 +39,7 @@ export async function tankModels() {
if (tankKey.includes('tutorial_bot')) return; if (tankKey.includes('tutorial_bot')) return;
const id = toUniqueId(nation, tank.id); const id = toUniqueId(nation, tank.id);
const parameters = await readYAMLDVPL<TankParameters>( const parameters = await readYAMLDVPL<TankParameters>(
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml.dvpl`, `${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml.dvpl`,
); );
@@ -8,9 +8,6 @@ export const vertexAttributeGLTFName: Partial<Record<VertexAttribute, string>> =
[VertexAttribute.TEXCOORD1]: 'TEXCOORD_0', [VertexAttribute.TEXCOORD1]: 'TEXCOORD_0',
[VertexAttribute.TEXCOORD2]: 'TEXCOORD_0', [VertexAttribute.TEXCOORD2]: 'TEXCOORD_0',
[VertexAttribute.TEXCOORD3]: 'TEXCOORD_0', [VertexAttribute.TEXCOORD3]: 'TEXCOORD_0',
[VertexAttribute.TANGENT]: 'TANGENT',
[VertexAttribute.JOINTINDEX]: 'JOINT_0',
[VertexAttribute.JOINTWEIGHT]: 'WEIGHT_0',
}; };
export const vertexAttributeGltfVectorSizes = { export const vertexAttributeGltfVectorSizes = {
...vertexAttributeVectorSizes, ...vertexAttributeVectorSizes,
@@ -6,6 +6,8 @@ import {
VertexAttribute, VertexAttribute,
} from '@blitzkit/core'; } from '@blitzkit/core';
import { Document, Material, Node, Scene } from '@gltf-transform/core'; import { Document, Material, Node, Scene } from '@gltf-transform/core';
import { KHRDracoMeshCompression } from '@gltf-transform/extensions';
import { dedup, prune } from '@gltf-transform/functions';
import { times } from 'lodash-es'; import { times } from 'lodash-es';
import { dirname } from 'path'; import { dirname } from 'path';
import { Matrix4, Quaternion, Vector3, Vector4Tuple } from 'three'; import { Matrix4, Quaternion, Vector3, Vector4Tuple } from 'three';
@@ -223,7 +225,9 @@ export async function extractModel(data: string, path: string) {
const primitive = document const primitive = document
.createPrimitive() .createPrimitive()
.setIndices(indicesAccessor) .setIndices(indicesAccessor)
.setMaterial(material); .setMaterial(material)
.setName(batchKey);
const attributes = new Map<VertexAttribute, number[][]>(); const attributes = new Map<VertexAttribute, number[][]>();
polygonGroup.vertices.forEach((vertex) => { polygonGroup.vertices.forEach((vertex) => {
@@ -236,25 +240,23 @@ export async function extractModel(data: string, path: string) {
}); });
}); });
if (attributes.has(VertexAttribute.TANGENT)) {
attributes.set(
VertexAttribute.TANGENT,
attributes
.get(VertexAttribute.TANGENT)!
.map((tangent) => [...tangent, 1]),
);
}
attributes.forEach((value, attribute) => { attributes.forEach((value, attribute) => {
const name = vertexAttributeGLTFName[attribute]; const name = vertexAttributeGLTFName[attribute];
if (!name || primitive.getAttribute(name)) return;
const vertexSize = vertexAttributeGltfVectorSizes[attribute];
if (
name === undefined ||
primitive.getAttribute(name) !== null
) {
return;
}
const vertexSize = vertexAttributeGltfVectorSizes[attribute];
const attributeAccessor = document const attributeAccessor = document
.createAccessor(name) .createAccessor(name)
.setType(vertexSize === 1 ? 'SCALAR' : `VEC${vertexSize}`) .setType(vertexSize === 1 ? 'SCALAR' : `VEC${vertexSize}`)
.setArray(new Float32Array(value.flat())) .setArray(new Float32Array(value.flat()))
.setBuffer(buffer); .setBuffer(buffer);
primitive.setAttribute(name, attributeAccessor); primitive.setAttribute(name, attributeAccessor);
}); });
@@ -288,5 +290,19 @@ export async function extractModel(data: string, path: string) {
parseHierarchies(sc2['#hierarchy'], scene); parseHierarchies(sc2['#hierarchy'], scene);
scene.addChild(document.createNode('test'));
await document.transform(prune({ keepAttributes: true }), dedup());
document
.createExtension(KHRDracoMeshCompression)
.setRequired(true)
.setEncoderOptions({
method: KHRDracoMeshCompression.EncoderMethod.EDGEBREAKER,
encodeSpeed: 0,
decodeSpeed: 0,
quantizationVolume: 'scene',
});
return document; return document;
} }
@@ -1,9 +1,14 @@
import { DdsReadStream, PvrReadStream } from '@blitzkit/core'; import { DdsReadStream, PvrReadStream } from '@blitzkit/core';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import sharp from 'sharp'; import sharp, { JpegOptions } from 'sharp';
import { readDVPLFile } from '../readDVPLFile'; import { readDVPLFile } from '../readDVPLFile';
import { TextureMutation } from './constants'; import { TextureMutation } from './constants';
const jpegOptions: JpegOptions = {
quality: 20,
mozjpeg: true,
};
export async function readTexture(path: string, mutation?: TextureMutation) { export async function readTexture(path: string, mutation?: TextureMutation) {
const ddsTexturePath = path.replace('.tex', '.dx11.dds.dvpl'); const ddsTexturePath = path.replace('.tex', '.dx11.dds.dvpl');
const isDds = existsSync(ddsTexturePath); const isDds = existsSync(ddsTexturePath);
@@ -35,7 +40,7 @@ export async function readTexture(path: string, mutation?: TextureMutation) {
raw.data[index + 3] = 255; raw.data[index + 3] = 255;
} }
return await sharp(raw.data, { raw }).jpeg().toBuffer(); return await sharp(raw.data, { raw }).jpeg(jpegOptions).toBuffer();
} }
case TextureMutation.RoughnessMetallicness: { case TextureMutation.RoughnessMetallicness: {
@@ -44,16 +49,16 @@ export async function readTexture(path: string, mutation?: TextureMutation) {
}); });
const metallicness = sharp(raw.data, { raw }) const metallicness = sharp(raw.data, { raw })
.extractChannel('green') .extractChannel('green')
.jpeg() .jpeg(jpegOptions)
.toBuffer(); .toBuffer();
const roughness = sharp(raw.data, { raw }) const roughness = sharp(raw.data, { raw })
.extractChannel('alpha') .extractChannel('alpha')
.jpeg() .jpeg(jpegOptions)
.toBuffer(); .toBuffer();
return await newImage return await newImage
.joinChannel(await Promise.all([roughness, metallicness])) .joinChannel(await Promise.all([roughness, metallicness]))
.jpeg() .jpeg(jpegOptions)
.toBuffer(); .toBuffer();
} }
@@ -64,15 +69,18 @@ export async function readTexture(path: string, mutation?: TextureMutation) {
*/ */
return await sharp(raw.data, { raw }) return await sharp(raw.data, { raw })
.extractChannel('alpha') .extractChannel('alpha')
.jpeg() .jpeg(jpegOptions)
.toBuffer(); .toBuffer();
} }
case TextureMutation.Albedo: { case TextureMutation.Albedo: {
return await sharp(raw.data, { raw }).removeAlpha().jpeg().toBuffer(); return await sharp(raw.data, { raw })
.removeAlpha()
.jpeg(jpegOptions)
.toBuffer();
} }
default: default:
return await sharp(raw.data, { raw }).jpeg().toBuffer(); return await sharp(raw.data, { raw }).jpeg(jpegOptions).toBuffer();
} }
} }
+11 -1
View File
@@ -2,6 +2,7 @@ import { asset } from '@blitzkit/core';
import { type ObjectMap, useLoader } from '@react-three/fiber'; import { type ObjectMap, useLoader } from '@react-three/fiber';
import { Mesh, MeshStandardMaterial } from 'three'; import { Mesh, MeshStandardMaterial } from 'three';
import { type GLTF, GLTFLoader } from 'three-stdlib'; import { type GLTF, GLTFLoader } from 'three-stdlib';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
const cache: Record< const cache: Record<
number, number,
@@ -12,7 +13,16 @@ const cache: Record<
> = {}; > = {};
export function useModel(id: number) { export function useModel(id: number) {
const gltf = useLoader(GLTFLoader, asset(`3d/tanks/models/${id}.glb`)); const gltf = useLoader(
GLTFLoader,
asset(`3d/tanks/models/${id}.glb`),
(loader) => {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');
loader.setDRACOLoader(dracoLoader);
},
);
if (!cache[id]) { if (!cache[id]) {
cache[id] = { cache[id] = {
gltf, gltf,