diff --git a/bun.lockb b/bun.lockb index 2ca4de527..637adba0d 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index d42defeb8..07d26b755 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "packages/*" ], "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: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", diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 9f51137b4..d5f3d770e 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -9,17 +9,21 @@ "setup:patches": "bun src/applyPatches.ts" }, "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:*", - "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": { "@types/decompress": "^4.2.7", - "@types/progress": "^2.0.7", - "@types/lodash": "^4.17.7" + "@types/draco3dgltf": "^1.4.3", + "@types/lodash": "^4.17.7", + "@types/progress": "^2.0.7" } } diff --git a/packages/scripts/src/buildAssets/tankModels.ts b/packages/scripts/src/buildAssets/tankModels.ts index fcca43f4c..6e0e305f2 100644 --- a/packages/scripts/src/buildAssets/tankModels.ts +++ b/packages/scripts/src/buildAssets/tankModels.ts @@ -1,5 +1,7 @@ import { toUniqueId } from '@blitzkit/core'; import { NodeIO } from '@gltf-transform/core'; +import { ALL_EXTENSIONS } from '@gltf-transform/extensions'; +import draco3d from 'draco3dgltf'; import { readdir } from 'fs/promises'; import { extractModel } from '../core/blitz/extractModel'; import { readXMLDVPL } from '../core/blitz/readXMLDVPL'; @@ -13,7 +15,12 @@ import { TankParameters } from './tankIcons'; export async function tankModels() { 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( (nations) => nations.filter((nation) => nation !== 'common'), ); @@ -32,6 +39,7 @@ export async function tankModels() { if (tankKey.includes('tutorial_bot')) return; const id = toUniqueId(nation, tank.id); + const parameters = await readYAMLDVPL( `${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml.dvpl`, ); diff --git a/packages/scripts/src/core/blitz/extractModel/constants.ts b/packages/scripts/src/core/blitz/extractModel/constants.ts index 159e8c35f..8df11615a 100644 --- a/packages/scripts/src/core/blitz/extractModel/constants.ts +++ b/packages/scripts/src/core/blitz/extractModel/constants.ts @@ -8,9 +8,6 @@ export const vertexAttributeGLTFName: Partial> = [VertexAttribute.TEXCOORD1]: 'TEXCOORD_0', [VertexAttribute.TEXCOORD2]: 'TEXCOORD_0', [VertexAttribute.TEXCOORD3]: 'TEXCOORD_0', - [VertexAttribute.TANGENT]: 'TANGENT', - [VertexAttribute.JOINTINDEX]: 'JOINT_0', - [VertexAttribute.JOINTWEIGHT]: 'WEIGHT_0', }; export const vertexAttributeGltfVectorSizes = { ...vertexAttributeVectorSizes, diff --git a/packages/scripts/src/core/blitz/extractModel/index.ts b/packages/scripts/src/core/blitz/extractModel/index.ts index 64281df2b..10d0e1a6d 100644 --- a/packages/scripts/src/core/blitz/extractModel/index.ts +++ b/packages/scripts/src/core/blitz/extractModel/index.ts @@ -6,6 +6,8 @@ import { VertexAttribute, } from '@blitzkit/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 { dirname } from 'path'; import { Matrix4, Quaternion, Vector3, Vector4Tuple } from 'three'; @@ -223,7 +225,9 @@ export async function extractModel(data: string, path: string) { const primitive = document .createPrimitive() .setIndices(indicesAccessor) - .setMaterial(material); + .setMaterial(material) + .setName(batchKey); + const attributes = new Map(); 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) => { 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 .createAccessor(name) .setType(vertexSize === 1 ? 'SCALAR' : `VEC${vertexSize}`) .setArray(new Float32Array(value.flat())) .setBuffer(buffer); + primitive.setAttribute(name, attributeAccessor); }); @@ -288,5 +290,19 @@ export async function extractModel(data: string, path: string) { 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; } diff --git a/packages/scripts/src/core/blitz/readTexture/index.ts b/packages/scripts/src/core/blitz/readTexture/index.ts index ce3ff9e88..4e0b954b9 100644 --- a/packages/scripts/src/core/blitz/readTexture/index.ts +++ b/packages/scripts/src/core/blitz/readTexture/index.ts @@ -1,9 +1,14 @@ import { DdsReadStream, PvrReadStream } from '@blitzkit/core'; import { existsSync } from 'fs'; -import sharp from 'sharp'; +import sharp, { JpegOptions } from 'sharp'; import { readDVPLFile } from '../readDVPLFile'; import { TextureMutation } from './constants'; +const jpegOptions: JpegOptions = { + quality: 20, + mozjpeg: true, +}; + export async function readTexture(path: string, mutation?: TextureMutation) { const ddsTexturePath = path.replace('.tex', '.dx11.dds.dvpl'); const isDds = existsSync(ddsTexturePath); @@ -35,7 +40,7 @@ export async function readTexture(path: string, mutation?: TextureMutation) { 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: { @@ -44,16 +49,16 @@ export async function readTexture(path: string, mutation?: TextureMutation) { }); const metallicness = sharp(raw.data, { raw }) .extractChannel('green') - .jpeg() + .jpeg(jpegOptions) .toBuffer(); const roughness = sharp(raw.data, { raw }) .extractChannel('alpha') - .jpeg() + .jpeg(jpegOptions) .toBuffer(); return await newImage .joinChannel(await Promise.all([roughness, metallicness])) - .jpeg() + .jpeg(jpegOptions) .toBuffer(); } @@ -64,15 +69,18 @@ export async function readTexture(path: string, mutation?: TextureMutation) { */ return await sharp(raw.data, { raw }) .extractChannel('alpha') - .jpeg() + .jpeg(jpegOptions) .toBuffer(); } case TextureMutation.Albedo: { - return await sharp(raw.data, { raw }).removeAlpha().jpeg().toBuffer(); + return await sharp(raw.data, { raw }) + .removeAlpha() + .jpeg(jpegOptions) + .toBuffer(); } default: - return await sharp(raw.data, { raw }).jpeg().toBuffer(); + return await sharp(raw.data, { raw }).jpeg(jpegOptions).toBuffer(); } } diff --git a/packages/website/src/hooks/useModel.ts b/packages/website/src/hooks/useModel.ts index 190f43161..5ff45b805 100644 --- a/packages/website/src/hooks/useModel.ts +++ b/packages/website/src/hooks/useModel.ts @@ -2,6 +2,7 @@ import { asset } from '@blitzkit/core'; import { type ObjectMap, useLoader } from '@react-three/fiber'; import { Mesh, MeshStandardMaterial } from 'three'; import { type GLTF, GLTFLoader } from 'three-stdlib'; +import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; const cache: Record< number, @@ -12,7 +13,16 @@ const cache: Record< > = {}; 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]) { cache[id] = { gltf,