Merge branch 'main' into dev/1.5

This commit is contained in:
GuoLei1990
2025-04-28 11:27:22 +08:00
133 changed files with 2331 additions and 1831 deletions

View File

@@ -8,9 +8,9 @@ import {
resourceLoader,
ResourceManager
} from "@galacean/engine-core";
import { getMeshoptDecoder, ready } from "./gltf/extensions/MeshoptDecoder";
import { GLTFResource } from "./gltf/GLTFResource";
import { GLTFParserContext } from "./gltf/parser";
import { getMeshoptDecoder, ready } from "./gltf/extensions/MeshoptDecoder";
@resourceLoader(AssetType.GLTF, ["gltf", "glb"])
export class GLTFLoader extends Loader<GLTFResource> {
@@ -44,10 +44,22 @@ export class GLTFLoader extends Loader<GLTFResource> {
...params
});
return new AssetPromise((resolve, reject, setTaskCompleteProgress, setTaskDetailProgress) => {
return new AssetPromise((resolve, reject, setTaskCompleteProgress, setTaskDetailProgress, onTaskCancel) => {
context._setTaskCompleteProgress = setTaskCompleteProgress;
context._setTaskDetailProgress = setTaskDetailProgress;
context.parse().then(resolve).catch(reject);
onTaskCancel(() => {
const getPromises = context._getPromises;
for (let i = 0, n = getPromises.length; i < n; i++) {
getPromises[i].cancel();
}
});
context
.parse()
.then(resolve)
.catch((e) => {
glTFResource.destroy();
reject(e);
});
});
}
}

View File

