mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: lod distance based model loading
This commit is contained in:
1 parent
9a8c0399be
commit
99fb44633e
3 files changed
+54
-31
No files matched your search
Vendored
+2
@@ -36,6 +36,8 @@
|
|||||||
"krieg",
|
"krieg",
|
||||||
"Leaderboard",
|
"Leaderboard",
|
||||||
"leaderboards",
|
"leaderboards",
|
||||||
|
"loddist",
|
||||||
|
"lods",
|
||||||
"metallicness",
|
"metallicness",
|
||||||
"MURICA",
|
"MURICA",
|
||||||
"nmatname",
|
"nmatname",
|
||||||
|
|||||||
@@ -518,7 +518,7 @@ if (allTargets || targets?.includes('tankModels')) {
|
|||||||
const nationVehicleId = tank.id;
|
const nationVehicleId = tank.id;
|
||||||
const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1;
|
const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1;
|
||||||
|
|
||||||
if (id !== 5137) continue;
|
if (id !== 6225) continue;
|
||||||
console.log(`Building model ${id} @ ${nation}/${tankIndex}`);
|
console.log(`Building model ${id} @ ${nation}/${tankIndex}`);
|
||||||
|
|
||||||
const parameters = await readYAMLDVPL<TankParameters>(
|
const parameters = await readYAMLDVPL<TankParameters>(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Document, Material, Node, Scene } from '@gltf-transform/core';
|
import { Document, Material, Node, Scene } from '@gltf-transform/core';
|
||||||
|
import { writeFileSync } from 'fs';
|
||||||
import { range, times } from 'lodash';
|
import { range, times } from 'lodash';
|
||||||
import { dirname } from 'path';
|
import { dirname } from 'path';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
@@ -8,6 +9,8 @@ import { readTexture } from '../blitzkrieg/readTexture';
|
|||||||
import { readDVPL } from './readDVPL';
|
import { readDVPL } from './readDVPL';
|
||||||
import { readDVPLFile } from './readDVPLFile';
|
import { readDVPLFile } from './readDVPLFile';
|
||||||
|
|
||||||
|
const MAX_FLOAT32 = 2 ** 127 * (2 - 2 ** -23);
|
||||||
|
|
||||||
enum KAType {
|
enum KAType {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
BOOLEAN = 1,
|
BOOLEAN = 1,
|
||||||
@@ -36,7 +39,7 @@ enum KAType {
|
|||||||
INT16 = 24,
|
INT16 = 24,
|
||||||
UINT16 = 25,
|
UINT16 = 25,
|
||||||
ARRAY = 27,
|
ARRAY = 27,
|
||||||
UNCONFIRMED_TRANSFORM = 29,
|
TRANSFORM = 29,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum VertexAttribute {
|
export enum VertexAttribute {
|
||||||
@@ -407,17 +410,15 @@ export class SCPGStream {
|
|||||||
return stringTable[index];
|
return stringTable[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
case KAType.UNCONFIRMED_TRANSFORM: {
|
case KAType.TRANSFORM: {
|
||||||
const position = this.consumeVector3();
|
const position = this.consumeVector3();
|
||||||
const scale = this.consumeVector3();
|
const scale = this.consumeVector3();
|
||||||
const rotation = this.consumeVector3();
|
const rotation = this.consumeVector4();
|
||||||
const UNCONFIRMED_scalar = this.consumeFloat();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
position,
|
position,
|
||||||
scale,
|
scale,
|
||||||
rotation,
|
rotation,
|
||||||
UNCONFIRMED_scalar,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,6 +512,8 @@ export class SCPGStream {
|
|||||||
const buffer = document.createBuffer();
|
const buffer = document.createBuffer();
|
||||||
const materials = new Map<bigint, Material | bigint>();
|
const materials = new Map<bigint, Material | bigint>();
|
||||||
|
|
||||||
|
writeFileSync('test.sc2.json', JSON.stringify(sc2, null, 2));
|
||||||
|
|
||||||
// create materials
|
// create materials
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
sc2['#dataNodes'].map(async (node) => {
|
sc2['#dataNodes'].map(async (node) => {
|
||||||
@@ -546,6 +549,8 @@ export class SCPGStream {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log(textures);
|
||||||
|
|
||||||
if (textures.baseRMMap) {
|
if (textures.baseRMMap) {
|
||||||
material.setMetallicRoughnessTexture(
|
material.setMetallicRoughnessTexture(
|
||||||
document
|
document
|
||||||
@@ -562,8 +567,7 @@ export class SCPGStream {
|
|||||||
.then(({ data, info }) => {
|
.then(({ data, info }) => {
|
||||||
// fake it till you make it
|
// fake it till you make it
|
||||||
for (let index = 0; index < data.length; index++) {
|
for (let index = 0; index < data.length; index++) {
|
||||||
data[index] =
|
data[index] = -data[index] + 255;
|
||||||
((-((data[index] / 255) * 2 - 1) + 1) / 2) * 255;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sharp(data, { raw: info }).jpeg().toBuffer();
|
return sharp(data, { raw: info }).jpeg().toBuffer();
|
||||||
@@ -588,8 +592,6 @@ export class SCPGStream {
|
|||||||
.then(({ data, info }) => {
|
.then(({ data, info }) => {
|
||||||
// https://www.youtube.com/watch?v=CGys6CnnYSg
|
// https://www.youtube.com/watch?v=CGys6CnnYSg
|
||||||
for (let index = 0; index < data.length; index += 3) {
|
for (let index = 0; index < data.length; index += 3) {
|
||||||
data[index] = data[index];
|
|
||||||
data[index + 1] = data[index + 1];
|
|
||||||
data[index + 2] = -data[index + 2] + 255;
|
data[index + 2] = -data[index + 2] + 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,14 +625,17 @@ export class SCPGStream {
|
|||||||
materials.set(id, resolvedMaterial);
|
materials.set(id, resolvedMaterial);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
writeFileSync('test.sc2.json', JSON.stringify(sc2, null, 2));
|
||||||
|
|
||||||
function parseHierarchies(hierarchies: Hierarchy[], parent: Scene | Node) {
|
function parseHierarchies(hierarchies: Hierarchy[], parent: Scene | Node) {
|
||||||
hierarchies.forEach((hierarchy) => {
|
hierarchies.forEach((hierarchy) => {
|
||||||
const node = document.createNode(hierarchy.name);
|
const node = document.createNode(hierarchy.name);
|
||||||
|
const components = times(
|
||||||
times(
|
|
||||||
hierarchy.components.count,
|
hierarchy.components.count,
|
||||||
(index) => hierarchy.components[index.toString().padStart(4, '0')],
|
(index) => hierarchy.components[index.toString().padStart(4, '0')],
|
||||||
).forEach((component) => {
|
);
|
||||||
|
|
||||||
|
components.forEach((component, componentIndex) => {
|
||||||
switch (component['comp.typename']) {
|
switch (component['comp.typename']) {
|
||||||
case 'TransformComponent': {
|
case 'TransformComponent': {
|
||||||
const translation = new Vector3();
|
const translation = new Vector3();
|
||||||
@@ -660,25 +665,45 @@ export class SCPGStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'RenderComponent': {
|
case 'RenderComponent': {
|
||||||
const batchIds = range(
|
let minLODDistanceBatchId: undefined | number = undefined;
|
||||||
component['rc.renderObj']['ro.batchCount'],
|
|
||||||
);
|
|
||||||
let minLODIndex = Infinity;
|
|
||||||
let minLODBatchId = Infinity;
|
|
||||||
|
|
||||||
batchIds.forEach((batchId) => {
|
if (component['rc.renderObj']['rb0.lodIndex'] === -1) {
|
||||||
const thisLODIndex =
|
minLODDistanceBatchId = 0;
|
||||||
component['rc.renderObj'][`rb${batchId}.lodIndex`];
|
} else {
|
||||||
|
const lodList = components.find(
|
||||||
|
(component) => component['comp.typename'] === 'LodComponent',
|
||||||
|
);
|
||||||
|
|
||||||
if (thisLODIndex <= minLODIndex) {
|
if (
|
||||||
minLODIndex = thisLODIndex;
|
lodList === undefined ||
|
||||||
minLODBatchId = batchId;
|
lodList['comp.typename'] !== 'LodComponent' // type annotation hack
|
||||||
|
) {
|
||||||
|
throw new SyntaxError('Missing LodComponent');
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
let minLODDistance = Infinity;
|
||||||
|
|
||||||
|
range(component['rc.renderObj']['ro.batchCount']).forEach(
|
||||||
|
(id) => {
|
||||||
|
const lodIndex =
|
||||||
|
component['rc.renderObj'][`rb${id}.lodIndex`];
|
||||||
|
const lodDistance =
|
||||||
|
lodList['lc.loddist'][`distance${lodIndex}`];
|
||||||
|
|
||||||
|
if (
|
||||||
|
lodDistance <= minLODDistance ||
|
||||||
|
lodDistance === MAX_FLOAT32
|
||||||
|
) {
|
||||||
|
minLODDistance = lodDistance;
|
||||||
|
minLODDistanceBatchId = id;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const batch =
|
const batch =
|
||||||
component['rc.renderObj']['ro.batches'][
|
component['rc.renderObj']['ro.batches'][
|
||||||
minLODBatchId.toString().padStart(4, '0')
|
minLODDistanceBatchId!.toString().padStart(4, '0')
|
||||||
];
|
];
|
||||||
const polygonGroup = scg.find(
|
const polygonGroup = scg.find(
|
||||||
(group) => group.id === batch['rb.datasource'],
|
(group) => group.id === batch['rb.datasource'],
|
||||||
@@ -725,11 +750,7 @@ export class SCPGStream {
|
|||||||
.setMaterial(material);
|
.setMaterial(material);
|
||||||
|
|
||||||
indexedVertexTypes.forEach((type) => {
|
indexedVertexTypes.forEach((type) => {
|
||||||
if (!(type in vertexAttributeGLTFName)) {
|
if (!(type in vertexAttributeGLTFName)) return;
|
||||||
throw new TypeError(
|
|
||||||
`Unhandled vertex type GLTF name: ${VertexAttribute[type]} (${type})`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const vertexSize = vertexAttributeVectorSizes[type];
|
const vertexSize = vertexAttributeVectorSizes[type];
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user