feat: support transparency

This commit is contained in:
TrèsAbhi committed 2025-10-11 21:22:48 -05:00
1 parent 06a3791ddd
commit 4ab03e56a2
7 files changed
+190 -184

No files matched your search

@@ -31,12 +31,12 @@ export async function tankModels() {
let index = 0;
for (const [tankKey, tank] of entries) {
console.log(` ${++index} / ${entries.length} : ${tankKey}`);
if (tankKey.includes("tutorial_bot")) continue;
const id = toUniqueId(nation, tank.id);
console.log(` ${++index} / ${entries.length} : ${tankKey}`);
const parameters = await readYAMLDVPL<TankParameters>(
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`
);
@@ -39,82 +39,95 @@ export async function extractModel(data: string, path: string) {
const buffer = document.createBuffer();
const materials = new Map<bigint, Material | bigint | undefined>();
// create materials
await Promise.all(
sc2["#dataNodes"].map(async (node) => {
const id = new DataView(node["#id"]).getBigUint64(0, true);
for (const node of sc2["#dataNodes"]) {
const id = new DataView(node["#id"]).getBigUint64(0, true);
if (node.parentMaterialKey !== undefined) {
/**
* material depends on a parent and doesn't seem to have any
* properties so we just point it to the parent
*/
materials.set(id, node.parentMaterialKey);
return;
if (node.parentMaterialKey !== undefined) {
/**
* material depends on a parent and doesn't seem to have any
* properties so we just point it to the parent
*/
materials.set(id, node.parentMaterialKey);
continue;
}
const material = document.createMaterial(node.materialName);
let textures: Textures | undefined = undefined;
if (node.textures) {
textures = node.textures;
} else if (typeof node.configCount === "number") {
textures = node.configArchive_0.textures;
}
if (textures) {
material.setBaseColorTexture(
document
.createTexture(node.materialName)
.setMimeType("image/webp")
.setImage(
await readBaseColor(
`${data}/3d/${dirname(path)}/${textures.baseColorMap ?? textures.albedo}`,
textures.miscMap
? `${data}/3d/${dirname(path)}/${textures.miscMap}`
: undefined
)
)
);
if (node.configCount) {
for (
let configIndex = 0;
configIndex < node.configCount;
configIndex++
) {
const archive = node[`configArchive_${configIndex}`];
if (
archive.configName !== "Default" ||
!archive.enabledPresets?.AlphaTest
) {
continue;
}
material.setAlphaMode("BLEND").setDoubleSided(true);
}
}
const material = document.createMaterial(node.materialName);
let textures: Textures | undefined = undefined;
if (node.textures) {
textures = node.textures;
} else if (typeof node.configCount === "number") {
textures = node.configArchive_0.textures;
}
if (textures) {
material.setBaseColorTexture(
if (textures.baseRMMap) {
material.setMetallicRoughnessTexture(
document
.createTexture(node.materialName)
.setMimeType("image/jpeg")
.setMimeType("image/webp")
.setImage(
await readBaseColor(
`${data}/3d/${dirname(path)}/${textures.baseColorMap ?? textures.albedo}`,
textures.miscMap
? `${data}/3d/${dirname(path)}/${textures.miscMap}`
: undefined
await readRoughnessMetallic(
`${data}/3d/${dirname(path)}/${textures.baseRMMap}`
)
)
);
}
if (textures.baseRMMap) {
material.setMetallicRoughnessTexture(
document
.createTexture(node.materialName)
.setMimeType("image/jpeg")
.setImage(
await readRoughnessMetallic(
`${data}/3d/${dirname(path)}/${textures.baseRMMap}`
)
if (textures.baseNormalMap ?? textures.normalmap) {
const isBase = textures.baseNormalMap !== undefined;
material.setNormalTexture(
document
.createTexture(node.materialName)
.setMimeType("image/webp")
.setImage(
await readNormal(
`${data}/3d/${dirname(path)}/${
textures.baseNormalMap ?? textures.normalmap
}`,
isBase
)
);
}
if (textures.baseNormalMap ?? textures.normalmap) {
const isBase = textures.baseNormalMap !== undefined;
material.setNormalTexture(
document
.createTexture(node.materialName)
.setMimeType("image/jpeg")
.setImage(
await readNormal(
`${data}/3d/${dirname(path)}/${
textures.baseNormalMap ?? textures.normalmap
}`,
isBase
)
)
);
}
materials.set(
new DataView(node["#id"]).getBigUint64(0, true),
material
)
);
}
})
);
materials.set(new DataView(node["#id"]).getBigUint64(0, true), material);
}
}
// replace children materials with parents
materials.forEach((material, id) => {
@@ -6,10 +6,7 @@ export async function readBaseColor(path: string, occlusionPath?: string) {
const occlusionRaw = occlusionPath
? await readTexture(occlusionPath)
: undefined;
const base = await sharp(baseRaw.data, { raw: baseRaw })
.removeAlpha()
.raw()
.toBuffer();
const base = await sharp(baseRaw.data, { raw: baseRaw }).raw().toBuffer();
const occlusion = occlusionRaw
? await sharp(occlusionRaw.data, { raw: occlusionRaw })
.extractChannel(3)
@@ -17,7 +14,7 @@ export async function readBaseColor(path: string, occlusionPath?: string) {
.toBuffer()
: undefined;
const combined = Buffer.alloc(baseRaw.width * baseRaw.height * 3);
const combined = Buffer.alloc(baseRaw.width * baseRaw.height * 4);
for (let i = 0; i < baseRaw.width * baseRaw.height; i++) {
let c = 1;
@@ -33,15 +30,16 @@ export async function readBaseColor(path: string, occlusionPath?: string) {
c = occlusion![occlusionI] / 255;
}
combined[i * 3 + 0] = Math.round(base[i * 3 + 0] * c);
combined[i * 3 + 1] = Math.round(base[i * 3 + 1] * c);
combined[i * 3 + 2] = Math.round(base[i * 3 + 2] * c);
combined[i * 4 + 0] = Math.round(base[i * 4 + 0] * c);
combined[i * 4 + 1] = Math.round(base[i * 4 + 1] * c);
combined[i * 4 + 2] = Math.round(base[i * 4 + 2] * c);
combined[i * 4 + 3] = base[i * 4 + 3];
}
const image = await sharp(combined, {
raw: { width: baseRaw.width, height: baseRaw.height, channels: 3 },
raw: { width: baseRaw.width, height: baseRaw.height, channels: 4 },
})
.jpeg()
.webp()
.toBuffer();
return image;
@@ -25,5 +25,5 @@ export async function readNormal(path: string, isBase: boolean) {
raw.data[index + 3] = 255;
}
return await sharp(raw.data, { raw }).jpeg().toBuffer();
return await sharp(raw.data, { raw }).webp().toBuffer();
}
@@ -17,7 +17,7 @@ export async function readRoughnessMetallic(path: string) {
const image = await sharp(combined, {
raw: { width: raw.width, height: raw.height, channels: 3 },
})
.jpeg()
.webp()
.toBuffer();
return image;