mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-28 21:19:52 +01:00
feat: support transparency
This commit is contained in:
1 parent
06a3791ddd
commit
4ab03e56a2
7 files changed
+190
-184
No files matched your search
+101
-102
@@ -1,20 +1,19 @@
|
|||||||
import { Vector3Tuple, Vector4Tuple } from 'three';
|
import { Vector3Tuple, Vector4Tuple } from "three";
|
||||||
import { ScpgReadStream } from './scpg';
|
import { ScpgReadStream } from "./scpg";
|
||||||
|
|
||||||
export interface SC2 {
|
export interface SC2 {
|
||||||
'#dataNodes': DataNode[];
|
"#dataNodes": DataNode[];
|
||||||
'#hierarchy': Hierarchy[];
|
"#hierarchy": Hierarchy[];
|
||||||
'#sceneComponents': SceneComponents;
|
"#sceneComponents": SceneComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
type DataNode = {
|
type DataNode = {
|
||||||
'##name': 'NMaterial';
|
"##name": "NMaterial";
|
||||||
'#id': ArrayBuffer;
|
"#id": ArrayBuffer;
|
||||||
materialName: string;
|
materialName: string;
|
||||||
parentMaterialKey?: bigint;
|
parentMaterialKey?: bigint;
|
||||||
qualityGroup?: string;
|
qualityGroup?: string;
|
||||||
fxName?: string;
|
fxName?: string;
|
||||||
|
|
||||||
textures?: Textures;
|
textures?: Textures;
|
||||||
} & (
|
} & (
|
||||||
| ({
|
| ({
|
||||||
@@ -80,8 +79,8 @@ export interface Textures {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Hierarchy {
|
export interface Hierarchy {
|
||||||
'##name': 'Entity';
|
"##name": "Entity";
|
||||||
'#hierarchy'?: Hierarchy[];
|
"#hierarchy"?: Hierarchy[];
|
||||||
components: Components;
|
components: Components;
|
||||||
flags: number;
|
flags: number;
|
||||||
id: bigint;
|
id: bigint;
|
||||||
@@ -97,12 +96,12 @@ type Components = {
|
|||||||
type RoBatches = Record<
|
type RoBatches = Record<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
'##name': 'RenderBatch';
|
"##name": "RenderBatch";
|
||||||
'rb.aabbox': RbAabbox;
|
"rb.aabbox": RbAabbox;
|
||||||
'rb.classname': 'RenderBatch';
|
"rb.classname": "RenderBatch";
|
||||||
'rb.datasource': bigint;
|
"rb.datasource": bigint;
|
||||||
'rb.nmatname': bigint;
|
"rb.nmatname": bigint;
|
||||||
'rb.sortingKey': number;
|
"rb.sortingKey": number;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@@ -113,50 +112,50 @@ interface RbAabbox {
|
|||||||
|
|
||||||
export type Component =
|
export type Component =
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'TransformComponent';
|
"comp.typename": "TransformComponent";
|
||||||
'tc.localRotation': Vector4Tuple;
|
"tc.localRotation": Vector4Tuple;
|
||||||
'tc.localScale': Vector3Tuple;
|
"tc.localScale": Vector3Tuple;
|
||||||
'tc.localTranslation': Vector3Tuple;
|
"tc.localTranslation": Vector3Tuple;
|
||||||
'tc.worldRotation': Vector4Tuple;
|
"tc.worldRotation": Vector4Tuple;
|
||||||
'tc.worldScale': Vector3Tuple;
|
"tc.worldScale": Vector3Tuple;
|
||||||
'tc.worldTranslation': Vector3Tuple;
|
"tc.worldTranslation": Vector3Tuple;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'RenderComponent';
|
"comp.typename": "RenderComponent";
|
||||||
'rc.renderObj': {
|
"rc.renderObj": {
|
||||||
'##name': 'Mesh';
|
"##name": "Mesh";
|
||||||
'ro.batchCount': number;
|
"ro.batchCount": number;
|
||||||
'ro.batches': RoBatches;
|
"ro.batches": RoBatches;
|
||||||
'ro.debugflags': number;
|
"ro.debugflags": number;
|
||||||
'ro.flags': number;
|
"ro.flags": number;
|
||||||
'ro.notShadowOnly': boolean;
|
"ro.notShadowOnly": boolean;
|
||||||
'ro.sOclCull': boolean;
|
"ro.sOclCull": boolean;
|
||||||
'ro.sOclIndex': number;
|
"ro.sOclIndex": number;
|
||||||
} & Record<`rb${number}.${'lodIndex' | 'switchIndex'}`, number>;
|
} & Record<`rb${number}.${"lodIndex" | "switchIndex"}`, number>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'SlotComponent';
|
"comp.typename": "SlotComponent";
|
||||||
'sc.attachmentRotation': number[];
|
"sc.attachmentRotation": number[];
|
||||||
'sc.attachmentScale': number[];
|
"sc.attachmentScale": number[];
|
||||||
'sc.attachmentTranslation': number[];
|
"sc.attachmentTranslation": number[];
|
||||||
'sc.configFilePath': string;
|
"sc.configFilePath": string;
|
||||||
'sc.slotName': string;
|
"sc.slotName": string;
|
||||||
'sc.template': string;
|
"sc.template": string;
|
||||||
'sc.typeFiltersCount': number;
|
"sc.typeFiltersCount": number;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'LodComponent';
|
"comp.typename": "LodComponent";
|
||||||
'lc.loddist': Record<`distance${number}`, number>;
|
"lc.loddist": Record<`distance${number}`, number>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'DecorItemComponent';
|
"comp.typename": "DecorItemComponent";
|
||||||
drawOrder: number;
|
drawOrder: number;
|
||||||
shouldApplyCamo: boolean;
|
shouldApplyCamo: boolean;
|
||||||
vanishTargetAlpha: number;
|
vanishTargetAlpha: number;
|
||||||
vanishWhenArmorShown: boolean;
|
vanishWhenArmorShown: boolean;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'NewSlotComponent';
|
"comp.typename": "NewSlotComponent";
|
||||||
slotItemsCount: number;
|
slotItemsCount: number;
|
||||||
slots: {
|
slots: {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
@@ -171,109 +170,109 @@ export type Component =
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'ScenarioComponent';
|
"comp.typename": "ScenarioComponent";
|
||||||
'scenario.scriptId': string;
|
"scenario.scriptId": string;
|
||||||
}
|
}
|
||||||
| ({
|
| ({
|
||||||
'comp.typename': 'StateSwitcherComponent';
|
"comp.typename": "StateSwitcherComponent";
|
||||||
'ssc.activeState': number;
|
"ssc.activeState": number;
|
||||||
'ssc.statesCount': number;
|
"ssc.statesCount": number;
|
||||||
} & Record<`ssc.state${number}`, string>)
|
} & Record<`ssc.state${number}`, string>)
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'CustomPropertiesComponent';
|
"comp.typename": "CustomPropertiesComponent";
|
||||||
'cpc.properties.archive': {
|
"cpc.properties.archive": {
|
||||||
'editor.donotremove': number;
|
"editor.donotremove": number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
| ({
|
| ({
|
||||||
'comp.typename': 'ActionComponent';
|
"comp.typename": "ActionComponent";
|
||||||
'ac.actionCount': number;
|
"ac.actionCount": number;
|
||||||
} & Record<
|
} & Record<
|
||||||
string, // 0000, 0001, ...
|
string, // 0000, 0001, ...
|
||||||
{
|
{
|
||||||
'act.delay': number;
|
"act.delay": number;
|
||||||
'act.delayVariation': number;
|
"act.delayVariation": number;
|
||||||
'act.entityName': string;
|
"act.entityName": string;
|
||||||
'act.event': number;
|
"act.event": number;
|
||||||
'act.eventToTrigger': string;
|
"act.eventToTrigger": string;
|
||||||
'act.motionFrameTime': number;
|
"act.motionFrameTime": number;
|
||||||
'act.motionSpeed': number;
|
"act.motionSpeed": number;
|
||||||
'act.stateActivated': number;
|
"act.stateActivated": number;
|
||||||
'act.stopAfterNRepeats': number;
|
"act.stopAfterNRepeats": number;
|
||||||
'act.stopWhenEmpty': boolean;
|
"act.stopWhenEmpty": boolean;
|
||||||
'act.switchIndex': number;
|
"act.switchIndex": number;
|
||||||
'act.type': number;
|
"act.type": number;
|
||||||
'act.userEventId': string;
|
"act.userEventId": string;
|
||||||
}
|
}
|
||||||
>)
|
>)
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'ParticleEffectComponent';
|
"comp.typename": "ParticleEffectComponent";
|
||||||
'pe.clearOnRestart': boolean;
|
"pe.clearOnRestart": boolean;
|
||||||
'pe.effectDuration': number;
|
"pe.effectDuration": number;
|
||||||
'pe.emitters': {
|
"pe.emitters": {
|
||||||
'##name': string;
|
"##name": string;
|
||||||
'emitter.data': {
|
"emitter.data": {
|
||||||
'emitter.id': `${number}`;
|
"emitter.id": `${number}`;
|
||||||
'emitter.quality': string;
|
"emitter.quality": string;
|
||||||
}[];
|
}[];
|
||||||
'emitter.position': Vector3Tuple;
|
"emitter.position": Vector3Tuple;
|
||||||
'emitter.rotation': Vector4Tuple;
|
"emitter.rotation": Vector4Tuple;
|
||||||
'emitter.scale': Vector3Tuple;
|
"emitter.scale": Vector3Tuple;
|
||||||
}[];
|
}[];
|
||||||
'pe.inheritScale': boolean;
|
"pe.inheritScale": boolean;
|
||||||
'pe.nestedEmitters': boolean;
|
"pe.nestedEmitters": boolean;
|
||||||
'pe.repeatsCount': number;
|
"pe.repeatsCount": number;
|
||||||
'pe.startFromTime': number;
|
"pe.startFromTime": number;
|
||||||
'pe.stopWhenEmpty': boolean;
|
"pe.stopWhenEmpty": boolean;
|
||||||
'pe.version': number;
|
"pe.version": number;
|
||||||
'ro.flags': number;
|
"ro.flags": number;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'TankElementComponent';
|
"comp.typename": "TankElementComponent";
|
||||||
isDestructible: boolean;
|
isDestructible: boolean;
|
||||||
shouldCastShadow: boolean;
|
shouldCastShadow: boolean;
|
||||||
shouldGenerateSilhouette: boolean;
|
shouldGenerateSilhouette: boolean;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'MotionComponent';
|
"comp.typename": "MotionComponent";
|
||||||
'motion.filepath': string;
|
"motion.filepath": string;
|
||||||
'motion.playbackRate': number;
|
"motion.playbackRate": number;
|
||||||
'simpleMotion.repeatsCount': number;
|
"simpleMotion.repeatsCount": number;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'SkeletonComponent';
|
"comp.typename": "SkeletonComponent";
|
||||||
joints: Record<
|
joints: Record<
|
||||||
string, // 0000, 0001, ...
|
string, // 0000, 0001, ...
|
||||||
{
|
{
|
||||||
'joint.bbox.max': Vector3Tuple;
|
"joint.bbox.max": Vector3Tuple;
|
||||||
'joint.bbox.min': Vector3Tuple;
|
"joint.bbox.min": Vector3Tuple;
|
||||||
'joint.bindPose': [
|
"joint.bindPose": [
|
||||||
Vector4Tuple,
|
Vector4Tuple,
|
||||||
Vector4Tuple,
|
Vector4Tuple,
|
||||||
Vector4Tuple,
|
Vector4Tuple,
|
||||||
Vector4Tuple,
|
Vector4Tuple,
|
||||||
];
|
];
|
||||||
'joint.invBindPose': [
|
"joint.invBindPose": [
|
||||||
Vector4Tuple,
|
Vector4Tuple,
|
||||||
Vector4Tuple,
|
Vector4Tuple,
|
||||||
Vector4Tuple,
|
Vector4Tuple,
|
||||||
Vector4Tuple,
|
Vector4Tuple,
|
||||||
];
|
];
|
||||||
'joint.name': string;
|
"joint.name": string;
|
||||||
'joint.parentIndex': number;
|
"joint.parentIndex": number;
|
||||||
'joint.uid': string;
|
"joint.uid": string;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
jointsCount: number;
|
jointsCount: number;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'AnimationComponent';
|
"comp.typename": "AnimationComponent";
|
||||||
animation: bigint;
|
animation: bigint;
|
||||||
animationTimeScale: number;
|
animationTimeScale: number;
|
||||||
repeatsCount: number;
|
repeatsCount: number;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'SkeletonJointBindingComponent';
|
"comp.typename": "SkeletonJointBindingComponent";
|
||||||
count: number;
|
count: number;
|
||||||
map: Record<
|
map: Record<
|
||||||
string, // 0000, 0001, ...
|
string, // 0000, 0001, ...
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
import { assertSecret } from "@blitzkit/core";
|
|
||||||
|
|
||||||
const dev = assertSecret(import.meta.env.DEV);
|
|
||||||
|
|
||||||
export function literals(
|
export function literals(
|
||||||
string: string,
|
string: string,
|
||||||
literals?: Record<string, string | number | undefined>
|
literals?: Record<string, string | number | undefined>
|
||||||
@@ -9,7 +5,7 @@ export function literals(
|
|||||||
for (const key in literals) {
|
for (const key in literals) {
|
||||||
const mutated = string.replaceAll(`{${key}}`, `${literals[key]}`);
|
const mutated = string.replaceAll(`{${key}}`, `${literals[key]}`);
|
||||||
|
|
||||||
if (dev && mutated === string) {
|
if (import.meta.env.DEV && mutated === string) {
|
||||||
console.warn(`Could not find literal {${key}} in string "${string}"`);
|
console.warn(`Could not find literal {${key}} in string "${string}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ export async function tankModels() {
|
|||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
for (const [tankKey, tank] of entries) {
|
for (const [tankKey, tank] of entries) {
|
||||||
console.log(` ${++index} / ${entries.length} : ${tankKey}`);
|
|
||||||
|
|
||||||
if (tankKey.includes("tutorial_bot")) continue;
|
if (tankKey.includes("tutorial_bot")) continue;
|
||||||
|
|
||||||
const id = toUniqueId(nation, tank.id);
|
const id = toUniqueId(nation, tank.id);
|
||||||
|
|
||||||
|
console.log(` ${++index} / ${entries.length} : ${tankKey}`);
|
||||||
|
|
||||||
const parameters = await readYAMLDVPL<TankParameters>(
|
const parameters = await readYAMLDVPL<TankParameters>(
|
||||||
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`
|
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -39,82 +39,95 @@ export async function extractModel(data: string, path: string) {
|
|||||||
const buffer = document.createBuffer();
|
const buffer = document.createBuffer();
|
||||||
const materials = new Map<bigint, Material | bigint | undefined>();
|
const materials = new Map<bigint, Material | bigint | undefined>();
|
||||||
|
|
||||||
// create materials
|
for (const node of sc2["#dataNodes"]) {
|
||||||
await Promise.all(
|
const id = new DataView(node["#id"]).getBigUint64(0, true);
|
||||||
sc2["#dataNodes"].map(async (node) => {
|
|
||||||
const id = new DataView(node["#id"]).getBigUint64(0, true);
|
|
||||||
|
|
||||||
if (node.parentMaterialKey !== undefined) {
|
if (node.parentMaterialKey !== undefined) {
|
||||||
/**
|
/**
|
||||||
* material depends on a parent and doesn't seem to have any
|
* material depends on a parent and doesn't seem to have any
|
||||||
* properties so we just point it to the parent
|
* properties so we just point it to the parent
|
||||||
*/
|
*/
|
||||||
materials.set(id, node.parentMaterialKey);
|
materials.set(id, node.parentMaterialKey);
|
||||||
return;
|
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);
|
if (textures.baseRMMap) {
|
||||||
let textures: Textures | undefined = undefined;
|
material.setMetallicRoughnessTexture(
|
||||||
|
|
||||||
if (node.textures) {
|
|
||||||
textures = node.textures;
|
|
||||||
} else if (typeof node.configCount === "number") {
|
|
||||||
textures = node.configArchive_0.textures;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (textures) {
|
|
||||||
material.setBaseColorTexture(
|
|
||||||
document
|
document
|
||||||
.createTexture(node.materialName)
|
.createTexture(node.materialName)
|
||||||
.setMimeType("image/jpeg")
|
.setMimeType("image/webp")
|
||||||
.setImage(
|
.setImage(
|
||||||
await readBaseColor(
|
await readRoughnessMetallic(
|
||||||
`${data}/3d/${dirname(path)}/${textures.baseColorMap ?? textures.albedo}`,
|
`${data}/3d/${dirname(path)}/${textures.baseRMMap}`
|
||||||
textures.miscMap
|
|
||||||
? `${data}/3d/${dirname(path)}/${textures.miscMap}`
|
|
||||||
: undefined
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (textures.baseRMMap) {
|
if (textures.baseNormalMap ?? textures.normalmap) {
|
||||||
material.setMetallicRoughnessTexture(
|
const isBase = textures.baseNormalMap !== undefined;
|
||||||
document
|
|
||||||
.createTexture(node.materialName)
|
material.setNormalTexture(
|
||||||
.setMimeType("image/jpeg")
|
document
|
||||||
.setImage(
|
.createTexture(node.materialName)
|
||||||
await readRoughnessMetallic(
|
.setMimeType("image/webp")
|
||||||
`${data}/3d/${dirname(path)}/${textures.baseRMMap}`
|
.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
|
// replace children materials with parents
|
||||||
materials.forEach((material, id) => {
|
materials.forEach((material, id) => {
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ export async function readBaseColor(path: string, occlusionPath?: string) {
|
|||||||
const occlusionRaw = occlusionPath
|
const occlusionRaw = occlusionPath
|
||||||
? await readTexture(occlusionPath)
|
? await readTexture(occlusionPath)
|
||||||
: undefined;
|
: undefined;
|
||||||
const base = await sharp(baseRaw.data, { raw: baseRaw })
|
const base = await sharp(baseRaw.data, { raw: baseRaw }).raw().toBuffer();
|
||||||
.removeAlpha()
|
|
||||||
.raw()
|
|
||||||
.toBuffer();
|
|
||||||
const occlusion = occlusionRaw
|
const occlusion = occlusionRaw
|
||||||
? await sharp(occlusionRaw.data, { raw: occlusionRaw })
|
? await sharp(occlusionRaw.data, { raw: occlusionRaw })
|
||||||
.extractChannel(3)
|
.extractChannel(3)
|
||||||
@@ -17,7 +14,7 @@ export async function readBaseColor(path: string, occlusionPath?: string) {
|
|||||||
.toBuffer()
|
.toBuffer()
|
||||||
: undefined;
|
: 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++) {
|
for (let i = 0; i < baseRaw.width * baseRaw.height; i++) {
|
||||||
let c = 1;
|
let c = 1;
|
||||||
@@ -33,15 +30,16 @@ export async function readBaseColor(path: string, occlusionPath?: string) {
|
|||||||
c = occlusion![occlusionI] / 255;
|
c = occlusion![occlusionI] / 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
combined[i * 3 + 0] = Math.round(base[i * 3 + 0] * c);
|
combined[i * 4 + 0] = Math.round(base[i * 4 + 0] * c);
|
||||||
combined[i * 3 + 1] = Math.round(base[i * 3 + 1] * c);
|
combined[i * 4 + 1] = Math.round(base[i * 4 + 1] * c);
|
||||||
combined[i * 3 + 2] = Math.round(base[i * 3 + 2] * 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, {
|
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();
|
.toBuffer();
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
|
|||||||
@@ -25,5 +25,5 @@ export async function readNormal(path: string, isBase: boolean) {
|
|||||||
raw.data[index + 3] = 255;
|
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, {
|
const image = await sharp(combined, {
|
||||||
raw: { width: raw.width, height: raw.height, channels: 3 },
|
raw: { width: raw.width, height: raw.height, channels: 3 },
|
||||||
})
|
})
|
||||||
.jpeg()
|
.webp()
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
|
|||||||
Reference in new issue
Block a user