@@ -71,7 +71,8 @@ export class GLTFResource extends ReferResource {
materials && this._disassociationSuperResource(materials);
if (meshes) {
for (let i = 0, n = meshes.length; i < n; i++) {
this._disassociationSuperResource(meshes[i]);
const meshArr = meshes[i];
meshArr && this._disassociationSuperResource(meshArr);
}
}
}
@@ -79,7 +80,7 @@ export class GLTFResource extends ReferResource {
private _disassociationSuperResource(resources: ReferResource[]): void {
for (let i = 0, n = resources.length; i < n; i++) {
// @ts-ignore
resources[i]._disassociationSuperResource(this);
resources[i]?._disassociationSuperResource(this);
}
}

View File

@@ -1,5 +1,7 @@
import {
AssetPromise,
IndexFormat,
Logger,
Texture2D,
TextureFilterMode,
TypedArray,
@@ -132,7 +134,7 @@ export class GLTFUtils {
context: GLTFParserContext,
bufferViews: IBufferView[],
accessor: IAccessor
): Promise<BufferInfo> {
): AssetPromise<BufferInfo> {
const componentType = accessor.componentType;
const TypedArray = GLTFUtils.getComponentType(componentType);
const dataElementSize = GLTFUtils.getAccessorTypeSize(accessor.type);
@@ -140,47 +142,51 @@ export class GLTFUtils {
const elementStride = dataElementSize * dataElementBytes;
const accessorCount = accessor.count;
let promise: Promise<BufferInfo>;
let promise: AssetPromise<BufferInfo>;
if (accessor.bufferView !== undefined) {
const bufferViewIndex = accessor.bufferView;
const bufferView = bufferViews[bufferViewIndex];
promise = context
.get<Uint8Array>(GLTFParserType.BufferView, accessor.bufferView)
.then((bufferViewData) => {
const bufferIndex = bufferView.buffer;
const bufferByteOffset = bufferViewData.byteOffset ?? 0;
const byteOffset = accessor.byteOffset ?? 0;
promise = context.get<Uint8Array>(GLTFParserType.BufferView, accessor.bufferView).then((bufferViewData) => {
const bufferIndex = bufferView.buffer;
const bufferByteOffset = bufferViewData.byteOffset ?? 0;
const byteOffset = accessor.byteOffset ?? 0;
const bufferStride = bufferView.byteStride;
const bufferStride = bufferView.byteStride;
let bufferInfo: BufferInfo;
// According to the glTF official documentation only byteStride not undefined is allowed
if (bufferStride !== undefined && bufferStride !== elementStride) {
const bufferSlice = Math.floor(byteOffset / bufferStride);
const bufferCacheKey = bufferViewIndex + ":" + componentType + ":" + bufferSlice + ":" + accessorCount;
const accessorBufferCache = context.accessorBufferCache;
bufferInfo = accessorBufferCache[bufferCacheKey];
if (!bufferInfo) {
const offset = bufferByteOffset + bufferSlice * bufferStride;
const count = accessorCount * (bufferStride / dataElementBytes);
let bufferInfo: BufferInfo;
// According to the glTF official documentation only byteStride not undefined is allowed
if (bufferStride !== undefined && bufferStride !== elementStride) {
const bufferSlice = Math.floor(byteOffset / bufferStride);
const bufferCacheKey = bufferViewIndex + ":" + componentType + ":" + bufferSlice + ":" + accessorCount;
const accessorBufferCache = context.accessorBufferCache;
bufferInfo = accessorBufferCache[bufferCacheKey];
if (!bufferInfo) {
const offset = bufferByteOffset + bufferSlice * bufferStride;
const count = accessorCount * (bufferStride / dataElementBytes);
const data = new TypedArray(bufferViewData.buffer, offset, count);
accessorBufferCache[bufferCacheKey] = bufferInfo = new BufferInfo(data, true, bufferStride);
bufferInfo.restoreInfo = new BufferDataRestoreInfo(
new RestoreDataAccessor(bufferIndex, TypedArray, offset, count)
);
}
} else {
const offset = bufferByteOffset + byteOffset;
const count = accessorCount * dataElementSize;
const data = new TypedArray(bufferViewData.buffer, offset, count);
accessorBufferCache[bufferCacheKey] = bufferInfo = new BufferInfo(data, true, bufferStride);
bufferInfo = new BufferInfo(data, false, elementStride);
bufferInfo.restoreInfo = new BufferDataRestoreInfo(
new RestoreDataAccessor(bufferIndex, TypedArray, offset, count)
);
}
} else {
const offset = bufferByteOffset + byteOffset;
const count = accessorCount * dataElementSize;
const data = new TypedArray(bufferViewData.buffer, offset, count);
bufferInfo = new BufferInfo(data, false, elementStride);
bufferInfo.restoreInfo = new BufferDataRestoreInfo(
new RestoreDataAccessor(bufferIndex, TypedArray, offset, count)
);
}
return bufferInfo;
});
return bufferInfo;
})
.catch((e) => {
Logger.error("GLTFUtil getAccessorBuffer error", e);
});
} else {
const count = accessorCount * dataElementSize;
const data = new TypedArray(count);
@@ -189,7 +195,7 @@ export class GLTFUtils {
new RestoreDataAccessor(undefined, TypedArray, undefined, count)
);
promise = Promise.resolve(bufferInfo);
promise = AssetPromise.resolve(bufferInfo);
}
return accessor.sparse
@@ -240,47 +246,50 @@ export class GLTFUtils {
const indicesBufferView = bufferViews[indices.bufferView];
const valuesBufferView = bufferViews[values.bufferView];
return Promise.all([
return AssetPromise.all([
context.get<Uint8Array>(GLTFParserType.BufferView, indices.bufferView),
context.get<Uint8Array>(GLTFParserType.BufferView, values.bufferView)
]).then(([indicesUint8Array, valuesUin8Array]) => {
const indicesByteOffset = (indices.byteOffset ?? 0) + (indicesUint8Array.byteOffset ?? 0);
const indicesByteLength = indicesUint8Array.byteLength;
const valuesByteOffset = (values.byteOffset ?? 0) + (valuesUin8Array.byteOffset ?? 0);
const valuesByteLength = valuesUin8Array.byteLength;
])
.then(([indicesUint8Array, valuesUin8Array]) => {
const indicesByteOffset = (indices.byteOffset ?? 0) + (indicesUint8Array.byteOffset ?? 0);
const indicesByteLength = indicesUint8Array.byteLength;
const valuesByteOffset = (values.byteOffset ?? 0) + (valuesUin8Array.byteOffset ?? 0);
const valuesByteLength = valuesUin8Array.byteLength;
restoreInfo.typeSize = accessorTypeSize;
restoreInfo.sparseCount = count;
restoreInfo.typeSize = accessorTypeSize;
restoreInfo.sparseCount = count;
const IndexTypeArray = GLTFUtils.getComponentType(indices.componentType);
const IndexTypeArray = GLTFUtils.getComponentType(indices.componentType);
const indexLength = indicesByteLength / IndexTypeArray.BYTES_PER_ELEMENT;
const indicesArray = new IndexTypeArray(indicesUint8Array.buffer, indicesByteOffset, indexLength);
restoreInfo.sparseIndices = new RestoreDataAccessor(
indicesBufferView.buffer,
IndexTypeArray,
indicesByteOffset,
indexLength
);
const indexLength = indicesByteLength / IndexTypeArray.BYTES_PER_ELEMENT;
const indicesArray = new IndexTypeArray(indicesUint8Array.buffer, indicesByteOffset, indexLength);
restoreInfo.sparseIndices = new RestoreDataAccessor(
indicesBufferView.buffer,
IndexTypeArray,
indicesByteOffset,
indexLength
);
const valueLength = valuesByteLength / TypedArray.BYTES_PER_ELEMENT;
const valuesArray = new TypedArray(valuesUin8Array.buffer, valuesByteOffset, valueLength);
restoreInfo.sparseValues = new RestoreDataAccessor(
valuesBufferView.buffer,
TypedArray,
valuesByteOffset,
valueLength
);
const valueLength = valuesByteLength / TypedArray.BYTES_PER_ELEMENT;
const valuesArray = new TypedArray(valuesUin8Array.buffer, valuesByteOffset, valueLength);
restoreInfo.sparseValues = new RestoreDataAccessor(
valuesBufferView.buffer,
TypedArray,
valuesByteOffset,
valueLength
);
for (let i = 0; i < count; i++) {
const replaceIndex = indicesArray[i];
for (let j = 0; j < accessorTypeSize; j++) {
data[replaceIndex * accessorTypeSize + j] = valuesArray[i * accessorTypeSize + j];
for (let i = 0; i < count; i++) {
const replaceIndex = indicesArray[i];
for (let j = 0; j < accessorTypeSize; j++) {
data[replaceIndex * accessorTypeSize + j] = valuesArray[i * accessorTypeSize + j];
}
}
}
bufferInfo.data = data;
});
bufferInfo.data = data;
})
.catch((e) => {
Logger.error("GLTFUtil processingSparseData error", e);
});
}
static getIndexFormat(type: AccessorComponentType): IndexFormat {

View File

@@ -1,3 +1,4 @@
import { AssetPromise, Logger } from "@galacean/engine-core";
import { registerGLTFExtension } from "../parser/GLTFParser";
import { GLTFParserContext, GLTFParserType } from "../parser/GLTFParserContext";
import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser";
@@ -6,18 +7,23 @@ import { getMeshoptDecoder } from "./MeshoptDecoder";
@registerGLTFExtension("EXT_meshopt_compression", GLTFExtensionMode.CreateAndParse)
class EXT_meshopt_compression extends GLTFExtensionParser {
override createAndParse(context: GLTFParserContext, schema: IEXTMeshoptCompressionSchema): Promise<Uint8Array> {
return context.get<ArrayBuffer>(GLTFParserType.Buffer, schema.buffer).then((arrayBuffer) => {
return getMeshoptDecoder().then((decoder) =>
decoder.decodeGltfBuffer(
schema.count,
schema.byteStride,
new Uint8Array(arrayBuffer, schema.byteOffset, schema.byteLength),
schema.mode,
schema.filter
)
);
});
override createAndParse(context: GLTFParserContext, schema: IEXTMeshoptCompressionSchema): AssetPromise<Uint8Array> {
return context
.get<ArrayBuffer>(GLTFParserType.Buffer, schema.buffer)
.then((arrayBuffer) => {
return getMeshoptDecoder().then((decoder) =>
decoder.decodeGltfBuffer(
schema.count,
schema.byteStride,
new Uint8Array(arrayBuffer, schema.byteOffset, schema.byteLength),
schema.mode,
schema.filter
)
);
})
.catch((e) => {
Logger.error("EXT_meshopt_compression: buffer error", e);
});
}
}

View File

@@ -1,4 +1,4 @@
import { SystemInfo, Texture2D } from "@galacean/engine-core";
import { AssetPromise, SystemInfo, Texture2D } from "@galacean/engine-core";
import type { ITexture } from "../GLTFSchema";
import { registerGLTFExtension } from "../parser/GLTFParser";
import { GLTFParserContext } from "../parser/GLTFParserContext";
@@ -26,13 +26,13 @@ class EXT_texture_webp extends GLTFExtensionParser {
}
}
override async createAndParse(
override createAndParse(
context: GLTFParserContext,
schema: EXTWebPSchema,
textureInfo: ITexture,
textureIndex: number,
isSRGBColorSpace: boolean
): Promise<Texture2D> {
): AssetPromise<Texture2D> {
const webPIndex = schema.source;
const { sampler, source: fallbackIndex = 0, name: textureName } = textureInfo;
const texture = GLTFTextureParser._parseTexture(

View File

@@ -1,4 +1,4 @@
import { Material } from "@galacean/engine-core";
import { AssetPromise, Material } from "@galacean/engine-core";
import { registerGLTFExtension } from "../parser/GLTFParser";
import { GLTFParserContext } from "../parser/GLTFParserContext";
import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser";
@@ -6,7 +6,7 @@ import { IGalaceanMaterialRemap } from "./GLTFExtensionSchema";
@registerGLTFExtension("GALACEAN_materials_remap", GLTFExtensionMode.CreateAndParse)
class GALACEAN_materials_remap extends GLTFExtensionParser {
override createAndParse(context: GLTFParserContext, schema: IGalaceanMaterialRemap): Promise<Material> {
override createAndParse(context: GLTFParserContext, schema: IGalaceanMaterialRemap): AssetPromise<Material> {
const { engine } = context.glTFResource;
// @ts-ignore
const promise = engine.resourceManager.getResourceByRef<Material>(schema);

View File

@@ -1,4 +1,4 @@
import { EngineObject } from "@galacean/engine-core";
import { AssetPromise, EngineObject } from "@galacean/engine-core";
import { GLTFExtensionOwnerSchema } from "../GLTFSchema";
import { GLTFParserContext } from "../parser/GLTFParserContext";
import { GLTFExtensionSchema } from "./GLTFExtensionSchema";
@@ -26,7 +26,7 @@ export abstract class GLTFExtensionParser {
extensionSchema: GLTFExtensionSchema,
extensionOwnerSchema: GLTFExtensionOwnerSchema,
...extra
): EngineObject | Promise<EngineObject | Uint8Array> {
): EngineObject | AssetPromise<EngineObject | Uint8Array> {
throw "Not implemented.";
}
@@ -44,7 +44,7 @@ export abstract class GLTFExtensionParser {
extensionSchema: GLTFExtensionSchema,
extensionOwnerSchema: GLTFExtensionOwnerSchema,
...extra
): void | Promise<void> {
): void | AssetPromise<void> {
throw "Not implemented.";
}
}

View File

@@ -1,4 +1,4 @@
import { PBRMaterial, Texture2D } from "@galacean/engine-core";
import { Logger, PBRMaterial, Texture2D } from "@galacean/engine-core";
import { GLTFMaterialParser } from "../parser/GLTFMaterialParser";
import { registerGLTFExtension } from "../parser/GLTFParser";
import { GLTFParserContext, GLTFParserType } from "../parser/GLTFParserContext";
@@ -16,9 +16,14 @@ class KHR_materials_anisotropy extends GLTFExtensionParser {
if (anisotropyTexture) {
GLTFMaterialParser._checkOtherTextureTransform(anisotropyTexture, "Anisotropy texture");
context.get<Texture2D>(GLTFParserType.Texture, anisotropyTexture.index).then((texture) => {
material.anisotropyTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, anisotropyTexture.index)
.then((texture) => {
material.anisotropyTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_anisotropy: anisotropy texture error", e);
});
}
}
}

View File

@@ -1,4 +1,4 @@
import { PBRMaterial, Texture2D } from "@galacean/engine-core";
import { Logger, PBRMaterial, Texture2D } from "@galacean/engine-core";
import { GLTFMaterialParser } from "../parser/GLTFMaterialParser";
import { registerGLTFExtension } from "../parser/GLTFParser";
import { GLTFParserContext, GLTFParserType } from "../parser/GLTFParserContext";
@@ -22,23 +22,38 @@ class KHR_materials_clearcoat extends GLTFExtensionParser {
if (clearcoatTexture) {
GLTFMaterialParser._checkOtherTextureTransform(clearcoatTexture, "Clear coat");
context.get<Texture2D>(GLTFParserType.Texture, clearcoatTexture.index).then((texture) => {
material.clearCoatTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, clearcoatTexture.index)
.then((texture) => {
material.clearCoatTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_clearcoat: clearcoat texture error", e);
});
}
if (clearcoatRoughnessTexture) {
GLTFMaterialParser._checkOtherTextureTransform(clearcoatRoughnessTexture, "Clear coat roughness");
context.get<Texture2D>(GLTFParserType.Texture, clearcoatRoughnessTexture.index).then((texture) => {
material.clearCoatRoughnessTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, clearcoatRoughnessTexture.index)
.then((texture) => {
material.clearCoatRoughnessTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_clearcoat: clearcoat roughness texture error", e);
});
}
if (clearcoatNormalTexture) {
GLTFMaterialParser._checkOtherTextureTransform(clearcoatNormalTexture, "Clear coat normal");
context.get<Texture2D>(GLTFParserType.Texture, clearcoatNormalTexture.index).then((texture) => {
material.clearCoatNormalTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, clearcoatNormalTexture.index)
.then((texture) => {
material.clearCoatNormalTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_clearcoat: clearcoat normal texture error", e);
});
}
}
}

View File

@@ -1,4 +1,4 @@
import { PBRMaterial, Texture2D } from "@galacean/engine-core";
import { Logger, PBRMaterial, Texture2D } from "@galacean/engine-core";
import { GLTFMaterialParser } from "../parser/GLTFMaterialParser";
import { registerGLTFExtension } from "../parser/GLTFParser";
import { GLTFParserContext, GLTFParserType } from "../parser/GLTFParserContext";
@@ -24,16 +24,26 @@ class KHR_materials_iridescence extends GLTFExtensionParser {
if (iridescenceTexture) {
GLTFMaterialParser._checkOtherTextureTransform(iridescenceTexture, "Iridescence texture");
context.get<Texture2D>(GLTFParserType.Texture, iridescenceTexture.index).then((texture) => {
material.iridescenceTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, iridescenceTexture.index)
.then((texture) => {
material.iridescenceTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_iridescence: iridescence texture error", e);
});
}
if (iridescenceThicknessTexture) {
GLTFMaterialParser._checkOtherTextureTransform(iridescenceThicknessTexture, "IridescenceThickness texture");
context.get<Texture2D>(GLTFParserType.Texture, iridescenceThicknessTexture.index).then((texture) => {
material.iridescenceThicknessTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, iridescenceThicknessTexture.index)
.then((texture) => {
material.iridescenceThicknessTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_iridescence: iridescence thickness error", e);
});
}
}
}

View File

@@ -1,4 +1,4 @@
import { PBRSpecularMaterial, Texture2D } from "@galacean/engine-core";
import { Logger, PBRSpecularMaterial, Texture2D } from "@galacean/engine-core";
import { Color } from "@galacean/engine-math";
import type { IMaterial } from "../GLTFSchema";
import { GLTFMaterialParser } from "../parser/GLTFMaterialParser";
@@ -28,10 +28,15 @@ class KHR_materials_pbrSpecularGlossiness extends GLTFExtensionParser {
}
if (diffuseTexture) {
context.get<Texture2D>(GLTFParserType.Texture, diffuseTexture.index).then((texture) => {
material.baseTexture = texture;
GLTFParser.executeExtensionsAdditiveAndParse(diffuseTexture.extensions, context, material, diffuseTexture);
});
context
.get<Texture2D>(GLTFParserType.Texture, diffuseTexture.index)
.then((texture) => {
material.baseTexture = texture;
GLTFParser.executeExtensionsAdditiveAndParse(diffuseTexture.extensions, context, material, diffuseTexture);
})
.catch((e) => {
Logger.error("KHR_materials_pbrSpecularGlossiness: diffuse texture error", e);
});
}
if (specularFactor) {
@@ -49,9 +54,14 @@ class KHR_materials_pbrSpecularGlossiness extends GLTFExtensionParser {
if (specularGlossinessTexture) {
GLTFMaterialParser._checkOtherTextureTransform(specularGlossinessTexture, "Specular glossiness");
context.get<Texture2D>(GLTFParserType.Texture, specularGlossinessTexture.index).then((texture) => {
material.specularGlossinessTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, specularGlossinessTexture.index)
.then((texture) => {
material.specularGlossinessTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_pbrSpecularGlossiness: specular glossiness texture error", e);
});
}
material.name = ownerSchema.name;

View File

@@ -1,4 +1,4 @@
import { PBRMaterial, Texture2D } from "@galacean/engine-core";
import { Logger, PBRMaterial, Texture2D } from "@galacean/engine-core";
import { Color } from "@galacean/engine-math";
import { GLTFMaterialParser } from "../parser/GLTFMaterialParser";
import { registerGLTFExtension } from "../parser/GLTFParser";
@@ -25,17 +25,27 @@ class KHR_materials_sheen extends GLTFExtensionParser {
if (sheenColorTexture) {
GLTFMaterialParser._checkOtherTextureTransform(sheenColorTexture, "Sheen texture");
context.get<Texture2D>(GLTFParserType.Texture, sheenColorTexture.index).then((texture) => {
material.sheenColorTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, sheenColorTexture.index)
.then((texture) => {
material.sheenColorTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_sheen: sheenColorTexture error", e);
});
}
if (sheenRoughnessTexture) {
GLTFMaterialParser._checkOtherTextureTransform(sheenRoughnessTexture, "SheenRoughness texture");
context.get<Texture2D>(GLTFParserType.Texture, sheenRoughnessTexture.index).then((texture) => {
material.sheenRoughnessTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, sheenRoughnessTexture.index)
.then((texture) => {
material.sheenRoughnessTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_sheen: sheenRoughnessTexture error", e);
});
}
}
}

View File

@@ -1,4 +1,4 @@
import { PBRMaterial, Texture2D } from "@galacean/engine-core";
import { Logger, PBRMaterial, Texture2D } from "@galacean/engine-core";
import { GLTFMaterialParser } from "../parser/GLTFMaterialParser";
import { registerGLTFExtension } from "../parser/GLTFParser";
import { GLTFParserContext, GLTFParserType } from "../parser/GLTFParserContext";
@@ -13,9 +13,14 @@ class KHR_materials_transmission extends GLTFExtensionParser {
if (transmissionTexture) {
GLTFMaterialParser._checkOtherTextureTransform(transmissionTexture, "Transmission texture");
context.get<Texture2D>(GLTFParserType.Texture, transmissionTexture.index).then((texture) => {
material.transmissionTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, transmissionTexture.index)
.then((texture) => {
material.transmissionTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_transmission: transmission texture error", e);
});
}
}
}

View File

@@ -1,4 +1,4 @@
import { Material, Renderer } from "@galacean/engine-core";
import { Logger, Material, Renderer } from "@galacean/engine-core";
import { registerGLTFExtension } from "../parser/GLTFParser";
import { GLTFParserContext, GLTFParserType } from "../parser/GLTFParserContext";
import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser";
@@ -29,13 +29,18 @@ class KHR_materials_variants extends GLTFExtensionParser {
for (let i = 0; i < mappings.length; i++) {
const { material: materialIndex, variants } = mappings[i];
context.get<Material>(GLTFParserType.Material, materialIndex).then((material) => {
extensionData.push({
renderer,
material,
variants: variants.map((index) => variantNames[index].name)
context
.get<Material>(GLTFParserType.Material, materialIndex)
.then((material) => {
extensionData.push({
renderer,
material,
variants: variants.map((index) => variantNames[index].name)
});
})
.catch((e) => {
Logger.error("KHR_materials_variants: material error", e);
});
});
}
}
}

View File

@@ -1,4 +1,4 @@
import { PBRMaterial, Texture2D } from "@galacean/engine-core";
import { Logger, PBRMaterial, Texture2D } from "@galacean/engine-core";
import { Color } from "@galacean/engine-math";
import { GLTFMaterialParser } from "../parser/GLTFMaterialParser";
import { registerGLTFExtension } from "../parser/GLTFParser";
@@ -25,9 +25,14 @@ class KHR_materials_volume extends GLTFExtensionParser {
if (thicknessTexture) {
GLTFMaterialParser._checkOtherTextureTransform(thicknessTexture, "Thickness texture");
context.get<Texture2D>(GLTFParserType.Texture, thicknessTexture.index).then((texture) => {
material.thicknessTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, thicknessTexture.index)
.then((texture) => {
material.thicknessTexture = texture;
})
.catch((e) => {
Logger.error("KHR_materials_volume: thickness texture error", e);
});
}
}
}

View File

@@ -1,11 +1,11 @@
import { AssetType, Texture2D, Utils } from "@galacean/engine-core";
import { AssetPromise, AssetType, Logger, Texture2D, Utils } from "@galacean/engine-core";
import { BufferTextureRestoreInfo } from "../../GLTFContentRestorer";
import { KTX2Loader } from "../../ktx2/KTX2Loader";
import type { ITexture } from "../GLTFSchema";
import { GLTFUtils } from "../GLTFUtils";
import { registerGLTFExtension } from "../parser/GLTFParser";
import { GLTFParserContext, GLTFParserType } from "../parser/GLTFParserContext";
import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser";
import { GLTFUtils } from "../GLTFUtils";
import { BufferTextureRestoreInfo } from "../../GLTFContentRestorer";
import { KTX2Loader } from "../../ktx2/KTX2Loader";
interface KHRBasisSchema {
source: number;
@@ -13,11 +13,11 @@ interface KHRBasisSchema {
@registerGLTFExtension("KHR_texture_basisu", GLTFExtensionMode.CreateAndParse)
class KHR_texture_basisu extends GLTFExtensionParser {
override async createAndParse(
override createAndParse(
context: GLTFParserContext,
schema: KHRBasisSchema,
textureInfo: ITexture
): Promise<Texture2D> {
): AssetPromise<Texture2D> {
const { glTF, glTFResource } = context;
const { engine, url } = glTFResource;
@@ -48,23 +48,28 @@ class KHR_texture_basisu extends GLTFExtensionParser {
} else {
const bufferView = glTF.bufferViews[bufferViewIndex];
return context.get<ArrayBuffer>(GLTFParserType.Buffer, bufferView.buffer).then((buffer) => {
const imageBuffer = new Uint8Array(buffer, bufferView.byteOffset, bufferView.byteLength);
return context
.get<ArrayBuffer>(GLTFParserType.Buffer, bufferView.buffer)
.then((buffer) => {
const imageBuffer = new Uint8Array(buffer, bufferView.byteOffset, bufferView.byteLength);
return KTX2Loader._parseBuffer(imageBuffer, engine)
.then(({ ktx2Container, engine, result, targetFormat, params }) =>
KTX2Loader._createTextureByBuffer(engine, ktx2Container.isSRGB, result, targetFormat, params)
)
.then((texture: Texture2D) => {
texture.name = textureName || imageName || `texture_${bufferViewIndex}`;
if (sampler !== undefined) {
GLTFUtils.parseSampler(texture, samplerInfo);
}
const bufferTextureRestoreInfo = new BufferTextureRestoreInfo(texture, bufferView, mimeType);
context.contentRestorer.bufferTextures.push(bufferTextureRestoreInfo);
return texture;
});
});
return KTX2Loader._parseBuffer(imageBuffer, engine)
.then(({ ktx2Container, engine, result, targetFormat, params }) =>
KTX2Loader._createTextureByBuffer(engine, ktx2Container.isSRGB, result, targetFormat, params)
)
.then((texture: Texture2D) => {
texture.name = textureName || imageName || `texture_${bufferViewIndex}`;
if (sampler !== undefined) {
GLTFUtils.parseSampler(texture, samplerInfo);
}
const bufferTextureRestoreInfo = new BufferTextureRestoreInfo(texture, bufferView, mimeType);
context.contentRestorer.bufferTextures.push(bufferTextureRestoreInfo);
return texture;
});
})
.catch((e) => {
Logger.error("KHR_texture_basisu: buffer error", e);
});
}
}
}

View File

@@ -3,6 +3,7 @@ import {
AnimationFloatArrayCurve,
AnimationQuaternionCurve,
AnimationVector3Curve,
AssetPromise,
Component,
Entity,
InterpolationType,
@@ -32,7 +33,7 @@ export class GLTFAnimationParser extends GLTFParser {
context: GLTFParserContext,
animationClip: AnimationClip,
animationInfo: IAnimation
): Promise<AnimationClip> {
): AssetPromise<AnimationClip> {
const { glTF } = context;
const { accessors, bufferViews } = glTF;
const { channels, samplers } = animationInfo;
@@ -41,7 +42,7 @@ export class GLTFAnimationParser extends GLTFParser {
const entities = context.get<Entity>(GLTFParserType.Entity);
let duration = -1;
let promises = new Array<Promise<void | Entity[]>>();
let promises = new Array<AssetPromise<void | Entity[]>>();
// parse samplers
for (let j = 0, m = len; j < m; j++) {
@@ -49,7 +50,7 @@ export class GLTFAnimationParser extends GLTFParser {
const inputAccessor = accessors[glTFSampler.input];
const outputAccessor = accessors[glTFSampler.output];
const promise = Promise.all([
const promise = AssetPromise.all([
GLTFUtils.getAccessorBuffer(context, bufferViews, inputAccessor),
GLTFUtils.getAccessorBuffer(context, bufferViews, outputAccessor)
]).then((bufferInfos) => {
@@ -98,7 +99,7 @@ export class GLTFAnimationParser extends GLTFParser {
promises.push(context.get<Entity>(GLTFParserType.Scene));
return Promise.all(promises).then(() => {
return AssetPromise.all(promises).then(() => {
for (let j = 0, m = channels.length; j < m; j++) {
const glTFChannel = channels[j];
const { target } = glTFChannel;
@@ -227,16 +228,16 @@ export class GLTFAnimationParser extends GLTFParser {
}
}
parse(context: GLTFParserContext, index: number): Promise<AnimationClip> {
parse(context: GLTFParserContext, index: number): AssetPromise<AnimationClip> {
const animationInfo = context.glTF.animations[index];
const { name = `AnimationClip${index}` } = animationInfo;
const animationClipPromise =
<Promise<AnimationClip> | AnimationClip>(
<AssetPromise<AnimationClip> | AnimationClip>(
GLTFParser.executeExtensionsCreateAndParse(animationInfo.extensions, context, animationInfo)
) || GLTFAnimationParser._parseStandardProperty(context, new AnimationClip(name), animationInfo);
return Promise.resolve(animationClipPromise).then((animationClip) => {
return AssetPromise.resolve(animationClipPromise).then((animationClip) => {
GLTFParser.executeExtensionsAdditiveAndParse(animationInfo.extensions, context, animationClip, animationInfo);
return animationClip;
});

View File

@@ -2,22 +2,29 @@ import {
AnimationClip,
AnimatorController,
AnimatorControllerLayer,
AnimatorStateMachine
AnimatorStateMachine,
AssetPromise,
Logger
} from "@galacean/engine-core";
import { GLTFParser } from "./GLTFParser";
import { GLTFParserContext, GLTFParserType, registerGLTFParser } from "./GLTFParserContext";
@registerGLTFParser(GLTFParserType.AnimatorController)
export class GLTFAnimatorControllerParser extends GLTFParser {
parse(context: GLTFParserContext): Promise<AnimatorController> {
parse(context: GLTFParserContext): AssetPromise<AnimatorController> {
if (!context.needAnimatorController) {
return Promise.resolve(null);
return AssetPromise.resolve(null);
}
return context.get<AnimationClip>(GLTFParserType.Animation).then((animations) => {
const animatorController = this._createAnimatorController(context, animations);
return Promise.resolve(animatorController);
});
return context
.get<AnimationClip>(GLTFParserType.Animation)
.then((animations) => {
const animatorController = this._createAnimatorController(context, animations);
return AssetPromise.resolve(animatorController);
})
.catch((e) => {
Logger.error("GLTFAnimatorControllerParser: animator controller error", e);
});
}
private _createAnimatorController(context: GLTFParserContext, animations: AnimationClip[]): AnimatorController {

View File

@@ -1,4 +1,4 @@
import { RequestConfig, Utils } from "@galacean/engine-core";
import { AssetPromise, RequestConfig, Utils } from "@galacean/engine-core";
import { BufferRequestInfo } from "../../GLTFContentRestorer";
import type { IBuffer } from "../GLTFSchema";
import { GLTFParser } from "./GLTFParser";
@@ -6,13 +6,15 @@ import { GLTFParserContext, GLTFParserType, registerGLTFParser } from "./GLTFPar
@registerGLTFParser(GLTFParserType.Buffer)
export class GLTFBufferParser extends GLTFParser {
parse(context: GLTFParserContext, index: number): Promise<ArrayBuffer> {
parse(context: GLTFParserContext, index: number): AssetPromise<ArrayBuffer> {
const buffers = context.glTF.buffers;
return context.buffers ? Promise.resolve(context.buffers[index]) : this._parseSingleBuffer(context, buffers[index]);
return context.buffers
? AssetPromise.resolve(context.buffers[index])
: this._parseSingleBuffer(context, buffers[index]);
}
private _parseSingleBuffer(context: GLTFParserContext, bufferInfo: IBuffer): Promise<ArrayBuffer> {
private _parseSingleBuffer(context: GLTFParserContext, bufferInfo: IBuffer): AssetPromise<ArrayBuffer> {
const { glTFResource, contentRestorer, resourceManager } = context;
const url = glTFResource.url;
// @ts-ignore

View File

@@ -1,15 +1,19 @@
import { registerGLTFParser, GLTFParserType, GLTFParserContext } from "./GLTFParserContext";
import { AssetPromise, Logger } from "@galacean/engine-core";
import { GLTFParser } from "./GLTFParser";
import { GLTFParserContext, GLTFParserType, registerGLTFParser } from "./GLTFParserContext";
@registerGLTFParser(GLTFParserType.BufferView)
export class GLTFBufferViewParser extends GLTFParser {
parse(context: GLTFParserContext, index: number): Promise<Uint8Array> {
parse(context: GLTFParserContext, index: number): AssetPromise<Uint8Array> {
const bufferView = context.glTF.bufferViews[index];
const { extensions, byteOffset = 0, byteLength, buffer: bufferIndex } = bufferView;
return extensions
? <Promise<Uint8Array>>GLTFParser.executeExtensionsCreateAndParse(extensions, context, bufferView)
? <AssetPromise<Uint8Array>>GLTFParser.executeExtensionsCreateAndParse(extensions, context, bufferView)
: context
.get<ArrayBuffer>(GLTFParserType.Buffer, bufferIndex)
.then((buffer) => new Uint8Array(buffer, byteOffset, byteLength));
.then((buffer) => new Uint8Array(buffer, byteOffset, byteLength))
.catch((e) => {
Logger.error("GLTFBufferViewParser: buffer error", e);
});
}
}

View File

@@ -1,6 +1,5 @@
import {
BlinnPhongMaterial,
Engine,
AssetPromise,
Logger,
Material,
PBRMaterial,
@@ -17,12 +16,6 @@ import { GLTFParserContext, GLTFParserType, registerGLTFParser } from "./GLTFPar
@registerGLTFParser(GLTFParserType.Material)
export class GLTFMaterialParser extends GLTFParser {
/** @internal */
static _getDefaultMaterial(engine: Engine): BlinnPhongMaterial {
return (GLTFMaterialParser._defaultMaterial ||= new BlinnPhongMaterial(engine));
}
private static _defaultMaterial: BlinnPhongMaterial;
/**
* @internal
*/
@@ -64,15 +57,20 @@ export class GLTFMaterialParser extends GLTFParser {
);
}
if (baseColorTexture) {
context.get<Texture2D>(GLTFParserType.Texture, baseColorTexture.index).then((texture) => {
material.baseTexture = texture;
GLTFParser.executeExtensionsAdditiveAndParse(
baseColorTexture.extensions,
context,
material,
baseColorTexture
);
});
context
.get<Texture2D>(GLTFParserType.Texture, baseColorTexture.index)
.then((texture) => {
material.baseTexture = texture;
GLTFParser.executeExtensionsAdditiveAndParse(
baseColorTexture.extensions,
context,
material,
baseColorTexture
);
})
.catch((e) => {
Logger.error("GLTFMaterialParser: baseColorTexture error", e);
});
}
if (material.constructor === PBRMaterial) {
@@ -80,10 +78,14 @@ export class GLTFMaterialParser extends GLTFParser {
material.roughness = roughnessFactor ?? 1;
if (metallicRoughnessTexture) {
GLTFMaterialParser._checkOtherTextureTransform(metallicRoughnessTexture, "Roughness metallic");
context.get<Texture2D>(GLTFParserType.Texture, metallicRoughnessTexture.index).then((texture) => {
material.roughnessMetallicTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, metallicRoughnessTexture.index)
.then((texture) => {
material.roughnessMetallicTexture = texture;
})
.catch((e) => {
Logger.error("GLTFMaterialParser: metallicRoughnessTexture error", e);
});
}
}
}
@@ -91,10 +93,14 @@ export class GLTFMaterialParser extends GLTFParser {
if (material.constructor === PBRMaterial || material.constructor === PBRSpecularMaterial) {
if (emissiveTexture) {
GLTFMaterialParser._checkOtherTextureTransform(emissiveTexture, "Emissive");
context.get<Texture2D>(GLTFParserType.Texture, emissiveTexture.index).then((texture) => {
material.emissiveTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, emissiveTexture.index)
.then((texture) => {
material.emissiveTexture = texture;
})
.catch((e) => {
Logger.error("GLTFMaterialParser: emissiveTexture error", e);
});
}
if (emissiveFactor) {
@@ -109,9 +115,14 @@ export class GLTFMaterialParser extends GLTFParser {
const { index, scale } = normalTexture;
GLTFMaterialParser._checkOtherTextureTransform(normalTexture, "Normal");
context.get<Texture2D>(GLTFParserType.Texture, index).then((texture) => {
material.normalTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, index)
.then((texture) => {
material.normalTexture = texture;
})
.catch((e) => {
Logger.error("GLTFMaterialParser: emissiveTexture error", e);
});
if (scale !== undefined) {
material.normalTextureIntensity = scale;
@@ -122,9 +133,14 @@ export class GLTFMaterialParser extends GLTFParser {
const { index, strength, texCoord } = occlusionTexture;
GLTFMaterialParser._checkOtherTextureTransform(occlusionTexture, "Occlusion");
context.get<Texture2D>(GLTFParserType.Texture, index).then((texture) => {
material.occlusionTexture = texture;
});
context
.get<Texture2D>(GLTFParserType.Texture, index)
.then((texture) => {
material.occlusionTexture = texture;
})
.catch((e) => {
Logger.error("GLTFMaterialParser: occlusionTexture error", e);
});
if (strength !== undefined) {
material.occlusionTextureIntensity = strength;
@@ -156,7 +172,7 @@ export class GLTFMaterialParser extends GLTFParser {
}
}
parse(context: GLTFParserContext, index: number): Promise<Material> {
parse(context: GLTFParserContext, index: number): AssetPromise<Material> {
const materialInfo = context.glTF.materials[index];
const glTFResource = context.glTFResource;
const engine = glTFResource.engine;
@@ -171,8 +187,9 @@ export class GLTFMaterialParser extends GLTFParser {
GLTFMaterialParser._parseStandardProperty(context, material as PBRMaterial, materialInfo);
}
return Promise.resolve(material).then((material) => {
material ||= GLTFMaterialParser._getDefaultMaterial(engine);
return AssetPromise.resolve(material).then((material) => {
// @ts-ignore
material ||= engine._basicResources._getBlinnPhongMaterial();
GLTFParser.executeExtensionsAdditiveAndParse(materialInfo.extensions, context, material, materialInfo);
// @ts-ignore
material._associationSuperResource(glTFResource);

View File

@@ -1,4 +1,12 @@
import { BlendShape, Buffer, BufferBindFlag, BufferUsage, ModelMesh, VertexElement } from "@galacean/engine-core";
import {
AssetPromise,
BlendShape,
Buffer,
BufferBindFlag,
BufferUsage,
ModelMesh,
VertexElement
} from "@galacean/engine-core";
import { Vector3 } from "@galacean/engine-math";
import {
BlendShapeDataRestoreInfo,
@@ -26,7 +34,7 @@ export class GLTFMeshParser extends GLTFParser {
gltfPrimitive: IMeshPrimitive,
gltf: IGLTF,
keepMeshData: boolean
): Promise<ModelMesh> {
): AssetPromise<ModelMesh> {
const { accessors } = gltf;
const { attributes, targets, indices, mode } = gltfPrimitive;
const engine = mesh.engine;
@@ -35,7 +43,7 @@ export class GLTFMeshParser extends GLTFParser {
let vertexCount: number;
let bufferBindIndex = 0;
const promises = new Array<Promise<void>>();
const promises = new Array<AssetPromise<void>>();
for (const attribute in attributes) {
const accessor = accessors[attributes[attribute]];
const promise = GLTFUtils.getAccessorBuffer(context, gltf.bufferViews, accessor).then((accessorBuffer) => {
@@ -121,7 +129,7 @@ export class GLTFMeshParser extends GLTFParser {
promises.push(promise);
}
return Promise.all(promises).then(() => {
return AssetPromise.all(promises).then(() => {
mesh.setVertexElements(vertexElements);
// Indices
@@ -155,7 +163,7 @@ export class GLTFMeshParser extends GLTFParser {
context: GLTFParserContext,
glTF: IGLTF,
accessor: IAccessor
): Promise<{ vertices: Vector3[]; restoreInfo: BlendShapeDataRestoreInfo }> {
): AssetPromise<{ vertices: Vector3[]; restoreInfo: BlendShapeDataRestoreInfo }> {
return GLTFUtils.getAccessorBuffer(context, glTF.bufferViews, accessor).then((bufferInfo) => {
const buffer = bufferInfo.data;
const byteOffset = bufferInfo.interleaved ? (accessor.byteOffset ?? 0) % bufferInfo.stride : 0;
@@ -186,11 +194,11 @@ export class GLTFMeshParser extends GLTFParser {
glTFTargets: {
[name: string]: number;
}[]
): Promise<void> {
): AssetPromise<void> {
const glTF = context.glTF;
const accessors = glTF.accessors;
const blendShapeNames = glTFMesh.extras ? glTFMesh.extras.targetNames : null;
let promises = new Array<Promise<void>>();
let promises = new Array<AssetPromise<void>>();
const blendShapeCount = glTFTargets.length;
const blendShapeCollection = new Array<BlendShapeData>(blendShapeCount);
@@ -206,13 +214,12 @@ export class GLTFMeshParser extends GLTFParser {
const hasNormal = normalTarget !== undefined;
const hasTangent = tangentTarget !== undefined;
const promise = Promise.all([
const promise = AssetPromise.all([
this._getBlendShapeData(context, glTF, accessors[targets["POSITION"]]),
hasNormal ? this._getBlendShapeData(context, glTF, accessors[normalTarget]) : null,
hasTangent ? this._getBlendShapeData(context, glTF, accessors[tangentTarget]) : null
]).then((vertices) => {
const [positionData, normalData, tangentData] = vertices;
const blendShape = new BlendShape(name);
blendShape.addFrame(
1.0,
@@ -232,7 +239,7 @@ export class GLTFMeshParser extends GLTFParser {
promises.push(promise);
}
return Promise.all(promises).then(() => {
return AssetPromise.all(promises).then(() => {
for (const blendShape of blendShapeCollection) {
mesh.addBlendShape(blendShape.blendShape);
meshRestoreInfo.blendShapes.push(blendShape.restoreInfo);
@@ -240,18 +247,17 @@ export class GLTFMeshParser extends GLTFParser {
});
}
parse(context: GLTFParserContext, index: number): Promise<ModelMesh[]> {
parse(context: GLTFParserContext, index: number): AssetPromise<ModelMesh[]> {
const meshInfo = context.glTF.meshes[index];
const { glTF, glTFResource } = context;
const engine = glTFResource.engine;
const primitivePromises = new Array<Promise<ModelMesh>>();
const primitivePromises = new Array<AssetPromise<ModelMesh>>();
for (let i = 0, length = meshInfo.primitives.length; i < length; i++) {
const gltfPrimitive = meshInfo.primitives[i];
primitivePromises[i] = new Promise((resolve) => {
const mesh = <ModelMesh | Promise<ModelMesh>>(
primitivePromises[i] = new AssetPromise((resolve, reject) => {
const mesh = <ModelMesh | AssetPromise<ModelMesh>>(
GLTFParser.executeExtensionsCreateAndParse(gltfPrimitive.extensions, context, gltfPrimitive, meshInfo)
);
@@ -284,12 +290,12 @@ export class GLTFMeshParser extends GLTFParser {
gltfPrimitive,
glTF,
context.params.keepMeshData
).then(resolve);
).then(resolve, reject);
}
});
}
return Promise.all(primitivePromises);
return AssetPromise.all(primitivePromises);
}
}

View File

@@ -1,4 +1,4 @@
import { AnimationClip, EngineObject, Material, Mesh } from "@galacean/engine-core";
import { AssetPromise, EngineObject } from "@galacean/engine-core";
import type { GLTFExtensionOwnerSchema } from "../GLTFSchema";
import { GLTFExtensionMode, GLTFExtensionParser } from "../extensions/GLTFExtensionParser";
import { GLTFExtensionSchema } from "../extensions/GLTFExtensionSchema";
@@ -23,15 +23,15 @@ export abstract class GLTFParser {
context: GLTFParserContext,
ownerSchema: GLTFExtensionOwnerSchema,
...extra
): EngineObject | void | Promise<EngineObject | Uint8Array | void> {
let resource: EngineObject | Promise<EngineObject> = null;
): EngineObject | void | AssetPromise<EngineObject | Uint8Array | void> {
let resource: EngineObject | AssetPromise<EngineObject> = null;
const extensionArray = Object.keys(extensions);
for (let i = extensionArray.length - 1; i >= 0; --i) {
const extensionName = extensionArray[i];
const extensionSchema = extensions[extensionName];
resource = <EngineObject | Promise<EngineObject>>(
resource = <EngineObject | AssetPromise<EngineObject>>(
GLTFParser._createAndParse(extensionName, context, extensionSchema, ownerSchema, ...extra)
);
if (resource) {
@@ -107,7 +107,7 @@ export abstract class GLTFParser {
extensionSchema: GLTFExtensionSchema,
ownerSchema: GLTFExtensionOwnerSchema,
...extra
): EngineObject | Uint8Array | Promise<EngineObject | Uint8Array> {
): EngineObject | Uint8Array | AssetPromise<EngineObject | Uint8Array> {
const parser = GLTFParser.getExtensionParser(extensionName, GLTFExtensionMode.CreateAndParse);
if (parser) {
@@ -124,10 +124,7 @@ export abstract class GLTFParser {
...extra
): void {
const parser = GLTFParser.getExtensionParser(extensionName, GLTFExtensionMode.AdditiveParse);
if (parser) {
parser.additiveParse(context, parseResource, extensionSchema, ownerSchema, ...extra);
}
parser?.additiveParse(context, parseResource, extensionSchema, ownerSchema, ...extra);
}
abstract parse(context: GLTFParserContext, index?: number);

View File

@@ -2,8 +2,10 @@ import {
AnimationClip,
Animator,
AnimatorController,
AssetPromise,
Buffer,
Entity,
Logger,
Material,
ModelMesh,
ResourceManager,
@@ -33,6 +35,9 @@ export class GLTFParserContext {
buffers?: ArrayBuffer[];
needAnimatorController = false;
/** @internal */
_getPromises: AssetPromise<unknown>[] = [];
private _resourceCache = new Map<string, any>();
private _progress = {
taskDetail: {},
@@ -54,21 +59,21 @@ export class GLTFParserContext {
get<T>(type: GLTFParserType.Entity, index: number): Entity;
get<T>(type: GLTFParserType.Entity): Entity[];
get<T>(type: GLTFParserType.Schema): Promise<T>;
get<T>(type: GLTFParserType.Validator): Promise<T>;
get<T>(type: GLTFParserType.AnimatorController): Promise<T>;
get<T>(type: GLTFParserType, index: number): Promise<T>;
get<T>(type: GLTFParserType): Promise<T[]>;
get<T>(type: GLTFParserType, index?: number): Entity | Entity[] | Promise<T> | Promise<T[]> {
get<T>(type: GLTFParserType.Schema): AssetPromise<T>;
get<T>(type: GLTFParserType.Validator): AssetPromise<T>;
get<T>(type: GLTFParserType.AnimatorController): AssetPromise<T>;
get<T>(type: GLTFParserType, index: number): AssetPromise<T>;
get<T>(type: GLTFParserType): AssetPromise<T[]>;
get<T>(type: GLTFParserType, index?: number): Entity | Entity[] | AssetPromise<T> | AssetPromise<T[]> {
const parser = GLTFParserContext._parsers[type];
if (!parser) {
return Promise.resolve(null);
return AssetPromise.resolve(null);
}
const cache = this._resourceCache;
const cacheKey = index === undefined ? `${type}` : `${type}:${index}`;
let resource: Entity | Entity[] | Promise<T> | Promise<T[]> = cache.get(cacheKey);
let resource: Entity | Entity[] | AssetPromise<T> | AssetPromise<T[]> = cache.get(cacheKey);
if (resource) {
return resource;
@@ -84,29 +89,32 @@ export class GLTFParserContext {
resource =
type === GLTFParserType.Entity
? <Entity[]>glTFItems.map((_, index) => this.get<Entity>(type, index))
: Promise.all<T>(glTFItems.map((_, index) => this.get<T>(type, index)));
: AssetPromise.all<T>(glTFItems.map((_, index) => this.get<T>(type, index)));
} else {
resource = parser.parse(this, index);
isSubAsset && this._handleSubAsset(resource, type, index);
}
} else {
resource = Promise.resolve<T>(null);
resource = AssetPromise.resolve<T>(null);
}
} else {
resource = parser.parse(this, index);
isSubAsset && this._handleSubAsset(resource, type, index);
}
if (resource instanceof AssetPromise) {
this._getPromises.push(resource);
}
cache.set(cacheKey, resource);
return resource;
}
parse(): Promise<GLTFResource> {
parse(): AssetPromise<GLTFResource> {
const promise = this.get<IGLTF>(GLTFParserType.Schema).then((json) => {
this.glTF = json;
this.needAnimatorController = !!(json.skins || json.animations);
return Promise.all([
return AssetPromise.all([
this.get<void>(GLTFParserType.Validator),
this.get<Texture2D>(GLTFParserType.Texture),
this.get<Material>(GLTFParserType.Material),
@@ -147,7 +155,7 @@ export class GLTFParserContext {
/**
* @internal
*/
_addTaskCompletePromise(taskPromise: Promise<any>): void {
_addTaskCompletePromise(taskPromise: PromiseLike<any>): void {
const task = this._progress.taskComplete;
task.total += 1;
taskPromise.then(
@@ -159,7 +167,7 @@ export class GLTFParserContext {
}
private _handleSubAsset<T>(
resource: Entity | Entity[] | Promise<T> | Promise<T[]>,
resource: Entity | Entity[] | AssetPromise<T> | AssetPromise<T[]>,
type: GLTFParserType,
index?: number
): void {
@@ -170,33 +178,37 @@ export class GLTFParserContext {
} else {
const url = this.glTFResource.url;
(<Promise<T>>resource).then((item: T) => {
if (index == undefined) {
this.glTFResource[glTFResourceKey] = item;
} else {
(this.glTFResource[glTFResourceKey] ||= [])[index] = item;
}
if (type === GLTFParserType.Mesh) {
for (let i = 0, length = (<ModelMesh[]>item).length; i < length; i++) {
const mesh = item[i] as ModelMesh;
// @ts-ignore
this.resourceManager._onSubAssetSuccess<ModelMesh>(url, `${glTFResourceKey}[${index}][${i}]`, mesh);
(<AssetPromise<T>>resource)
.then((item: T) => {
if (index == undefined) {
this.glTFResource[glTFResourceKey] = item;
} else {
(this.glTFResource[glTFResourceKey] ||= [])[index] = item;
}
} else {
// @ts-ignore
this.resourceManager._onSubAssetSuccess<T>(
url,
`${glTFResourceKey}${index === undefined ? "" : `[${index}]`}`,
item
);
if (type === GLTFParserType.Scene && (this.glTF.scene ?? 0) === index) {
if (type === GLTFParserType.Mesh) {
for (let i = 0, length = (<ModelMesh[]>item).length; i < length; i++) {
const mesh = item[i] as ModelMesh;
// @ts-ignore
this.resourceManager._onSubAssetSuccess<ModelMesh>(url, `${glTFResourceKey}[${index}][${i}]`, mesh);
}
} else {
// @ts-ignore
this.resourceManager._onSubAssetSuccess<Entity>(url, `defaultSceneRoot`, item as Entity);
this.resourceManager._onSubAssetSuccess<T>(
url,
`${glTFResourceKey}${index === undefined ? "" : `[${index}]`}`,
item
);
if (type === GLTFParserType.Scene && (this.glTF.scene ?? 0) === index) {
// @ts-ignore
this.resourceManager._onSubAssetSuccess<Entity>(url, `defaultSceneRoot`, item as Entity);
}
}
}
});
})
.catch((e) => {
Logger.error("GLTFParserContext", `Failed to load ${glTFResourceKey} ${index}: ${e}`);
});
}
}
}

View File

@@ -1,6 +1,8 @@
import {
AssetPromise,
Camera,
Entity,
Logger,
Material,
Mesh,
MeshRenderer,
@@ -11,13 +13,12 @@ import {
import { BoundingBox, Matrix } from "@galacean/engine-math";
import { GLTFResource } from "../GLTFResource";
import { CameraType, ICamera, INode } from "../GLTFSchema";
import { GLTFMaterialParser } from "./GLTFMaterialParser";
import { GLTFParser } from "./GLTFParser";
import { GLTFParserContext, GLTFParserType, registerGLTFParser } from "./GLTFParserContext";
@registerGLTFParser(GLTFParserType.Scene)
export class GLTFSceneParser extends GLTFParser {
parse(context: GLTFParserContext, index: number): Promise<Entity> {
parse(context: GLTFParserContext, index: number): AssetPromise<Entity> {
const {
glTF: { scenes, scene = 0 },
glTFResource
@@ -46,24 +47,24 @@ export class GLTFSceneParser extends GLTFParser {
glTFResource._defaultSceneRoot = sceneRoot;
}
const promises = new Array<Promise<void[]>>();
const promises = new Array<AssetPromise<void[]>>();
for (let i = 0; i < sceneNodes.length; i++) {
promises.push(this._parseEntityComponent(context, sceneNodes[i]));
}
return Promise.all(promises).then(() => {
return AssetPromise.all(promises).then(() => {
GLTFParser.executeExtensionsAdditiveAndParse(sceneExtensions, context, sceneRoot, sceneInfo);
return sceneRoot;
});
}
private _parseEntityComponent(context: GLTFParserContext, index: number): Promise<void[]> {
private _parseEntityComponent(context: GLTFParserContext, index: number): AssetPromise<void[]> {
const { glTF, glTFResource } = context;
const entityInfo = glTF.nodes[index];
const { camera: cameraID, mesh: meshID } = entityInfo;
const entity = context.get<Entity>(GLTFParserType.Entity, index);
let promise: Promise<void>;
let promise: AssetPromise<void>;
if (cameraID !== undefined) {
this._createCamera(glTFResource, glTF.cameras[cameraID], entity);
@@ -73,7 +74,7 @@ export class GLTFSceneParser extends GLTFParser {
promise = this._createRenderer(context, entityInfo, entity);
}
return Promise.resolve(promise).then(() => {
return AssetPromise.resolve(promise).then(() => {
const promises = [];
const children = entityInfo.children;
@@ -83,7 +84,7 @@ export class GLTFSceneParser extends GLTFParser {
}
}
return Promise.all(promises);
return AssetPromise.all(promises);
});
}
@@ -127,59 +128,65 @@ export class GLTFSceneParser extends GLTFParser {
camera.enabled = false;
}
private _createRenderer(context: GLTFParserContext, entityInfo: INode, entity: Entity): Promise<void> {
private _createRenderer(context: GLTFParserContext, entityInfo: INode, entity: Entity): AssetPromise<void> {
const { mesh: meshID, skin: skinID } = entityInfo;
const glTFMesh = context.glTF.meshes[meshID];
const glTFMeshPrimitives = glTFMesh.primitives;
const rendererCount = glTFMeshPrimitives.length;
const blendShapeWeights = entityInfo.weights || glTFMesh.weights;
const materialPromises = new Array<Promise<Material>>(rendererCount);
const materialPromises = new Array<AssetPromise<Material>>(rendererCount);
for (let i = 0; i < rendererCount; i++) {
materialPromises[i] = context.get<Material>(GLTFParserType.Material, glTFMeshPrimitives[i].material ?? -1);
}
return Promise.all([
return AssetPromise.all([
context.get<ModelMesh[]>(GLTFParserType.Mesh, meshID),
skinID !== undefined && context.get<Skin>(GLTFParserType.Skin, skinID),
Promise.all(materialPromises)
]).then(([meshes, skin, materials]) => {
for (let i = 0; i < rendererCount; i++) {
const material = materials[i] || GLTFMaterialParser._getDefaultMaterial(context.glTFResource.engine);
const glTFPrimitive = glTFMeshPrimitives[i];
const mesh = meshes[i];
AssetPromise.all(materialPromises)
])
.then(([meshes, skin, materials]) => {
// @ts-ignore
const basicResources = context.glTFResource.engine._basicResources;
for (let i = 0; i < rendererCount; i++) {
const material = materials[i] || basicResources._getBlinnPhongMaterial();
const glTFPrimitive = glTFMeshPrimitives[i];
const mesh = meshes[i];
let renderer: MeshRenderer | SkinnedMeshRenderer;
let renderer: MeshRenderer | SkinnedMeshRenderer;
if (skin || blendShapeWeights) {
const skinRenderer = entity.addComponent(SkinnedMeshRenderer);
skinRenderer.mesh = mesh;
if (skin) {
this._computeLocalBounds(skinRenderer, mesh, skin.bones, skin.rootBone, skin.inverseBindMatrices);
skinRenderer.skin = skin;
if (skin || blendShapeWeights) {
const skinRenderer = entity.addComponent(SkinnedMeshRenderer);
skinRenderer.mesh = mesh;
if (skin) {
this._computeLocalBounds(skinRenderer, mesh, skin.bones, skin.rootBone, skin.inverseBindMatrices);
skinRenderer.skin = skin;
}
if (blendShapeWeights) {
skinRenderer.blendShapeWeights = new Float32Array(blendShapeWeights);
}
renderer = skinRenderer;
} else {
renderer = entity.addComponent(MeshRenderer);
renderer.mesh = mesh;
}
if (blendShapeWeights) {
skinRenderer.blendShapeWeights = new Float32Array(blendShapeWeights);
}
renderer = skinRenderer;
} else {
renderer = entity.addComponent(MeshRenderer);
renderer.mesh = mesh;
renderer.setMaterial(material);
// Enable vertex color if mesh has COLOR_0 vertex element
mesh.vertexElements.forEach((element) => {
if (element.semantic === "COLOR_0") {
renderer.enableVertexColor = true;
}
});
GLTFParser.executeExtensionsAdditiveAndParse(glTFPrimitive.extensions, context, renderer, glTFPrimitive);
}
renderer.setMaterial(material);
// Enable vertex color if mesh has COLOR_0 vertex element
mesh.vertexElements.forEach((element) => {
if (element.semantic === "COLOR_0") {
renderer.enableVertexColor = true;
}
});
GLTFParser.executeExtensionsAdditiveAndParse(glTFPrimitive.extensions, context, renderer, glTFPrimitive);
}
});
})
.catch((e) => {
Logger.error("GLTFSceneParser: create renderer error", e);
});
}
private _computeLocalBounds(

View File

@@ -1,4 +1,4 @@
import { Entity, Skin } from "@galacean/engine-core";
import { AssetPromise, Entity, Skin } from "@galacean/engine-core";
import { Matrix } from "@galacean/engine-math";
import { GLTFUtils } from "../GLTFUtils";
import { GLTFParser } from "./GLTFParser";
@@ -6,7 +6,7 @@ import { GLTFParserContext, GLTFParserType, registerGLTFParser } from "./GLTFPar
@registerGLTFParser(GLTFParserType.Skin)
export class GLTFSkinParser extends GLTFParser {
parse(context: GLTFParserContext, index: number): Promise<Skin> {
parse(context: GLTFParserContext, index: number): AssetPromise<Skin> {
const glTF = context.glTF;
const skinInfo = glTF.skins[index];
const { inverseBindMatrices, skeleton, joints, name = `SKIN_${index}` } = skinInfo;
@@ -50,7 +50,7 @@ export class GLTFSkinParser extends GLTFParser {
return skin;
});
return Promise.resolve(skinPromise);
return AssetPromise.resolve(skinPromise);
}
private _findSkeletonRootBone(joints: number[], entities: Entity[]): Entity {

View File

@@ -1,4 +1,4 @@
import { AssetType, Texture, Texture2D, TextureWrapMode, Utils } from "@galacean/engine-core";
import { AssetPromise, AssetType, Logger, Texture, Texture2D, TextureWrapMode, Utils } from "@galacean/engine-core";
import { BufferTextureRestoreInfo } from "../../GLTFContentRestorer";
import { TextureWrapMode as GLTFTextureWrapMode, IMaterial } from "../GLTFSchema";
import { GLTFUtils } from "../GLTFUtils";
@@ -22,14 +22,14 @@ export class GLTFTextureParser extends GLTFParser {
sampler?: number,
textureName?: string,
isSRGBColorSpace?: boolean
): Promise<Texture2D> {
): AssetPromise<Texture2D> {
const { glTFResource, glTF } = context;
const { engine, url } = glTFResource;
const { uri, bufferView: bufferViewIndex, mimeType, name: imageName } = glTF.images[imageIndex];
const useSampler = sampler !== undefined;
const samplerInfo = useSampler && GLTFUtils.getSamplerInfo(glTF.samplers[sampler]);
let texture: Promise<Texture2D>;
let texture: AssetPromise<Texture2D>;
if (uri) {
const extIndex = uri.lastIndexOf(".");
@@ -54,44 +54,47 @@ export class GLTFTextureParser extends GLTFParser {
context._addTaskCompletePromise(texture);
} else {
const bufferView = glTF.bufferViews[bufferViewIndex];
texture = context
.get<ArrayBuffer>(GLTFParserType.Buffer)
.then((buffers) => {
const buffer = buffers[bufferView.buffer];
const imageBuffer = new Uint8Array(buffer, bufferView.byteOffset, bufferView.byteLength);
return GLTFUtils.loadImageBuffer(imageBuffer, mimeType).then((image) => {
const texture = new Texture2D(
engine,
image.width,
image.height,
undefined,
samplerInfo?.mipmap,
isSRGBColorSpace
);
texture.setImageSource(image);
texture.generateMipmaps();
texture = context.get<ArrayBuffer>(GLTFParserType.Buffer).then((buffers) => {
const buffer = buffers[bufferView.buffer];
const imageBuffer = new Uint8Array(buffer, bufferView.byteOffset, bufferView.byteLength);
texture.name = textureName || imageName || `texture_${textureIndex}`;
useSampler && GLTFUtils.parseSampler(texture, samplerInfo);
return GLTFUtils.loadImageBuffer(imageBuffer, mimeType).then((image) => {
const texture = new Texture2D(
engine,
image.width,
image.height,
undefined,
samplerInfo?.mipmap,
isSRGBColorSpace
);
texture.setImageSource(image);
texture.generateMipmaps();
const bufferTextureRestoreInfo = new BufferTextureRestoreInfo(texture, bufferView, mimeType);
context.contentRestorer.bufferTextures.push(bufferTextureRestoreInfo);
texture.name = textureName || imageName || `texture_${textureIndex}`;
useSampler && GLTFUtils.parseSampler(texture, samplerInfo);
const bufferTextureRestoreInfo = new BufferTextureRestoreInfo(texture, bufferView, mimeType);
context.contentRestorer.bufferTextures.push(bufferTextureRestoreInfo);
return texture;
return texture;
});
})
.catch((e) => {
Logger.error("GLTFTextureParser: image buffer error", e);
});
});
}
return texture;
}
parse(context: GLTFParserContext, textureIndex: number): Promise<Texture> {
parse(context: GLTFParserContext, textureIndex: number): AssetPromise<Texture> {
const textureInfo = context.glTF.textures[textureIndex];
const glTFResource = context.glTFResource;
const { sampler, source: imageIndex = 0, name: textureName, extensions } = textureInfo;
const isSRGBColorSpace = this._isSRGBColorSpace(textureIndex, context.glTF.materials);
let texture = <Texture | Promise<Texture>>(
let texture = <Texture | AssetPromise<Texture>>(
GLTFParser.executeExtensionsCreateAndParse(extensions, context, textureInfo, textureIndex, isSRGBColorSpace)
);
@@ -106,7 +109,7 @@ export class GLTFTextureParser extends GLTFParser {
);
}
return Promise.resolve(texture).then((texture) => {
return AssetPromise.resolve(texture).then((texture) => {
GLTFParser.executeExtensionsAdditiveAndParse(extensions, context, texture, textureInfo);
// @ts-ignore
texture._associationSuperResource(glTFResource);

View File

@@ -1,10 +1,10 @@
import { Logger } from "@galacean/engine-core";
import { AssetPromise, Logger } from "@galacean/engine-core";
import { GLTFParser } from "./GLTFParser";
import { GLTFParserContext, GLTFParserType, registerGLTFParser } from "./GLTFParserContext";
@registerGLTFParser(GLTFParserType.Validator)
export class GLTFValidator extends GLTFParser {
parse(context: GLTFParserContext): Promise<void> {
parse(context: GLTFParserContext): AssetPromise<void> {
const {
asset: { version },
extensionsUsed,
@@ -37,6 +37,6 @@ export class GLTFValidator extends GLTFParser {
}
}
return Promise.resolve(null);
return AssetPromise.resolve(null);
}
}

View File

@@ -1,4 +1,4 @@
import { Engine } from "@galacean/engine-core";
import { AssetPromise, Engine } from "@galacean/engine-core";
import { BufferReader } from "./utils/BufferReader";
import { decoderMap } from "./utils/Decorator";
import { FileHeader } from "./utils/FileHeader";
@@ -15,7 +15,7 @@ export type { IModelMesh } from "./resources/mesh/IModelMesh";
* @param engine - engine
* @returns
*/
export function decode<T>(arrayBuffer: ArrayBuffer, engine: Engine): Promise<T> {
export function decode<T>(arrayBuffer: ArrayBuffer, engine: Engine): AssetPromise<T> {
const header = FileHeader.decode(arrayBuffer);
const bufferReader = new BufferReader(new Uint8Array(arrayBuffer), header.headerLength, header.dataLength);
return decoderMap[header.type].decode(engine, bufferReader).then((object) => {

View File

@@ -1,5 +1,6 @@
import {
AnimationArrayCurve,
AnimationBoolCurve,
AnimationClip,
AnimationColorCurve,
AnimationCurve,
@@ -7,17 +8,17 @@ import {
AnimationFloatArrayCurve,
AnimationFloatCurve,
AnimationQuaternionCurve,
AnimationRefCurve,
AnimationStringCurve,
AnimationVector2Curve,
AnimationVector3Curve,
AnimationVector4Curve,
AnimationRefCurve,
AssetPromise,
Engine,
Keyframe,
KeyframeValueType,
ReferResource,
AnimationStringCurve,
AnimationBoolCurve,
Loader
Loader,
ReferResource
} from "@galacean/engine-core";
import { Color, Quaternion, Vector2, Vector3, Vector4 } from "@galacean/engine-math";
import type { BufferReader } from "../../utils/BufferReader";
@@ -39,8 +40,8 @@ export enum InterpolableValueType {
@decoder("AnimationClip")
export class AnimationClipDecoder {
public static decode(engine: Engine, bufferReader: BufferReader): Promise<AnimationClip> {
return new Promise((resolve) => {
public static decode(engine: Engine, bufferReader: BufferReader): AssetPromise<AnimationClip> {
return new AssetPromise((resolve) => {
const name = bufferReader.nextStr();
const clip = new AnimationClip(name);
const eventsLen = bufferReader.nextUint16();

View File

@@ -1,4 +1,4 @@
import type { Engine } from "@galacean/engine-core";
import { AssetPromise, Engine } from "@galacean/engine-core";
import { BlendShape, ModelMesh } from "@galacean/engine-core";
import { Color, Vector2, Vector3, Vector4 } from "@galacean/engine-math";
import type { BufferReader } from "../../utils/BufferReader";
@@ -10,8 +10,8 @@ import type { IEncodedModelMesh } from "./IModelMesh";
*/
@decoder("Mesh")
export class MeshDecoder {
public static decode(engine: Engine, bufferReader: BufferReader): Promise<ModelMesh> {
return new Promise((resolve) => {
public static decode(engine: Engine, bufferReader: BufferReader): AssetPromise<ModelMesh> {
return new AssetPromise((resolve) => {
const modelMesh = new ModelMesh(engine);
const jsonDataString = bufferReader.nextStr();
const encodedMeshData: IEncodedModelMesh = JSON.parse(jsonDataString);

View File

@@ -1,11 +1,11 @@
import { Engine, Texture2D } from "@galacean/engine-core";
import { AssetPromise, Engine, Texture2D } from "@galacean/engine-core";
import { BufferReader } from "../../utils/BufferReader";
import { decoder } from "../../utils/Decorator";
@decoder("Texture2D")
export class Texture2DDecoder {
static decode(engine: Engine, bufferReader: BufferReader): Promise<Texture2D> {
return new Promise((resolve, reject) => {
static decode(engine: Engine, bufferReader: BufferReader): AssetPromise<Texture2D> {
return new AssetPromise((resolve, reject) => {
const objectId = bufferReader.nextStr();
const mipmap = !!bufferReader.nextUint8();
const filterMode = bufferReader.nextUint8();

View File

@@ -1,10 +1,10 @@
import { Engine } from "@galacean/engine-core";
import { AssetPromise, Engine } from "@galacean/engine-core";
import type { BufferReader } from "./BufferReader";
export const decoderMap: Record<
string,
{
decode: (engine: Engine, bufferReader: BufferReader) => Promise<any>;
decode: (engine: Engine, bufferReader: BufferReader) => AssetPromise<any>;
}
> = {};