From 335cd4d699559f3036a8d37af2c6b079a2a5ca58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 5 Sep 2025 23:34:59 -0500 Subject: [PATCH] feat: rewrite some systems --- .../scripts/src/buildAssets/tankModels.ts | 18 ++- .../src/core/blitz/extractModel/constants.ts | 14 +- .../src/core/blitz/extractModel/index.ts | 51 +++---- .../scripts/src/core/blitz/readBaseColor.ts | 7 + packages/scripts/src/core/blitz/readNormal.ts | 30 +++++ .../scripts/src/core/blitz/readOcclusion.ts | 25 ++++ .../src/core/blitz/readRoughnessMetallic.ts | 27 ++++ .../src/core/blitz/readTexture/index.ts | 126 +++++++++--------- .../TankSandbox/components/Lighting.tsx | 2 +- .../TankSandbox/components/TankModel.tsx | 7 + packages/website/src/hooks/useModel.ts | 12 +- 11 files changed, 212 insertions(+), 107 deletions(-) create mode 100644 packages/scripts/src/core/blitz/readBaseColor.ts create mode 100644 packages/scripts/src/core/blitz/readNormal.ts create mode 100644 packages/scripts/src/core/blitz/readOcclusion.ts create mode 100644 packages/scripts/src/core/blitz/readRoughnessMetallic.ts diff --git a/packages/scripts/src/buildAssets/tankModels.ts b/packages/scripts/src/buildAssets/tankModels.ts index 736478db7..851088f97 100644 --- a/packages/scripts/src/buildAssets/tankModels.ts +++ b/packages/scripts/src/buildAssets/tankModels.ts @@ -1,11 +1,10 @@ import { toUniqueId } from "@blitzkit/core"; import { NodeIO } from "@gltf-transform/core"; import { ALL_EXTENSIONS } from "@gltf-transform/extensions"; -import { readdir } from "fs/promises"; +import { readdir, writeFile } from "fs/promises"; import { extractModel } from "../core/blitz/extractModel"; import { readXMLDVPL } from "../core/blitz/readXMLDVPL"; import { readYAMLDVPL } from "../core/blitz/readYAMLDVPL"; -import { commitAssets } from "../core/github/commitAssets"; import { FileChange } from "../core/github/commitMultipleFiles"; import { DATA } from "./constants"; import { VehicleDefinitionList } from "./definitions"; @@ -37,6 +36,8 @@ export async function tankModels() { const id = toUniqueId(nation, tank.id); + if (id !== 5681) continue; + const parameters = await readYAMLDVPL( `${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml` ); @@ -44,13 +45,16 @@ export async function tankModels() { DATA, parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, "") ); + const content = Buffer.from(await nodeIO.writeBinary(model)); - changes.push({ - path: `3d/tanks/models/${id}.glb`, - content: Buffer.from(await nodeIO.writeBinary(model)), - }); + changes.push({ path: `3d/tanks/models/${id}.glb`, content }); + + await writeFile( + "C:/Projects/blitzkit/packages/website/public/test.glb", + content + ); } - await commitAssets(`tank models ${nation}`, changes); + // await commitAssets(`tank models ${nation}`, changes); } } diff --git a/packages/scripts/src/core/blitz/extractModel/constants.ts b/packages/scripts/src/core/blitz/extractModel/constants.ts index 8df11615a..07775a4d2 100644 --- a/packages/scripts/src/core/blitz/extractModel/constants.ts +++ b/packages/scripts/src/core/blitz/extractModel/constants.ts @@ -1,13 +1,13 @@ -import { VertexAttribute, vertexAttributeVectorSizes } from '@blitzkit/core'; +import { VertexAttribute, vertexAttributeVectorSizes } from "@blitzkit/core"; export const vertexAttributeGLTFName: Partial> = { - [VertexAttribute.VERTEX]: 'POSITION', - [VertexAttribute.NORMAL]: 'NORMAL', - [VertexAttribute.TEXCOORD0]: 'TEXCOORD_0', - [VertexAttribute.TEXCOORD1]: 'TEXCOORD_0', - [VertexAttribute.TEXCOORD2]: 'TEXCOORD_0', - [VertexAttribute.TEXCOORD3]: 'TEXCOORD_0', + [VertexAttribute.VERTEX]: "POSITION", + [VertexAttribute.NORMAL]: "NORMAL", + [VertexAttribute.TEXCOORD0]: "TEXCOORD_0", + [VertexAttribute.TEXCOORD1]: "TEXCOORD_1", + [VertexAttribute.TEXCOORD2]: "TEXCOORD_2", + [VertexAttribute.TEXCOORD3]: "TEXCOORD_3", }; 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 9d33865de..c77dccb2c 100644 --- a/packages/scripts/src/core/blitz/extractModel/index.ts +++ b/packages/scripts/src/core/blitz/extractModel/index.ts @@ -9,9 +9,11 @@ import { Document, Material, Node, Scene } from "@gltf-transform/core"; import { dedup, prune } from "@gltf-transform/functions"; import { times } from "lodash-es"; import { dirname } from "path"; +import { readBaseColor } from "../readBaseColor"; import { readDVPLFile } from "../readDVPLFile"; -import { readTexture } from "../readTexture"; -import { TextureMutation } from "../readTexture/constants"; +import { readNormal } from "../readNormal"; +import { readOcclusion } from "../readOcclusion"; +import { readRoughnessMetallic } from "../readRoughnessMetallic"; import { vertexAttributeGLTFName, vertexAttributeGltfVectorSizes, @@ -67,9 +69,8 @@ export async function extractModel(data: string, path: string) { .createTexture(node.materialName) .setMimeType("image/jpeg") .setImage( - await readTexture( - `${data}/3d/${dirname(path)}/${textures.baseColorMap ?? textures.albedo}`, - TextureMutation.Albedo + await readBaseColor( + `${data}/3d/${dirname(path)}/${textures.baseColorMap ?? textures.albedo}` ) ) ); @@ -80,9 +81,21 @@ export async function extractModel(data: string, path: string) { .createTexture(node.materialName) .setMimeType("image/jpeg") .setImage( - await readTexture( - `${data}/3d/${dirname(path)}/${textures.baseRMMap}`, - TextureMutation.RoughnessMetallicness + await readRoughnessMetallic( + `${data}/3d/${dirname(path)}/${textures.baseRMMap}` + ) + ) + ); + } + + if (textures.miscMap) { + material.setOcclusionTexture( + document + .createTexture(node.materialName) + .setMimeType("image/jpeg") + .setImage( + await readOcclusion( + `${data}/3d/${dirname(path)}/${textures.miscMap}` ) ) ); @@ -96,25 +109,11 @@ export async function extractModel(data: string, path: string) { .createTexture(node.materialName) .setMimeType("image/jpeg") .setImage( - await readTexture( + await readNormal( `${data}/3d/${dirname(path)}/${ textures.baseNormalMap ?? textures.normalmap }`, - isBase ? TextureMutation.Normal : undefined - ) - ) - ); - } - - if (textures.miscMap) { - material.setOcclusionTexture( - document - .createTexture(node.materialName) - .setMimeType("image/jpeg") - .setImage( - await readTexture( - `${data}/3d/${dirname(path)}/${textures.miscMap}`, - TextureMutation.Miscellaneous + isBase ) ) ); @@ -237,6 +236,10 @@ export async function extractModel(data: string, path: string) { .setBuffer(buffer); primitive.setAttribute(name, attributeAccessor); + + if (attribute === VertexAttribute.TEXCOORD0) { + primitive.setAttribute("TEXCOORD_2", attributeAccessor); + } }); const mesh = document diff --git a/packages/scripts/src/core/blitz/readBaseColor.ts b/packages/scripts/src/core/blitz/readBaseColor.ts new file mode 100644 index 000000000..0a9f58813 --- /dev/null +++ b/packages/scripts/src/core/blitz/readBaseColor.ts @@ -0,0 +1,7 @@ +import sharp from "sharp"; +import { readTexture } from "./readTexture"; + +export async function readBaseColor(path: string) { + const raw = await readTexture(path); + return await sharp(raw.data, { raw }).removeAlpha().jpeg().toBuffer(); +} diff --git a/packages/scripts/src/core/blitz/readNormal.ts b/packages/scripts/src/core/blitz/readNormal.ts new file mode 100644 index 000000000..704433540 --- /dev/null +++ b/packages/scripts/src/core/blitz/readNormal.ts @@ -0,0 +1,30 @@ +import sharp from "sharp"; +import { readTexture } from "./readTexture"; + +export async function readNormal(path: string, isBase: boolean) { + const raw = await readTexture(path); + + if (!isBase) { + return await sharp(raw.data, { raw }).removeAlpha().jpeg().toBuffer(); + } + + const bytes = 4 * raw.width * raw.height; + + for (let index = 0; index < bytes; index += 4) { + /** + * Red is always 255 and blue is always 0. Only alpha and green contain any + * sort of information. + */ + let x = raw.data[index + 3] * (2 / 255) - 1; + let y = raw.data[index + 1] * (2 / 255) - 1; + const underSqrt = 1 - x ** 2 - y ** 2; + let z = underSqrt > 0 ? Math.sqrt(underSqrt) : -Math.sqrt(-underSqrt); + + raw.data[index] = Math.round((x + 1) * (255 / 2)); + raw.data[index + 1] = Math.round((y + 1) * (255 / 2)); + raw.data[index + 2] = Math.round((z + 1) * (255 / 2)); + raw.data[index + 3] = 255; + } + + return await sharp(raw.data, { raw }).jpeg().toBuffer(); +} diff --git a/packages/scripts/src/core/blitz/readOcclusion.ts b/packages/scripts/src/core/blitz/readOcclusion.ts new file mode 100644 index 000000000..633fda7f5 --- /dev/null +++ b/packages/scripts/src/core/blitz/readOcclusion.ts @@ -0,0 +1,25 @@ +import { writeFile } from "fs/promises"; +import sharp from "sharp"; +import { readTexture } from "./readTexture"; + +export async function readOcclusion(path: string) { + const raw = await readTexture(path); + const blitz = sharp(raw.data, { raw: raw }); + const occlusion = await blitz?.extractChannel(3).raw().toBuffer(); + + const combined = Buffer.alloc(raw.width * raw.height * 3); + + for (let i = 0; i < raw.width * raw.height; i++) { + combined[i * 3 + 0] = occlusion?.[i] ?? 0; + } + + const image = await sharp(combined, { + raw: { width: raw.width, height: raw.height, channels: 3 }, + }) + .jpeg() + .toBuffer(); + + writeFile("test.ao.jpg", image); + + return image; +} diff --git a/packages/scripts/src/core/blitz/readRoughnessMetallic.ts b/packages/scripts/src/core/blitz/readRoughnessMetallic.ts new file mode 100644 index 000000000..1b067ac61 --- /dev/null +++ b/packages/scripts/src/core/blitz/readRoughnessMetallic.ts @@ -0,0 +1,27 @@ +import { writeFile } from "fs/promises"; +import sharp from "sharp"; +import { readTexture } from "./readTexture"; + +export async function readRoughnessMetallic(path: string) { + const raw = await readTexture(path); + const blitz = sharp(raw.data, { raw: raw }); + const metallicness = await blitz?.extractChannel(1).raw().toBuffer(); + const roughness = await blitz?.extractChannel(3).raw().toBuffer(); + + const combined = Buffer.alloc(raw.width * raw.height * 3); + + for (let i = 0; i < raw.width * raw.height; i++) { + combined[i * 3 + 1] = roughness?.[i] ?? 0; + combined[i * 3 + 2] = metallicness?.[i] ?? 0; + } + + const image = await sharp(combined, { + raw: { width: raw.width, height: raw.height, channels: 3 }, + }) + .jpeg() + .toBuffer(); + + writeFile("test.rm.jpg", image); + + return image; +} diff --git a/packages/scripts/src/core/blitz/readTexture/index.ts b/packages/scripts/src/core/blitz/readTexture/index.ts index 73b2495c6..708abee4f 100644 --- a/packages/scripts/src/core/blitz/readTexture/index.ts +++ b/packages/scripts/src/core/blitz/readTexture/index.ts @@ -1,81 +1,83 @@ -import { DdsReadStream, PvrReadStream } from '@blitzkit/core'; -import { existsSync } from 'fs'; -import sharp from 'sharp'; -import { DATA_COMPRESSED } from '../../../buildAssets/constants'; -import { readDVPLFile } from '../readDVPLFile'; -import { TextureMutation } from './constants'; +import { DdsReadStream, PvrReadStream } from "@blitzkit/core"; +import { existsSync } from "fs"; +import sharp from "sharp"; +import { DATA_COMPRESSED } from "../../../buildAssets/constants"; +import { readDVPLFile } from "../readDVPLFile"; +import { TextureMutation } from "./constants"; -export async function readTexture(path: string, mutation?: TextureMutation) { - const ddsTexturePath = path.replace('.tex', '.dx11.dds'); +export async function readTexture(path: string) { + const ddsTexturePath = path.replace(".tex", ".dx11.dds"); const isDds = existsSync( - `${ddsTexturePath}${DATA_COMPRESSED ? '.dvpl' : ''}`, + `${ddsTexturePath}${DATA_COMPRESSED ? ".dvpl" : ""}` ); const resolvedTexturePath = isDds ? ddsTexturePath - : ddsTexturePath.replace('.dds', '.pvr'); + : ddsTexturePath.replace(".dds", ".pvr"); const decompressedDvpl = await readDVPLFile(`${resolvedTexturePath}.dvpl`); const raw = isDds ? await new DdsReadStream(decompressedDvpl.buffer as ArrayBuffer).dds() : new PvrReadStream(decompressedDvpl.buffer as ArrayBuffer).pvr(); - switch (mutation) { - case TextureMutation.Normal: { - const bytes = 4 * raw.width * raw.height; - for (let index = 0; index < bytes; index += 4) { - /** - * Red is always 255 and blue is always 0. Only alpha and green contain any - * sort of information. - */ - let x = raw.data[index + 3] * (2 / 255) - 1; - let y = raw.data[index + 1] * (2 / 255) - 1; - const underSqrt = 1 - x ** 2 - y ** 2; - let z = underSqrt > 0 ? Math.sqrt(underSqrt) : -Math.sqrt(-underSqrt); + return raw; - raw.data[index] = Math.round((x + 1) * (255 / 2)); - raw.data[index + 1] = Math.round((y + 1) * (255 / 2)); - raw.data[index + 2] = Math.round((z + 1) * (255 / 2)); - raw.data[index + 3] = 255; - } + // switch (mutation) { + // case TextureMutation.Normal: { + // const bytes = 4 * raw.width * raw.height; + // for (let index = 0; index < bytes; index += 4) { + // /** + // * Red is always 255 and blue is always 0. Only alpha and green contain any + // * sort of information. + // */ + // let x = raw.data[index + 3] * (2 / 255) - 1; + // let y = raw.data[index + 1] * (2 / 255) - 1; + // const underSqrt = 1 - x ** 2 - y ** 2; + // let z = underSqrt > 0 ? Math.sqrt(underSqrt) : -Math.sqrt(-underSqrt); - return await sharp(raw.data, { raw }).jpeg().toBuffer(); - } + // raw.data[index] = Math.round((x + 1) * (255 / 2)); + // raw.data[index + 1] = Math.round((y + 1) * (255 / 2)); + // raw.data[index + 2] = Math.round((z + 1) * (255 / 2)); + // raw.data[index + 3] = 255; + // } - case TextureMutation.RoughnessMetallicness: { - const newImage = sharp(Buffer.alloc(raw.width * raw.height), { - raw: { ...raw, channels: 1 }, - }); - const metallicness = sharp(raw.data, { raw }) - .extractChannel('green') - .jpeg() - .toBuffer(); - const roughness = sharp(raw.data, { raw }) - .extractChannel('alpha') - .jpeg() - .toBuffer(); + // return await sharp(raw.data, { raw }).jpeg().toBuffer(); + // } - return await newImage - .joinChannel(await Promise.all([roughness, metallicness])) - .jpeg() - .toBuffer(); - } + // case TextureMutation.RoughnessMetallicness: { + // const newImage = sharp(Buffer.alloc(raw.width * raw.height), { + // raw: { ...raw, channels: 1 }, + // }); + // const metallicness = sharp(raw.data, { raw }) + // .extractChannel("green") + // .jpeg() + // .toBuffer(); + // const roughness = sharp(raw.data, { raw }) + // .extractChannel("alpha") + // .jpeg() + // .toBuffer(); - case TextureMutation.Miscellaneous: { - /** - * Alpha is ambient occlusion and green is emissive. But very few tanks - * use emissive so I am ignoring it for now. - */ - return await sharp(raw.data, { raw }) - .extractChannel('alpha') - .jpeg() - .toBuffer(); - } + // return await newImage + // .joinChannel(await Promise.all([roughness, metallicness])) + // .jpeg() + // .toBuffer(); + // } - case TextureMutation.Albedo: { - return await sharp(raw.data, { raw }).removeAlpha().jpeg().toBuffer(); - } + // case TextureMutation.Miscellaneous: { + // /** + // * Alpha is ambient occlusion and green is emissive. But very few tanks + // * use emissive so I am ignoring it for now. + // */ + // return await sharp(raw.data, { raw }) + // .extractChannel("alpha") + // .jpeg() + // .toBuffer(); + // } - default: - return await sharp(raw.data, { raw }).jpeg().toBuffer(); - } + // case TextureMutation.Albedo: { + // return await sharp(raw.data, { raw }).removeAlpha().jpeg().toBuffer(); + // } + + // default: + // return await sharp(raw.data, { raw }).jpeg().toBuffer(); + // } } diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx index 18ad45213..f439df237 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx @@ -64,7 +64,7 @@ export function Lighting() { position={position} intensity={INTENSITY} penumbra={1} - castShadow={cast} + // castShadow={cast} decay={1} color={color} /> diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx index 2e5a066dc..e2a00cc5a 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx @@ -28,6 +28,13 @@ export function TankModel() { const { gltf } = useModel(protagonist.tank.id); const nodes = Object.values(gltf.nodes); + nodes.forEach((n) => { + if (n instanceof Mesh && n.material instanceof MeshStandardMaterial) { + n.material.aoMapIntensity = 10; + console.log(n.geometry.attributes); + } + }); + useTankTransform(track, turret, turretContainer, gunContainer); return ( diff --git a/packages/website/src/hooks/useModel.ts b/packages/website/src/hooks/useModel.ts index 525cb051a..6621a46ce 100644 --- a/packages/website/src/hooks/useModel.ts +++ b/packages/website/src/hooks/useModel.ts @@ -1,7 +1,6 @@ -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 { type ObjectMap, useLoader } from "@react-three/fiber"; +import { Mesh, MeshStandardMaterial } from "three"; +import { type GLTF, GLTFLoader } from "three-stdlib"; const cache: Record< number, @@ -12,7 +11,8 @@ 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`)); + const gltf = useLoader(GLTFLoader, `/test.glb`); if (!cache[id]) { cache[id] = { @@ -21,7 +21,7 @@ export function useModel(id: number) { (node) => node instanceof Mesh && node.material instanceof MeshStandardMaterial && - node.material.roughnessMap !== null, + node.material.roughnessMap !== null ), }; }