Files
node-metaverse/lib/classes/LLGLTFMaterialOverride.ts

404 lines
12 KiB
TypeScript
Raw Normal View History

import type {
2023-11-16 02:03:08 +00:00
LLGLTFExtensionsAndExtras,
LLGLTFMaterialData,
LLGLTFMaterialEntry,
LLGLTFTextureInfo,
} from './LLGLTFMaterialData';
import { UUID } from './UUID';
2023-11-10 23:57:26 +00:00
export interface LLGLTFTextureTransformOverride
{
2023-11-16 02:03:08 +00:00
offset?: number[];
scale?: number[];
rotation?: number
2023-11-10 23:57:26 +00:00
}
export class LLGLTFMaterialOverride
{
2023-11-16 02:03:08 +00:00
public textures?: (string | null)[];
2023-11-10 23:57:26 +00:00
public baseColor?: number[];
2023-11-16 02:03:08 +00:00
public emissiveFactor?: number[];
2023-11-10 23:57:26 +00:00
public metallicFactor?: number;
public roughnessFactor?: number;
public alphaMode?: number;
public alphaCutoff?: number;
public doubleSided?: boolean;
2023-11-16 02:03:08 +00:00
public textureTransforms?: (LLGLTFTextureTransformOverride | null)[];
public static fromFullMaterialJSON(json: string): LLGLTFMaterialOverride
{
const obj = JSON.parse(json) as LLGLTFMaterialData;
const over = new LLGLTFMaterialOverride();
if (!obj.materials?.length)
{
return over;
}
const mat = obj.materials[0];
const getTexture = (idx: number): { uuid: string | null, transform: LLGLTFTextureTransformOverride | null } =>
{
const found: {
uuid: string | null,
transform: LLGLTFTextureTransformOverride | null
} = {
uuid: null,
transform: null
};
if (obj.textures && Array.isArray(obj.textures) && obj.textures.length > idx)
{
const source = obj.textures[idx].source;
if (source !== undefined && obj.images && Array.isArray(obj.images) && obj.images.length > source)
{
const img = obj.images[source];
if ('uri' in img)
{
found.uuid = img.uri ?? null;
if (found.uuid === UUID.zero().toString())
{
found.uuid = null;
}
}
}
const transform = obj.textures[idx].extensions?.KHR_texture_transform as {
offset?: number[],
scale?: number[],
rotation?: number
};
if (transform)
{
found.transform = transform ?? null;
}
}
return found;
};
if (mat.pbrMetallicRoughness)
{
const pbr = mat.pbrMetallicRoughness;
if (pbr.metallicFactor !== undefined)
{
over.metallicFactor = pbr.metallicFactor;
}
if (pbr.roughnessFactor !== undefined)
{
over.roughnessFactor = pbr.roughnessFactor;
}
if (pbr.baseColorFactor !== undefined && Array.isArray(pbr.baseColorFactor) && pbr.baseColorFactor.length === 4)
{
over.baseColor = pbr.baseColorFactor;
}
if (pbr.baseColorTexture?.index !== undefined)
{
const tex = getTexture(pbr.baseColorTexture.index);
if (tex?.uuid)
{
over.setTexture(0, tex.uuid);
}
if (tex?.transform)
{
over.setTransform(0, tex.transform);
}
}
if (pbr.metallicRoughnessTexture?.index !== undefined)
{
const tex = getTexture(pbr.metallicRoughnessTexture.index);
if (tex?.uuid)
{
over.setTexture(2, tex.uuid);
}
if (tex?.transform)
{
over.setTransform(2, tex.transform);
}
}
}
if (mat.alphaMode)
{
switch (mat.alphaMode)
{
case 'BLEND':
over.alphaMode = 1;
break;
case 'MASK':
over.alphaMode = 2;
break;
}
}
else if (mat.extras?.override_alpha_mode)
{
over.alphaMode = 0;
}
if (mat.alphaCutoff !== undefined)
{
over.alphaCutoff = mat.alphaCutoff;
}
if (mat.emissiveFactor !== undefined)
{
over.emissiveFactor = mat.emissiveFactor;
}
if (mat.doubleSided === true)
{
over.doubleSided = true;
}
else if (mat.extras?.override_double_sided)
{
over.doubleSided = false;
}
if (mat.normalTexture?.index !== undefined)
{
const tex = getTexture(mat.normalTexture?.index);
if (tex?.uuid)
{
over.setTexture(1, tex.uuid);
}
if (tex?.transform)
{
over.setTransform(1, tex.transform);
}
}
if (mat.emissiveTexture?.index !== undefined)
{
const tex = getTexture(mat.emissiveTexture?.index);
if (tex?.uuid)
{
over.setTexture(3, tex.uuid);
}
if (tex?.transform)
{
over.setTransform(3, tex.transform);
}
}
return over;
}
2023-11-16 02:03:08 +00:00
public getFullMaterialJSON(): string
{
const obj: LLGLTFMaterialData = {};
obj.asset = {
version: '2.0',
};
let texIndex = 0;
const material: LLGLTFMaterialEntry & LLGLTFExtensionsAndExtras = {};
const addTexture = (texNum: number): number | undefined =>
{
let idx: number | undefined = undefined;
if ((this.textures && this.textures.length > texNum && this.textures[texNum] !== null) || (this.textureTransforms && this.textureTransforms.length > texNum && this.textureTransforms[texNum] !== null))
{
idx = texIndex++;
if (idx === 0)
{
obj.images = [];
obj.textures = [];
}
const texture = this.textures?.[texNum];
if (texture)
{
if (obj.images)
{
obj.images.push({
uri: texture
});
}
2023-11-16 02:03:08 +00:00
}
else
{
if (obj.images)
{
obj.images.push({
uri: UUID.zero().toString()
});
}
2023-11-16 02:03:08 +00:00
}
const tex: {
source: number
} & LLGLTFExtensionsAndExtras = {
source: idx
};
if (this.textureTransforms && this.textureTransforms.length > texNum && this.textureTransforms[texNum] !== null)
{
const trans = this.textureTransforms[texNum];
tex.extensions = {
KHR_texture_transform: {
offset: trans?.offset ?? undefined,
scale: trans?.scale ?? undefined,
rotation: trans?.rotation ?? undefined
}
};
}
if (obj.textures === undefined)
{
obj.textures = [
tex
];
}
else
{
obj.textures.push(tex);
}
}
return idx;
}
if (
this.baseColor !== undefined
|| (this.textures !== undefined
&& ((this.textures.length > 0
&& this.textures[0] !== undefined
)
|| (this.textures.length > 2
&& this.textures[2] !== undefined
)))
|| this.metallicFactor !== undefined
|| this.roughnessFactor !== undefined
)
{
const pbrMetallicRoughness: {
baseColorFactor?: number[];
baseColorTexture?: LLGLTFTextureInfo;
metallicRoughnessTexture?: LLGLTFTextureInfo;
metallicFactor?: number;
roughnessFactor?: number;
} & LLGLTFExtensionsAndExtras = {
baseColorFactor: this.baseColor,
metallicFactor: this.metallicFactor,
roughnessFactor: this.roughnessFactor
};
let texIdx2 = addTexture(0);
if (texIdx2 !== undefined)
{
pbrMetallicRoughness.baseColorTexture = {
index: texIdx2
};
}
texIdx2 = addTexture(2);
if (texIdx2 !== undefined)
{
pbrMetallicRoughness.metallicRoughnessTexture = {
index: texIdx2
};
material.occlusionTexture = {
index: texIdx2
};
}
material.pbrMetallicRoughness = pbrMetallicRoughness;
}
if (this.alphaMode !== undefined)
{
if (this.alphaMode === 0) // OPAQUE
{
material.extras = {
override_alpha_mode: true
};
}
else if (this.alphaMode === 1)
{
material.alphaMode = 'BLEND';
}
else if (this.alphaMode === 2)
{
material.alphaMode = 'MASK';
}
}
if (this.alphaCutoff !== undefined)
{
material.alphaCutoff = this.alphaCutoff;
}
if (this.emissiveFactor !== undefined)
{
material.emissiveFactor = this.emissiveFactor;
}
if (this.doubleSided)
{
material.doubleSided = this.doubleSided;
}
else if (this.doubleSided === false)
{
if (!material.extras)
{
material.extras = {};
}
material.extras.override_double_sided = true;
}
// Emissive Texture
let texIdx = addTexture(3);
if (texIdx !== undefined)
{
material.emissiveTexture = {
index: texIdx
};
}
// Normal Map Texture
texIdx = addTexture(1);
if (texIdx !== undefined)
{
material.normalTexture = {
index: texIdx
};
}
if (Object.keys(material).length > 0)
{
obj.materials = [
material
];
}
return JSON.stringify(obj);
}
public setTexture(idx: number, uuid: string): void
{
if (!this.textures)
{
this.textures = [];
}
for (let x = this.textures.length; x < idx + 1; x++)
{
this.textures.push(null);
}
this.textures[idx] = uuid;
}
public setTransform(idx: number, trans: LLGLTFTextureTransformOverride): void
{
if (!this.textureTransforms)
{
this.textureTransforms = [];
}
for (let x = this.textureTransforms.length; x < idx + 1; x++)
{
this.textureTransforms.push(null);
}
this.textureTransforms[idx] = trans;
}
2023-11-10 23:57:26 +00:00
}