From 08aaa778f32428b4c312c1e3fa8e99f07764be8f Mon Sep 17 00:00:00 2001 From: Hu Song Date: Tue, 21 Feb 2023 15:31:48 +0800 Subject: [PATCH 01/11] Add `toJSON` in base math class (#1380) * feat: add toJSON in base math class --- packages/math/src/Color.ts | 13 +++++++++++++ packages/math/src/Quaternion.ts | 13 +++++++++++++ packages/math/src/Vector2.ts | 11 +++++++++++ packages/math/src/Vector3.ts | 12 ++++++++++++ packages/math/src/Vector4.ts | 13 +++++++++++++ tests/src/math/Color.test.ts | 6 ++++++ tests/src/math/Vector2.test.ts | 5 +++++ tests/src/math/Vector3.test.ts | 5 +++++ tests/src/math/Vector4.test.ts | 5 +++++ 9 files changed, 83 insertions(+) diff --git a/packages/math/src/Color.ts b/packages/math/src/Color.ts index 00931f5f8f..c9d9385db0 100644 --- a/packages/math/src/Color.ts +++ b/packages/math/src/Color.ts @@ -303,6 +303,19 @@ export class Color implements IClone, ICopy { return (max + min) / 2; } + + /** + * Serialize this color to a JSON representation. + * @return A JSON representation of this color + */ + toJSON(): ColorLike { + return { + r: this._r, + g: this._g, + b: this._b, + a: this._a + }; + } } interface ColorLike { diff --git a/packages/math/src/Quaternion.ts b/packages/math/src/Quaternion.ts index f721f4e2f7..25467985b2 100644 --- a/packages/math/src/Quaternion.ts +++ b/packages/math/src/Quaternion.ts @@ -757,6 +757,19 @@ export class Quaternion implements IClone, ICopy, ICopy { out[outOffset] = this._x; out[outOffset + 1] = this._y; } + + /** + * Serialize this vector to a JSON representation. + * @returns A JSON representation of this vector + */ + toJSON(): Vector2Like { + return { + x: this._x, + y: this._y + }; + } } interface Vector2Like { diff --git a/packages/math/src/Vector3.ts b/packages/math/src/Vector3.ts index b41ff454bb..a5eec72e9b 100644 --- a/packages/math/src/Vector3.ts +++ b/packages/math/src/Vector3.ts @@ -585,6 +585,18 @@ export class Vector3 implements IClone, ICopy { out[outOffset + 1] = this._y; out[outOffset + 2] = this._z; } + + /** + * Serialize this vector to a JSON representation. + * @returns A JSON representation of this vector + */ + toJSON(): Vector3Like { + return { + x: this._x, + y: this._y, + z: this._z + }; + } } interface Vector3Like { diff --git a/packages/math/src/Vector4.ts b/packages/math/src/Vector4.ts index e207765d7f..7328b3b09f 100644 --- a/packages/math/src/Vector4.ts +++ b/packages/math/src/Vector4.ts @@ -503,6 +503,19 @@ export class Vector4 implements IClone, ICopy { out[outOffset + 2] = this._z; out[outOffset + 3] = this._w; } + + /** + * Serialize this vector to a JSON representation. + * @returns A JSON representation of this vector + */ + toJSON(): Vector4Like { + return { + x: this._x, + y: this._y, + z: this._z, + w: this._w + }; + } } interface Vector4Like { diff --git a/tests/src/math/Color.test.ts b/tests/src/math/Color.test.ts index 375a79181b..afd1a480dc 100644 --- a/tests/src/math/Color.test.ts +++ b/tests/src/math/Color.test.ts @@ -84,4 +84,10 @@ describe("Color test", () => { expect(Color.equals(colorLinear, colorNewLinear)).to.eq(true); } }); + + it('toJSON', ()=>{ + const color = new Color(1, 0.5, 0.5, 1); + const json = color.toJSON(); + expect(json).to.deep.eq({r: 1, g: 0.5, b: 0.5, a: 1}); + }) }); diff --git a/tests/src/math/Vector2.test.ts b/tests/src/math/Vector2.test.ts index 0353c71f39..617717df3f 100644 --- a/tests/src/math/Vector2.test.ts +++ b/tests/src/math/Vector2.test.ts @@ -203,4 +203,9 @@ describe("Vector2 test", () => { expect(toString(a.scale(2))).to.eq(toString(a)); expect(toString(a)).to.eq("vec2(6, 8)"); }); + + it("toJSON", () => { + const a = new Vector2(3, 4); + expect(a.toJSON()).to.deep.eq({ x: 3, y: 4 }); + }); }); diff --git a/tests/src/math/Vector3.test.ts b/tests/src/math/Vector3.test.ts index 6edbb9e887..0dfaeb5cfd 100644 --- a/tests/src/math/Vector3.test.ts +++ b/tests/src/math/Vector3.test.ts @@ -257,4 +257,9 @@ describe("Vector3 test", () => { a.transformByQuat(new Quaternion(2, 3, 4, 5)); expect(toString(a)).to.eq("vec3(108, 162, 216)"); }); + + it("toJSON", () => { + const a = new Vector3(2, 3, 4); + expect(JSON.stringify(a)).to.eq('{"x":2,"y":3,"z":4}'); + }); }); diff --git a/tests/src/math/Vector4.test.ts b/tests/src/math/Vector4.test.ts index fb395592a5..7a4c3d8bcb 100644 --- a/tests/src/math/Vector4.test.ts +++ b/tests/src/math/Vector4.test.ts @@ -209,4 +209,9 @@ describe("Vector4 test", () => { expect(toString(a.scale(2))).to.eq(toString(a)); expect(toString(a)).to.eq("vec4(6, 8, 0, 0)"); }); + + it("toJSON", () => { + const a = new Vector4(3, 4, 5, 0); + expect(JSON.stringify(a)).to.eq('{"x":3,"y":4,"z":5,"w":0}'); + }); }); From 94c19976ef277bce22d57767e31406a910390905 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Wed, 22 Feb 2023 14:53:25 +0800 Subject: [PATCH 02/11] feat: refactor transform API --- packages/core/src/Transform.ts | 51 +++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index 2426853c8d..5844db33fa 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -1,6 +1,6 @@ import { MathUtil, Matrix, Matrix3x3, Quaternion, Vector3 } from "@oasis-engine/math"; import { BoolUpdateFlag } from "./BoolUpdateFlag"; -import { assignmentClone, deepClone, ignoreClone } from "./clone/CloneManager"; +import { deepClone, ignoreClone } from "./clone/CloneManager"; import { Component } from "./Component"; import { Entity } from "./Entity"; import { UpdateFlagManager } from "./UpdateFlagManager"; @@ -39,6 +39,13 @@ export class Transform extends Component { private _localMatrix: Matrix = new Matrix(); @deepClone private _worldMatrix: Matrix = new Matrix(); + @ignoreClone + private _worldForward: Vector3; + @ignoreClone + private _worldRight: Vector3; + @ignoreClone + private _up: Vector3; + @ignoreClone private _isParentDirty: boolean = true; @ignoreClone @@ -403,36 +410,42 @@ export class Transform extends Component { } /** - * Get the forward direction in world space. - * @param forward - Forward vector - * @returns Forward vector + * The forward direction in world space. */ - getWorldForward(forward: Vector3): Vector3 { + get worldForward(): Vector3 { + let worldForward = this._worldForward; + if (!worldForward) { + this._worldForward = worldForward = new Vector3(); + } const e = this.worldMatrix.elements; - forward.set(-e[8], -e[9], -e[10]); - return forward.normalize(); + worldForward.set(-e[8], -e[9], -e[10]); + return worldForward.normalize(); } /** - * Get the right direction in world space. - * @param right - Right vector - * @returns Right vector + * The right direction in world space. */ - getWorldRight(right: Vector3): Vector3 { + get worldRight(): Vector3 { + let worldRight = this._worldRight; + if (!worldRight) { + this._worldForward = worldRight = new Vector3(); + } const e = this.worldMatrix.elements; - right.set(e[0], e[1], e[2]); - return right.normalize(); + worldRight.set(e[0], e[1], e[2]); + return worldRight.normalize(); } /** - * Get the up direction in world space. - * @param up - Up vector - * @returns Up vector + * The up direction in world space. */ - getWorldUp(up: Vector3): Vector3 { + get worldUp(): Vector3 { + let worldUp = this._up; + if (!worldUp) { + this._worldForward = worldUp = new Vector3(); + } const e = this.worldMatrix.elements; - up.set(e[4], e[5], e[6]); - return up.normalize(); + worldUp.set(e[4], e[5], e[6]); + return worldUp.normalize(); } /** From a4116d9ba4af5a4bd07f6ec5d868fd40d6d6e847 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Wed, 22 Feb 2023 15:56:10 +0800 Subject: [PATCH 03/11] refactor: opt code --- packages/core/src/Camera.ts | 4 ++-- packages/core/src/lighting/DirectLight.ts | 5 +---- packages/core/src/lighting/SpotLight.ts | 4 +--- packages/core/src/shadow/CascadedShadowCasterPass.ts | 7 ++++--- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index cb26b35e42..b82ae00e4a 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -436,9 +436,9 @@ export class Camera extends Component { const transform = this.entity.transform; Matrix.multiply(this.projectionMatrix, this.viewMatrix, virtualCamera.viewProjectionMatrix); - virtualCamera.forward.copyFrom(transform.worldPosition); + virtualCamera.position.copyFrom(transform.worldPosition); if (virtualCamera.isOrthographic) { - transform.getWorldForward(virtualCamera.forward); + virtualCamera.forward.copyFrom(transform.worldForward); } context.camera = this; diff --git a/packages/core/src/lighting/DirectLight.ts b/packages/core/src/lighting/DirectLight.ts index 5623f08a2f..4ad99bdb04 100644 --- a/packages/core/src/lighting/DirectLight.ts +++ b/packages/core/src/lighting/DirectLight.ts @@ -25,16 +25,13 @@ export class DirectLight extends Light { shaderData.setFloatArray(DirectLight._directionProperty, data.direction); } - private _forward: Vector3 = new Vector3(); - private _reverseDirection: Vector3 = new Vector3(); /** * Get direction. */ get direction(): Vector3 { - this.entity.transform.getWorldForward(this._forward); - return this._forward; + return this.entity.transform.worldForward; } /** diff --git a/packages/core/src/lighting/SpotLight.ts b/packages/core/src/lighting/SpotLight.ts index f35c1d6eec..0aee9ea1e8 100644 --- a/packages/core/src/lighting/SpotLight.ts +++ b/packages/core/src/lighting/SpotLight.ts @@ -44,7 +44,6 @@ export class SpotLight extends Light { /** Angle, in radians, from falloff begins to ends. */ penumbra: number = Math.PI / 12; - private _forward: Vector3 = new Vector3(); private _inverseDirection: Vector3 = new Vector3(); private _projectMatrix: Matrix = new Matrix(); @@ -59,8 +58,7 @@ export class SpotLight extends Light { * Get light direction. */ get direction(): Vector3 { - this.entity.transform.getWorldForward(this._forward); - return this._forward; + return this.entity.transform.worldForward; } /** diff --git a/packages/core/src/shadow/CascadedShadowCasterPass.ts b/packages/core/src/shadow/CascadedShadowCasterPass.ts index 218e2f8ebb..9a4845b78d 100644 --- a/packages/core/src/shadow/CascadedShadowCasterPass.ts +++ b/packages/core/src/shadow/CascadedShadowCasterPass.ts @@ -135,7 +135,8 @@ export class CascadedShadowCasterPass { lightSide.set(lightWorldE[0], lightWorldE[1], lightWorldE[2]); lightUp.set(lightWorldE[4], lightWorldE[5], lightWorldE[6]); lightForward.set(-lightWorldE[8], -lightWorldE[9], -lightWorldE[10]); - camera.entity.transform.getWorldForward(CascadedShadowCasterPass._tempVector); + const cameraForward = CascadedShadowCasterPass._tempVector; + cameraForward.copyFrom(camera.entity.transform.worldForward); const shadowTileResolution = this._shadowTileResolution; @@ -144,7 +145,7 @@ export class CascadedShadowCasterPass { splitDistance[j], splitDistance[j + 1], camera, - CascadedShadowCasterPass._tempVector.normalize(), + cameraForward, shadowSliceData ); ShadowUtils.getDirectionLightShadowCullPlanes( @@ -202,7 +203,7 @@ export class CascadedShadowCasterPass { const { x, y } = viewports[j]; rhi.setGlobalDepthBias(1.0, 1.0); - + rhi.viewport(x, y, shadowTileResolution, shadowTileResolution); // for no cascade is for the edge,for cascade is for the beyond maxCascade pixel can use (0,0,0) trick sample the shadowMap rhi.scissor(x + 1, y + 1, shadowTileResolution - 2, shadowTileResolution - 2); From b51e87ecd76fce282268a5bbc9f3c29be2421492 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Wed, 22 Feb 2023 16:06:38 +0800 Subject: [PATCH 04/11] refactor: opt code --- tests/src/core/Transform.test.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/src/core/Transform.test.ts diff --git a/tests/src/core/Transform.test.ts b/tests/src/core/Transform.test.ts new file mode 100644 index 0000000000..60f3c97b0d --- /dev/null +++ b/tests/src/core/Transform.test.ts @@ -0,0 +1,26 @@ +import { MathUtil, Matrix, Ray, Vector2, Vector3, Vector4 } from "@oasis-engine/math"; +import { WebGLEngine } from "@oasis-engine/rhi-webgl"; +import { Camera, Entity } from "@oasis-engine/core"; +import { expect } from "chai"; + +const canvasDOM = document.createElement("canvas"); +canvasDOM.width = 1024; +canvasDOM.height = 1024; + +describe("Transform test", function () { + let entity: Entity; + before(() => { + const engine = new WebGLEngine(canvasDOM); + entity = engine.sceneManager.activeScene.createRootEntity(); + }); + + it("World direction", () => { + const transform = entity.transform; + transform.position.set(1, -2, 3); + transform.rotate(0, 45, 0); + + expect(transform.worldForward).to.deep.equal(new Vector3(-0.7071067811865476, -0, -0.7071067811865476)); + expect(transform.worldRight).to.deep.equal(new Vector3(0.7071067811865476, 0, -0.7071067811865476)); + expect(transform.worldUp).to.deep.equal(new Vector3(0, 1, 0)); + }); +}); From 83e87ce1c6d2f2209e21b42a0c0e7e6c22596c59 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Wed, 22 Feb 2023 16:12:48 +0800 Subject: [PATCH 05/11] refactor: opt code --- packages/core/src/Transform.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index 5844db33fa..1be4c309f4 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -44,7 +44,7 @@ export class Transform extends Component { @ignoreClone private _worldRight: Vector3; @ignoreClone - private _up: Vector3; + private _worldUp: Vector3; @ignoreClone private _isParentDirty: boolean = true; @@ -439,7 +439,7 @@ export class Transform extends Component { * The up direction in world space. */ get worldUp(): Vector3 { - let worldUp = this._up; + let worldUp = this._worldUp; if (!worldUp) { this._worldForward = worldUp = new Vector3(); } From 21f4190092cc0c391613b833384f60769767e2e2 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Wed, 22 Feb 2023 16:29:18 +0800 Subject: [PATCH 06/11] refactor: opt code --- packages/core/src/Transform.ts | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index 1be4c309f4..ef2b820795 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -413,10 +413,7 @@ export class Transform extends Component { * The forward direction in world space. */ get worldForward(): Vector3 { - let worldForward = this._worldForward; - if (!worldForward) { - this._worldForward = worldForward = new Vector3(); - } + const worldForward = (this._worldForward ||= new Vector3()); const e = this.worldMatrix.elements; worldForward.set(-e[8], -e[9], -e[10]); return worldForward.normalize(); @@ -426,10 +423,7 @@ export class Transform extends Component { * The right direction in world space. */ get worldRight(): Vector3 { - let worldRight = this._worldRight; - if (!worldRight) { - this._worldForward = worldRight = new Vector3(); - } + const worldRight = (this._worldRight ||= new Vector3()); const e = this.worldMatrix.elements; worldRight.set(e[0], e[1], e[2]); return worldRight.normalize(); @@ -439,10 +433,7 @@ export class Transform extends Component { * The up direction in world space. */ get worldUp(): Vector3 { - let worldUp = this._worldUp; - if (!worldUp) { - this._worldForward = worldUp = new Vector3(); - } + const worldUp = (this._worldUp ||= new Vector3()); const e = this.worldMatrix.elements; worldUp.set(e[4], e[5], e[6]); return worldUp.normalize(); From 7724d8cd2900930bd9929020e70c06fd59e92f88 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Wed, 22 Feb 2023 16:38:05 +0800 Subject: [PATCH 07/11] refactor: opt code --- packages/core/src/Transform.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index ef2b820795..867f3e8204 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -40,11 +40,11 @@ export class Transform extends Component { @deepClone private _worldMatrix: Matrix = new Matrix(); @ignoreClone - private _worldForward: Vector3; + private _worldForward: Vector3 = null; @ignoreClone - private _worldRight: Vector3; + private _worldRight: Vector3 = null; @ignoreClone - private _worldUp: Vector3; + private _worldUp: Vector3 = null; @ignoreClone private _isParentDirty: boolean = true; From 0522015082e2d97867075151a296ecc8207dd7a4 Mon Sep 17 00:00:00 2001 From: ChenMo Date: Wed, 22 Feb 2023 16:43:11 +0800 Subject: [PATCH 08/11] Optimization `Transform` direction related API (#1381) * feat: optimization `Transform` direction related API * fix: cull bug --- packages/core/src/Camera.ts | 4 +- packages/core/src/Transform.ts | 42 ++++++++++--------- packages/core/src/lighting/DirectLight.ts | 5 +-- packages/core/src/lighting/SpotLight.ts | 4 +- .../src/shadow/CascadedShadowCasterPass.ts | 7 ++-- tests/src/core/Transform.test.ts | 26 ++++++++++++ 6 files changed, 57 insertions(+), 31 deletions(-) create mode 100644 tests/src/core/Transform.test.ts diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index cb26b35e42..b82ae00e4a 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -436,9 +436,9 @@ export class Camera extends Component { const transform = this.entity.transform; Matrix.multiply(this.projectionMatrix, this.viewMatrix, virtualCamera.viewProjectionMatrix); - virtualCamera.forward.copyFrom(transform.worldPosition); + virtualCamera.position.copyFrom(transform.worldPosition); if (virtualCamera.isOrthographic) { - transform.getWorldForward(virtualCamera.forward); + virtualCamera.forward.copyFrom(transform.worldForward); } context.camera = this; diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index 2426853c8d..867f3e8204 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -1,6 +1,6 @@ import { MathUtil, Matrix, Matrix3x3, Quaternion, Vector3 } from "@oasis-engine/math"; import { BoolUpdateFlag } from "./BoolUpdateFlag"; -import { assignmentClone, deepClone, ignoreClone } from "./clone/CloneManager"; +import { deepClone, ignoreClone } from "./clone/CloneManager"; import { Component } from "./Component"; import { Entity } from "./Entity"; import { UpdateFlagManager } from "./UpdateFlagManager"; @@ -39,6 +39,13 @@ export class Transform extends Component { private _localMatrix: Matrix = new Matrix(); @deepClone private _worldMatrix: Matrix = new Matrix(); + @ignoreClone + private _worldForward: Vector3 = null; + @ignoreClone + private _worldRight: Vector3 = null; + @ignoreClone + private _worldUp: Vector3 = null; + @ignoreClone private _isParentDirty: boolean = true; @ignoreClone @@ -403,36 +410,33 @@ export class Transform extends Component { } /** - * Get the forward direction in world space. - * @param forward - Forward vector - * @returns Forward vector + * The forward direction in world space. */ - getWorldForward(forward: Vector3): Vector3 { + get worldForward(): Vector3 { + const worldForward = (this._worldForward ||= new Vector3()); const e = this.worldMatrix.elements; - forward.set(-e[8], -e[9], -e[10]); - return forward.normalize(); + worldForward.set(-e[8], -e[9], -e[10]); + return worldForward.normalize(); } /** - * Get the right direction in world space. - * @param right - Right vector - * @returns Right vector + * The right direction in world space. */ - getWorldRight(right: Vector3): Vector3 { + get worldRight(): Vector3 { + const worldRight = (this._worldRight ||= new Vector3()); const e = this.worldMatrix.elements; - right.set(e[0], e[1], e[2]); - return right.normalize(); + worldRight.set(e[0], e[1], e[2]); + return worldRight.normalize(); } /** - * Get the up direction in world space. - * @param up - Up vector - * @returns Up vector + * The up direction in world space. */ - getWorldUp(up: Vector3): Vector3 { + get worldUp(): Vector3 { + const worldUp = (this._worldUp ||= new Vector3()); const e = this.worldMatrix.elements; - up.set(e[4], e[5], e[6]); - return up.normalize(); + worldUp.set(e[4], e[5], e[6]); + return worldUp.normalize(); } /** diff --git a/packages/core/src/lighting/DirectLight.ts b/packages/core/src/lighting/DirectLight.ts index 5623f08a2f..4ad99bdb04 100644 --- a/packages/core/src/lighting/DirectLight.ts +++ b/packages/core/src/lighting/DirectLight.ts @@ -25,16 +25,13 @@ export class DirectLight extends Light { shaderData.setFloatArray(DirectLight._directionProperty, data.direction); } - private _forward: Vector3 = new Vector3(); - private _reverseDirection: Vector3 = new Vector3(); /** * Get direction. */ get direction(): Vector3 { - this.entity.transform.getWorldForward(this._forward); - return this._forward; + return this.entity.transform.worldForward; } /** diff --git a/packages/core/src/lighting/SpotLight.ts b/packages/core/src/lighting/SpotLight.ts index f35c1d6eec..0aee9ea1e8 100644 --- a/packages/core/src/lighting/SpotLight.ts +++ b/packages/core/src/lighting/SpotLight.ts @@ -44,7 +44,6 @@ export class SpotLight extends Light { /** Angle, in radians, from falloff begins to ends. */ penumbra: number = Math.PI / 12; - private _forward: Vector3 = new Vector3(); private _inverseDirection: Vector3 = new Vector3(); private _projectMatrix: Matrix = new Matrix(); @@ -59,8 +58,7 @@ export class SpotLight extends Light { * Get light direction. */ get direction(): Vector3 { - this.entity.transform.getWorldForward(this._forward); - return this._forward; + return this.entity.transform.worldForward; } /** diff --git a/packages/core/src/shadow/CascadedShadowCasterPass.ts b/packages/core/src/shadow/CascadedShadowCasterPass.ts index 218e2f8ebb..9a4845b78d 100644 --- a/packages/core/src/shadow/CascadedShadowCasterPass.ts +++ b/packages/core/src/shadow/CascadedShadowCasterPass.ts @@ -135,7 +135,8 @@ export class CascadedShadowCasterPass { lightSide.set(lightWorldE[0], lightWorldE[1], lightWorldE[2]); lightUp.set(lightWorldE[4], lightWorldE[5], lightWorldE[6]); lightForward.set(-lightWorldE[8], -lightWorldE[9], -lightWorldE[10]); - camera.entity.transform.getWorldForward(CascadedShadowCasterPass._tempVector); + const cameraForward = CascadedShadowCasterPass._tempVector; + cameraForward.copyFrom(camera.entity.transform.worldForward); const shadowTileResolution = this._shadowTileResolution; @@ -144,7 +145,7 @@ export class CascadedShadowCasterPass { splitDistance[j], splitDistance[j + 1], camera, - CascadedShadowCasterPass._tempVector.normalize(), + cameraForward, shadowSliceData ); ShadowUtils.getDirectionLightShadowCullPlanes( @@ -202,7 +203,7 @@ export class CascadedShadowCasterPass { const { x, y } = viewports[j]; rhi.setGlobalDepthBias(1.0, 1.0); - + rhi.viewport(x, y, shadowTileResolution, shadowTileResolution); // for no cascade is for the edge,for cascade is for the beyond maxCascade pixel can use (0,0,0) trick sample the shadowMap rhi.scissor(x + 1, y + 1, shadowTileResolution - 2, shadowTileResolution - 2); diff --git a/tests/src/core/Transform.test.ts b/tests/src/core/Transform.test.ts new file mode 100644 index 0000000000..60f3c97b0d --- /dev/null +++ b/tests/src/core/Transform.test.ts @@ -0,0 +1,26 @@ +import { MathUtil, Matrix, Ray, Vector2, Vector3, Vector4 } from "@oasis-engine/math"; +import { WebGLEngine } from "@oasis-engine/rhi-webgl"; +import { Camera, Entity } from "@oasis-engine/core"; +import { expect } from "chai"; + +const canvasDOM = document.createElement("canvas"); +canvasDOM.width = 1024; +canvasDOM.height = 1024; + +describe("Transform test", function () { + let entity: Entity; + before(() => { + const engine = new WebGLEngine(canvasDOM); + entity = engine.sceneManager.activeScene.createRootEntity(); + }); + + it("World direction", () => { + const transform = entity.transform; + transform.position.set(1, -2, 3); + transform.rotate(0, 45, 0); + + expect(transform.worldForward).to.deep.equal(new Vector3(-0.7071067811865476, -0, -0.7071067811865476)); + expect(transform.worldRight).to.deep.equal(new Vector3(0.7071067811865476, 0, -0.7071067811865476)); + expect(transform.worldUp).to.deep.equal(new Vector3(0, 1, 0)); + }); +}); From 54b48dc9dd659f586d9bf66d1b2e4c503833c11a Mon Sep 17 00:00:00 2001 From: zhuxudong Date: Wed, 1 Mar 2023 18:31:31 +0800 Subject: [PATCH 09/11] glTF parse support custom extsnions and parser (#1008) * feat: glTF parse support custom extsnions and parser Co-authored-by: ChenMo --- packages/loader/src/GLTFLoader.ts | 17 +- packages/loader/src/gltf/GLTFParser.ts | 63 ---- packages/loader/src/gltf/GLTFPipeline.ts | 76 +++++ packages/loader/src/gltf/GLTFResource.ts | 7 +- .../src/gltf/{Schema.ts => GLTFSchema.ts} | 3 + packages/loader/src/gltf/GLTFUtil.ts | 26 +- .../src/gltf/extensions/ExtensionParser.ts | 22 -- .../gltf/extensions/GLTFExtensionParser.ts | 73 +++++ .../{Schema.ts => GLTFExtensionSchema.ts} | 7 +- .../extensions/KHR_draco_mesh_compression.ts | 189 ++++++++++- .../gltf/extensions/KHR_lights_punctual.ts | 24 +- .../extensions/KHR_materials_clearcoat.ts | 25 +- .../KHR_materials_pbrSpecularGlossiness.ts | 33 +- .../gltf/extensions/KHR_materials_unlit.ts | 20 +- .../gltf/extensions/KHR_materials_variants.ts | 32 +- .../gltf/extensions/KHR_mesh_quantization.ts | 8 +- .../gltf/extensions/KHR_texture_transform.ts | 22 +- .../gltf/extensions/OASIS_materials_remap.ts | 17 +- packages/loader/src/gltf/extensions/index.ts | 5 +- packages/loader/src/gltf/index.ts | 6 + ...mationParser.ts => GLTFAnimationParser.ts} | 10 +- .../{BufferParser.ts => GLTFBufferParser.ts} | 10 +- .../{EntityParser.ts => GLTFEntityParser.ts} | 14 +- .../src/gltf/parser/GLTFMaterialParser.ts | 166 ++++++++++ .../{MeshParser.ts => GLTFMeshParser.ts} | 293 +++++------------- packages/loader/src/gltf/parser/GLTFParser.ts | 160 ++++++++++ ...{ParserContext.ts => GLTFParserContext.ts} | 4 +- .../{SceneParser.ts => GLTFSceneParser.ts} | 67 ++-- .../{SkinParser.ts => GLTFSkinParser.ts} | 8 +- ...{TextureParser.ts => GLTFTextureParser.ts} | 14 +- .../parser/{Validator.ts => GLTFValidator.ts} | 23 +- .../loader/src/gltf/parser/MaterialParser.ts | 186 ----------- packages/loader/src/gltf/parser/Parser.ts | 76 ----- packages/loader/src/gltf/parser/index.ts | 11 + packages/loader/src/index.ts | 4 +- 35 files changed, 944 insertions(+), 777 deletions(-) delete mode 100644 packages/loader/src/gltf/GLTFParser.ts create mode 100644 packages/loader/src/gltf/GLTFPipeline.ts rename packages/loader/src/gltf/{Schema.ts => GLTFSchema.ts} (99%) delete mode 100644 packages/loader/src/gltf/extensions/ExtensionParser.ts create mode 100644 packages/loader/src/gltf/extensions/GLTFExtensionParser.ts rename packages/loader/src/gltf/extensions/{Schema.ts => GLTFExtensionSchema.ts} (96%) create mode 100644 packages/loader/src/gltf/index.ts rename packages/loader/src/gltf/parser/{AnimationParser.ts => GLTFAnimationParser.ts} (96%) rename packages/loader/src/gltf/parser/{BufferParser.ts => GLTFBufferParser.ts} (79%) rename packages/loader/src/gltf/parser/{EntityParser.ts => GLTFEntityParser.ts} (82%) create mode 100644 packages/loader/src/gltf/parser/GLTFMaterialParser.ts rename packages/loader/src/gltf/parser/{MeshParser.ts => GLTFMeshParser.ts} (52%) create mode 100644 packages/loader/src/gltf/parser/GLTFParser.ts rename packages/loader/src/gltf/parser/{ParserContext.ts => GLTFParserContext.ts} (97%) rename packages/loader/src/gltf/parser/{SceneParser.ts => GLTFSceneParser.ts} (66%) rename packages/loader/src/gltf/parser/{SkinParser.ts => GLTFSkinParser.ts} (92%) rename packages/loader/src/gltf/parser/{TextureParser.ts => GLTFTextureParser.ts} (89%) rename packages/loader/src/gltf/parser/{Validator.ts => GLTFValidator.ts} (51%) delete mode 100644 packages/loader/src/gltf/parser/MaterialParser.ts delete mode 100644 packages/loader/src/gltf/parser/Parser.ts create mode 100644 packages/loader/src/gltf/parser/index.ts diff --git a/packages/loader/src/GLTFLoader.ts b/packages/loader/src/GLTFLoader.ts index 01141543d7..990a5c35fd 100644 --- a/packages/loader/src/GLTFLoader.ts +++ b/packages/loader/src/GLTFLoader.ts @@ -1,18 +1,19 @@ import { AssetPromise, AssetType, Loader, LoadItem, resourceLoader, ResourceManager } from "@oasis-engine/core"; -import { GLTFParser } from "./gltf/GLTFParser"; +import { GLTFPipeline } from "./gltf/GLTFPipeline"; import { GLTFResource } from "./gltf/GLTFResource"; -import { ParserContext } from "./gltf/parser/ParserContext"; +import { GLTFParserContext } from "./gltf/parser/GLTFParserContext"; @resourceLoader(AssetType.Prefab, ["gltf", "glb"]) export class GLTFLoader extends Loader { load(item: LoadItem, resourceManager: ResourceManager): Record> { - const url = item.url; - const context = new ParserContext(url); + const { url } = item; + const params = item.params; + const context = new GLTFParserContext(url); const glTFResource = new GLTFResource(resourceManager.engine, url); const masterPromiseInfo = context.masterPromiseInfo; context.glTFResource = glTFResource; - context.keepMeshData = item.params?.keepMeshData ?? false; + context.keepMeshData = params?.keepMeshData ?? false; masterPromiseInfo.onCancel(() => { const { chainPromises } = context; @@ -21,8 +22,8 @@ export class GLTFLoader extends Loader { } }); - GLTFParser.defaultPipeline - .parse(context) + (params?.pipeline || GLTFPipeline.defaultPipeline) + ._parse(context) .then(masterPromiseInfo.resolve) .catch((e) => { console.error(e); @@ -39,4 +40,6 @@ export class GLTFLoader extends Loader { export interface GLTFParams { /** Keep raw mesh data for glTF parser, default is false. */ keepMeshData: boolean; + /** Custom glTF pipeline. */ + pipeline: GLTFPipeline; } diff --git a/packages/loader/src/gltf/GLTFParser.ts b/packages/loader/src/gltf/GLTFParser.ts deleted file mode 100644 index 18514c41b2..0000000000 --- a/packages/loader/src/gltf/GLTFParser.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { AssetPromise } from "@oasis-engine/core"; -import { GLTFResource } from "./GLTFResource"; -import { AnimationParser } from "./parser/AnimationParser"; -import { BufferParser } from "./parser/BufferParser"; -import { EntityParser } from "./parser/EntityParser"; -import { MaterialParser } from "./parser/MaterialParser"; -import { MeshParser } from "./parser/MeshParser"; -import { Parser } from "./parser/Parser"; -import { ParserContext } from "./parser/ParserContext"; -import { SceneParser } from "./parser/SceneParser"; -import { SkinParser } from "./parser/SkinParser"; -import { TextureParser } from "./parser/TextureParser"; -import { Validator } from "./parser/Validator"; - -export class GLTFParser { - static defaultPipeline = new GLTFParser([ - BufferParser, - Validator, - TextureParser, - MaterialParser, - MeshParser, - EntityParser, - SkinParser, - AnimationParser, - SceneParser - ]); - - private _pipes: Parser[] = []; - - private constructor(pipes: (new () => Parser)[]) { - pipes.forEach((pipe: new () => Parser, index: number) => { - this._pipes[index] = new pipe(); - }); - } - - parse(context: ParserContext): AssetPromise { - const glTFResource = context.glTFResource; - let lastPipe; - - return new AssetPromise((resolve, reject) => { - this._pipes.forEach((parser: Parser) => { - if (lastPipe) { - lastPipe = lastPipe.then(() => { - return parser.parse(context); - }); - if (lastPipe.cancel) { - context.chainPromises.push(lastPipe); - } - } else { - lastPipe = parser.parse(context); - } - }); - - if (lastPipe) { - lastPipe - .then(() => { - resolve(glTFResource); - }) - .catch(reject); - } - }); - } -} diff --git a/packages/loader/src/gltf/GLTFPipeline.ts b/packages/loader/src/gltf/GLTFPipeline.ts new file mode 100644 index 0000000000..b9ae25f638 --- /dev/null +++ b/packages/loader/src/gltf/GLTFPipeline.ts @@ -0,0 +1,76 @@ +import { AssetPromise } from "@oasis-engine/core"; +import { GLTFResource } from "./GLTFResource"; +import { GLTFAnimationParser } from "./parser/GLTFAnimationParser"; +import { GLTFBufferParser } from "./parser/GLTFBufferParser"; +import { GLTFEntityParser } from "./parser/GLTFEntityParser"; +import { GLTFMaterialParser } from "./parser/GLTFMaterialParser"; +import { GLTFMeshParser } from "./parser/GLTFMeshParser"; +import { GLTFParser } from "./parser/GLTFParser"; +import { GLTFParserContext } from "./parser/GLTFParserContext"; +import { GLTFSceneParser } from "./parser/GLTFSceneParser"; +import { GLTFSkinParser } from "./parser/GLTFSkinParser"; +import { GLTFTextureParser } from "./parser/GLTFTextureParser"; +import { GLTFValidator } from "./parser/GLTFValidator"; + +/** + * GLTF pipeline. + */ +export class GLTFPipeline { + /** + * Default pipeline. + */ + static defaultPipeline = new GLTFPipeline( + GLTFBufferParser, + GLTFValidator, + GLTFTextureParser, + GLTFMaterialParser, + GLTFMeshParser, + GLTFEntityParser, + GLTFSkinParser, + GLTFAnimationParser, + GLTFSceneParser + ); + + private _parsers: GLTFParser[] = []; + + /** + * Constructor of GLTFPipeline. + * @param parsers - Parsers to be executed in order + */ + constructor(...parsers: (new () => GLTFParser)[]) { + parsers.forEach((pipe: new () => GLTFParser, index: number) => { + this._parsers[index] = new pipe(); + }); + } + + /** + * @internal + */ + _parse(context: GLTFParserContext): AssetPromise { + const glTFResource = context.glTFResource; + let lastParser; + + return new AssetPromise((resolve, reject) => { + this._parsers.forEach((parser: GLTFParser) => { + if (lastParser) { + lastParser = lastParser.then(() => { + return parser.parse(context); + }); + if (lastParser.cancel) { + context.chainPromises.push(lastParser); + } + } else { + lastParser = parser.parse(context); + } + }); + + if (lastParser) { + lastParser + .then(() => { + resolve(glTFResource); + }) + .catch(reject); + } + }); + } +} diff --git a/packages/loader/src/gltf/GLTFResource.ts b/packages/loader/src/gltf/GLTFResource.ts index 682ff9208e..9034a5d710 100644 --- a/packages/loader/src/gltf/GLTFResource.ts +++ b/packages/loader/src/gltf/GLTFResource.ts @@ -7,7 +7,6 @@ import { Light, Material, ModelMesh, - Renderer, Skin, Texture2D } from "@oasis-engine/core"; @@ -38,8 +37,8 @@ export class GLTFResource extends EngineObject { sceneRoots: Entity[]; /** Oasis RootEntity after SceneParser. */ defaultSceneRoot: Entity; - /** Renderer can replace material by `renderer.setMaterial` if gltf use plugin-in KHR_materials_variants. */ - variants?: { renderer: Renderer; material: Material; variants: string[] }[]; + /** Extensions data. */ + extensionsData: Record; constructor(engine: Engine, url: string) { super(engine); @@ -66,6 +65,6 @@ export class GLTFResource extends EngineObject { this.cameras = null; this.lights = null; this.sceneRoots = null; - this.variants = null; + this.extensionsData = null; } } diff --git a/packages/loader/src/gltf/Schema.ts b/packages/loader/src/gltf/GLTFSchema.ts similarity index 99% rename from packages/loader/src/gltf/Schema.ts rename to packages/loader/src/gltf/GLTFSchema.ts index 9a6e33e94f..5e1f0f9ca2 100644 --- a/packages/loader/src/gltf/Schema.ts +++ b/packages/loader/src/gltf/GLTFSchema.ts @@ -853,3 +853,6 @@ export interface IGLTF extends IProperty { */ textures?: ITexture[]; } + +/** glTF extensible owner schema. */ +export type GLTFExtensionOwnerSchema = IMeshPrimitive | IMaterial | ITextureInfo | INode; diff --git a/packages/loader/src/gltf/GLTFUtil.ts b/packages/loader/src/gltf/GLTFUtil.ts index b363140396..9b3611e40d 100644 --- a/packages/loader/src/gltf/GLTFUtil.ts +++ b/packages/loader/src/gltf/GLTFUtil.ts @@ -1,27 +1,7 @@ import { IndexFormat, TypedArray, VertexElementFormat } from "@oasis-engine/core"; import { Color, Vector2, Vector3, Vector4 } from "@oasis-engine/math"; -import { BufferInfo, ParserContext } from "./parser/ParserContext"; -import { AccessorComponentType, AccessorType, IAccessor, IBufferView, IGLTF } from "./Schema"; - -const charCodeOfDot = ".".charCodeAt(0); -const reEscapeChar = /\\(\\)?/g; -const rePropName = RegExp( - // Match anything that isn't a dot or bracket. - "[^.[\\]]+" + - "|" + - // Or match property names within brackets. - "\\[(?:" + - // Match a non-string expression. - "([^\"'][^[]*)" + - "|" + - // Or match strings (supports escaping characters). - "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + - ")\\]" + - "|" + - // Or match "" as the space between consecutive dots or empty brackets. - "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", - "g" -); +import { BufferInfo, GLTFParserContext } from "./parser/GLTFParserContext"; +import { AccessorComponentType, AccessorType, IAccessor, IBufferView, IGLTF } from "./GLTFSchema"; /** * @internal @@ -147,7 +127,7 @@ export class GLTFUtil { } } - static getAccessorBuffer(context: ParserContext, gltf: IGLTF, accessor: IAccessor): BufferInfo { + static getAccessorBuffer(context: GLTFParserContext, gltf: IGLTF, accessor: IAccessor): BufferInfo { const { buffers } = context; const bufferViews = gltf.bufferViews; diff --git a/packages/loader/src/gltf/extensions/ExtensionParser.ts b/packages/loader/src/gltf/extensions/ExtensionParser.ts deleted file mode 100644 index 57358e433a..0000000000 --- a/packages/loader/src/gltf/extensions/ExtensionParser.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { EngineObject } from "@oasis-engine/core"; -import { ParserContext } from "../parser/ParserContext"; -import { ExtensionSchema } from "./Schema"; - -export abstract class ExtensionParser { - initialize(): void {} - - parseEngineResource( - schema: ExtensionSchema, - parseResource: EngineObject, - context: ParserContext, - ...extra - ): void | Promise {} - - createEngineResource( - schema: ExtensionSchema, - context: ParserContext, - ...extra - ): EngineObject | Promise { - return null; - } -} diff --git a/packages/loader/src/gltf/extensions/GLTFExtensionParser.ts b/packages/loader/src/gltf/extensions/GLTFExtensionParser.ts new file mode 100644 index 0000000000..63aa3fd1ef --- /dev/null +++ b/packages/loader/src/gltf/extensions/GLTFExtensionParser.ts @@ -0,0 +1,73 @@ +import { EngineObject } from "@oasis-engine/core"; +import { GLTFExtensionOwnerSchema } from "../GLTFSchema"; +import { GLTFParserContext } from "../parser/GLTFParserContext"; +import { GLTFExtensionSchema } from "./GLTFExtensionSchema"; + +/** + * Base class of glTF extension parser. + */ +export abstract class GLTFExtensionParser { + /** + * @internal + * The extension mode. + */ + _mode: GLTFExtensionMode; + + /** + * Initialize the parser. + * @remarks Some plugins require initialization. + * @returns The void or promise + */ + initialize(): void | Promise {} + + /** + * Create and parse the resource. + * @remarks This method overrides the default resource creation. + * @param context - The parser context + * @param extensionSchema - The extension schema + * @param extensionOwnerSchema - The extension owner schema + * @returns The resource or promise + */ + createAndParse( + context: GLTFParserContext, + extensionSchema: GLTFExtensionSchema, + extensionOwnerSchema: GLTFExtensionOwnerSchema, + ...extra + ): EngineObject | Promise { + throw "Not implemented."; + } + + /** + * Additive parse to the resource. + * @param context - The parser context + * @param parseResource - The parsed resource + * @param extensionSchema - The extension schema + * @param extensionOwnerSchema - The extension owner schema + * @returns The void or promise + */ + additiveParse( + context: GLTFParserContext, + parseResource: EngineObject, + extensionSchema: GLTFExtensionSchema, + extensionOwnerSchema: GLTFExtensionOwnerSchema, + ...extra + ): void | Promise { + throw "Not implemented."; + } +} + +/** + * glTF Extension mode. + */ +export enum GLTFExtensionMode { + /** + * Cerate instance and parse mode. + * @remarks + * If the glTF property has multiple extensions of `CreateAndParse` mode, only execute the last one. + * If this method is registered, the default pipeline processing will be ignored. + */ + CreateAndParse, + + /** Additive parse mode. */ + AdditiveParse +} diff --git a/packages/loader/src/gltf/extensions/Schema.ts b/packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts similarity index 96% rename from packages/loader/src/gltf/extensions/Schema.ts rename to packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts index 53793d5462..477914ed8c 100644 --- a/packages/loader/src/gltf/extensions/Schema.ts +++ b/packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts @@ -1,4 +1,4 @@ -import { IMaterialNormalTextureInfo, ITextureInfo } from "../Schema"; +import { IMaterialNormalTextureInfo, ITextureInfo } from "../GLTFSchema"; /** * Interfaces from the KHR_lights_punctual extension @@ -159,7 +159,7 @@ export interface IOasisMaterialRemap { isClone?: boolean; } -export type ExtensionSchema = +export type GLTFExtensionSchema = | IKHRLightsPunctual_Light | IKHRDracoMeshCompression | IKHRMaterialsClearcoat @@ -175,4 +175,5 @@ export type ExtensionSchema = | IKHRTextureBasisU | IKHRTextureTransform | IKHRXmp - | IKHRXmp_Node; + | IKHRXmp_Node + | Object; diff --git a/packages/loader/src/gltf/extensions/KHR_draco_mesh_compression.ts b/packages/loader/src/gltf/extensions/KHR_draco_mesh_compression.ts index 2e5667c2f8..5d079b46f2 100644 --- a/packages/loader/src/gltf/extensions/KHR_draco_mesh_compression.ts +++ b/packages/loader/src/gltf/extensions/KHR_draco_mesh_compression.ts @@ -1,23 +1,42 @@ +import { ModelMesh, TypedArray } from "@oasis-engine/core"; import { DRACODecoder } from "@oasis-engine/draco"; +import { Vector3 } from "@oasis-engine/math"; +import { AccessorType, IGLTF, IMesh, IMeshPrimitive } from "../GLTFSchema"; import { GLTFUtil } from "../GLTFUtil"; -import { registerExtension } from "../parser/Parser"; -import { ParserContext } from "../parser/ParserContext"; -import { IMeshPrimitive } from "../Schema"; -import { ExtensionParser } from "./ExtensionParser"; -import { IKHRDracoMeshCompression } from "./Schema"; - -@registerExtension("KHR_draco_mesh_compression") -class KHR_draco_mesh_compression extends ExtensionParser { +import { GLTFMeshParser } from "../parser"; +import { registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFParserContext } from "../parser/GLTFParserContext"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; +import { IKHRDracoMeshCompression } from "./GLTFExtensionSchema"; + +@registerGLTFExtension("KHR_draco_mesh_compression", GLTFExtensionMode.CreateAndParse) +class KHR_draco_mesh_compression extends GLTFExtensionParser { private static _decoder: DRACODecoder; + private static _tempVector3 = new Vector3(); + /** + * @override + */ initialize(): void { if (!KHR_draco_mesh_compression._decoder) { KHR_draco_mesh_compression._decoder = new DRACODecoder(); } } - createEngineResource(schema: IKHRDracoMeshCompression, context: ParserContext, gltfPrimitive: IMeshPrimitive) { - const { gltf, buffers } = context; + /** + * @override + */ + createAndParse( + context: GLTFParserContext, + schema: IKHRDracoMeshCompression, + gltfPrimitive: IMeshPrimitive, + gltfMesh: IMesh + ) { + const { + gltf, + buffers, + glTFResource: { engine } + } = context; const { bufferViews, accessors } = gltf; const { bufferView: bufferViewIndex, attributes: gltfAttributeMap } = schema; @@ -41,6 +60,154 @@ class KHR_draco_mesh_compression extends ExtensionParser { indexType }; const buffer = GLTFUtil.getBufferViewData(bufferViews[bufferViewIndex], buffers); - return KHR_draco_mesh_compression._decoder.decode(buffer, taskConfig).then((parsedGeometry) => parsedGeometry); + return KHR_draco_mesh_compression._decoder.decode(buffer, taskConfig).then((decodedGeometry) => { + const mesh = new ModelMesh(engine, gltfMesh.name); + return this._parseMeshFromGLTFPrimitiveDraco( + mesh, + gltfMesh, + gltfPrimitive, + gltf, + (attributeSemantic) => { + for (let j = 0; j < decodedGeometry.attributes.length; j++) { + if (decodedGeometry.attributes[j].name === attributeSemantic) { + return decodedGeometry.attributes[j].array; + } + } + return null; + }, + (attributeSemantic, shapeIndex) => { + throw "BlendShape animation is not supported when using draco."; + }, + () => { + return decodedGeometry.index.array; + }, + context.keepMeshData + ); + }); + } + + private _parseMeshFromGLTFPrimitiveDraco( + mesh: ModelMesh, + gltfMesh: IMesh, + gltfPrimitive: IMeshPrimitive, + gltf: IGLTF, + getVertexBufferData: (semantic: string) => TypedArray, + getBlendShapeData: (semantic: string, shapeIndex: number) => TypedArray, + getIndexBufferData: () => TypedArray, + keepMeshData: boolean + ): Promise { + const { attributes, targets, indices, mode } = gltfPrimitive; + let vertexCount: number; + + const { accessors } = gltf; + const accessor = accessors[attributes["POSITION"]]; + const positionBuffer = getVertexBufferData("POSITION"); + const positions = GLTFUtil.floatBufferToVector3Array(positionBuffer); + mesh.setPositions(positions); + + const { bounds } = mesh; + vertexCount = accessor.count; + if (accessor.min && accessor.max) { + bounds.min.copyFromArray(accessor.min); + bounds.max.copyFromArray(accessor.max); + } else { + const position = KHR_draco_mesh_compression._tempVector3; + const { min, max } = bounds; + + min.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); + max.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); + + const stride = positionBuffer.length / vertexCount; + for (let j = 0; j < vertexCount; j++) { + const offset = j * stride; + position.copyFromArray(positionBuffer, offset); + Vector3.min(min, position, min); + Vector3.max(max, position, max); + } + } + + for (const attributeSemantic in attributes) { + if (attributeSemantic === "POSITION") { + continue; + } + const bufferData = getVertexBufferData(attributeSemantic); + switch (attributeSemantic) { + case "NORMAL": + const normals = GLTFUtil.floatBufferToVector3Array(bufferData); + mesh.setNormals(normals); + break; + case "TEXCOORD_0": + const texturecoords = GLTFUtil.floatBufferToVector2Array(bufferData); + mesh.setUVs(texturecoords, 0); + break; + case "TEXCOORD_1": + const texturecoords1 = GLTFUtil.floatBufferToVector2Array(bufferData); + mesh.setUVs(texturecoords1, 1); + break; + case "TEXCOORD_2": + const texturecoords2 = GLTFUtil.floatBufferToVector2Array(bufferData); + mesh.setUVs(texturecoords2, 2); + break; + case "TEXCOORD_3": + const texturecoords3 = GLTFUtil.floatBufferToVector2Array(bufferData); + mesh.setUVs(texturecoords3, 3); + break; + case "TEXCOORD_4": + const texturecoords4 = GLTFUtil.floatBufferToVector2Array(bufferData); + mesh.setUVs(texturecoords4, 4); + break; + case "TEXCOORD_5": + const texturecoords5 = GLTFUtil.floatBufferToVector2Array(bufferData); + mesh.setUVs(texturecoords5, 5); + break; + case "TEXCOORD_6": + const texturecoords6 = GLTFUtil.floatBufferToVector2Array(bufferData); + mesh.setUVs(texturecoords6, 6); + break; + case "TEXCOORD_7": + const texturecoords7 = GLTFUtil.floatBufferToVector2Array(bufferData); + mesh.setUVs(texturecoords7, 7); + break; + case "COLOR_0": + const colors = GLTFUtil.floatBufferToColorArray( + bufferData, + accessors[attributes["COLOR_0"]].type === AccessorType.VEC3 + ); + mesh.setColors(colors); + break; + case "TANGENT": + const tangents = GLTFUtil.floatBufferToVector4Array(bufferData); + mesh.setTangents(tangents); + break; + + case "JOINTS_0": + const joints = GLTFUtil.floatBufferToVector4Array(bufferData); + mesh.setBoneIndices(joints); + break; + case "WEIGHTS_0": + const weights = GLTFUtil.floatBufferToVector4Array(bufferData); + mesh.setBoneWeights(weights); + break; + default: + // console.warn(`Unsupport attribute semantic ${attributeSemantic}.`); + break; + } + } + + // Indices + if (indices !== undefined) { + const indexAccessor = gltf.accessors[indices]; + const indexData = getIndexBufferData(); + mesh.setIndices(indexData); + mesh.addSubMesh(0, indexAccessor.count, mode); + } else { + mesh.addSubMesh(0, vertexCount, mode); + } + + // BlendShapes + targets && GLTFMeshParser._createBlendShape(mesh, gltfMesh, targets, getBlendShapeData); + + mesh.uploadData(!keepMeshData); + return Promise.resolve(mesh); } } diff --git a/packages/loader/src/gltf/extensions/KHR_lights_punctual.ts b/packages/loader/src/gltf/extensions/KHR_lights_punctual.ts index 67364b0cd2..ad1962a59a 100644 --- a/packages/loader/src/gltf/extensions/KHR_lights_punctual.ts +++ b/packages/loader/src/gltf/extensions/KHR_lights_punctual.ts @@ -1,13 +1,19 @@ import { DirectLight, Entity, PointLight, SpotLight } from "@oasis-engine/core"; -import { registerExtension } from "../parser/Parser"; -import { ParserContext } from "../parser/ParserContext"; -import { ExtensionParser } from "./ExtensionParser"; -import { IKHRLightsPunctual_Light } from "./Schema"; - -@registerExtension("KHR_lights_punctual") -class KHR_lights_punctual extends ExtensionParser { - parseEngineResource(schema: IKHRLightsPunctual_Light, entity: Entity, context: ParserContext): void { - const { color, intensity = 1, type, range, spot } = schema; +import { registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFParserContext } from "../parser/GLTFParserContext"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; +import { IKHRLightsPunctual, IKHRLightsPunctual_LightNode } from "./GLTFExtensionSchema"; + +@registerGLTFExtension("KHR_lights_punctual", GLTFExtensionMode.AdditiveParse) +class KHR_lights_punctual extends GLTFExtensionParser { + /** + * @override + */ + additiveParse(context: GLTFParserContext, entity: Entity, extensionSchema: IKHRLightsPunctual_LightNode): void { + const lightsSchema = (context.gltf.extensions.KHR_lights_punctual).lights; + const lightSchema = lightsSchema[extensionSchema.light]; + + const { color, intensity = 1, type, range, spot } = lightSchema; const glTFResource = context.glTFResource; let light: DirectLight | PointLight | SpotLight; diff --git a/packages/loader/src/gltf/extensions/KHR_materials_clearcoat.ts b/packages/loader/src/gltf/extensions/KHR_materials_clearcoat.ts index 8d1ad21f6b..8e060fa264 100644 --- a/packages/loader/src/gltf/extensions/KHR_materials_clearcoat.ts +++ b/packages/loader/src/gltf/extensions/KHR_materials_clearcoat.ts @@ -1,13 +1,16 @@ import { PBRMaterial } from "@oasis-engine/core"; -import { MaterialParser } from "../parser/MaterialParser"; -import { registerExtension } from "../parser/Parser"; -import { ParserContext } from "../parser/ParserContext"; -import { ExtensionParser } from "./ExtensionParser"; -import { IKHRMaterialsClearcoat } from "./Schema"; +import { GLTFMaterialParser } from "../parser/GLTFMaterialParser"; +import { registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFParserContext } from "../parser/GLTFParserContext"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; +import { IKHRMaterialsClearcoat } from "./GLTFExtensionSchema"; -@registerExtension("KHR_materials_clearcoat") -class KHR_materials_clearcoat extends ExtensionParser { - parseEngineResource(schema: IKHRMaterialsClearcoat, material: PBRMaterial, context: ParserContext): void { +@registerGLTFExtension("KHR_materials_clearcoat", GLTFExtensionMode.AdditiveParse) +class KHR_materials_clearcoat extends GLTFExtensionParser { + /** + * @override + */ + additiveParse(context: GLTFParserContext, material: PBRMaterial, schema: IKHRMaterialsClearcoat): void { const { textures } = context.glTFResource; const { clearcoatFactor = 0, @@ -22,15 +25,15 @@ class KHR_materials_clearcoat extends ExtensionParser { if (clearcoatTexture) { material.clearCoatTexture = textures[clearcoatTexture.index]; - MaterialParser._checkOtherTextureTransform(clearcoatTexture, "Clear coat"); + GLTFMaterialParser._checkOtherTextureTransform(clearcoatTexture, "Clear coat"); } if (clearcoatRoughnessTexture) { material.clearCoatRoughnessTexture = textures[clearcoatRoughnessTexture.index]; - MaterialParser._checkOtherTextureTransform(clearcoatRoughnessTexture, "Clear coat roughness"); + GLTFMaterialParser._checkOtherTextureTransform(clearcoatRoughnessTexture, "Clear coat roughness"); } if (clearcoatNormalTexture) { material.clearCoatNormalTexture = textures[clearcoatNormalTexture.index]; - MaterialParser._checkOtherTextureTransform(clearcoatNormalTexture, "Clear coat normal"); + GLTFMaterialParser._checkOtherTextureTransform(clearcoatNormalTexture, "Clear coat normal"); } } } diff --git a/packages/loader/src/gltf/extensions/KHR_materials_pbrSpecularGlossiness.ts b/packages/loader/src/gltf/extensions/KHR_materials_pbrSpecularGlossiness.ts index f339e3a6a6..6ee4a3588c 100644 --- a/packages/loader/src/gltf/extensions/KHR_materials_pbrSpecularGlossiness.ts +++ b/packages/loader/src/gltf/extensions/KHR_materials_pbrSpecularGlossiness.ts @@ -1,14 +1,22 @@ import { PBRSpecularMaterial } from "@oasis-engine/core"; import { Color } from "@oasis-engine/math"; -import { MaterialParser } from "../parser/MaterialParser"; -import { Parser, registerExtension } from "../parser/Parser"; -import { ParserContext } from "../parser/ParserContext"; -import { ExtensionParser } from "./ExtensionParser"; -import { IKHRMaterialsPbrSpecularGlossiness } from "./Schema"; +import { IMaterial } from "../GLTFSchema"; +import { GLTFMaterialParser } from "../parser/GLTFMaterialParser"; +import { GLTFParser, registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFParserContext } from "../parser/GLTFParserContext"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; +import { IKHRMaterialsPbrSpecularGlossiness } from "./GLTFExtensionSchema"; -@registerExtension("KHR_materials_pbrSpecularGlossiness") -class KHR_materials_pbrSpecularGlossiness extends ExtensionParser { - createEngineResource(schema: IKHRMaterialsPbrSpecularGlossiness, context: ParserContext): PBRSpecularMaterial { +@registerGLTFExtension("KHR_materials_pbrSpecularGlossiness", GLTFExtensionMode.CreateAndParse) +class KHR_materials_pbrSpecularGlossiness extends GLTFExtensionParser { + /** + * @override + */ + createAndParse( + context: GLTFParserContext, + schema: IKHRMaterialsPbrSpecularGlossiness, + ownerSchema: IMaterial + ): PBRSpecularMaterial { const { engine, textures } = context.glTFResource; const material = new PBRSpecularMaterial(engine); const { diffuseFactor, diffuseTexture, specularFactor, glossinessFactor, specularGlossinessTexture } = schema; @@ -24,10 +32,7 @@ class KHR_materials_pbrSpecularGlossiness extends ExtensionParser { if (diffuseTexture) { material.baseTexture = textures[diffuseTexture.index]; - const KHR_texture_transform = diffuseTexture.extensions?.KHR_texture_transform; - if (KHR_texture_transform) { - Parser.parseEngineResource("KHR_texture_transform", KHR_texture_transform, material, context); - } + GLTFParser.executeExtensionsAdditiveAndParse(diffuseTexture.extensions, context, material, diffuseTexture); } if (specularFactor) { @@ -44,9 +49,11 @@ class KHR_materials_pbrSpecularGlossiness extends ExtensionParser { if (specularGlossinessTexture) { material.specularGlossinessTexture = textures[specularGlossinessTexture.index]; - MaterialParser._checkOtherTextureTransform(specularGlossinessTexture, "Specular glossiness"); + GLTFMaterialParser._checkOtherTextureTransform(specularGlossinessTexture, "Specular glossiness"); } + material.name = ownerSchema.name; + GLTFMaterialParser._parseStandardProperty(context, material, ownerSchema); return material; } } diff --git a/packages/loader/src/gltf/extensions/KHR_materials_unlit.ts b/packages/loader/src/gltf/extensions/KHR_materials_unlit.ts index f27ed6a8e8..0ab7bd0745 100644 --- a/packages/loader/src/gltf/extensions/KHR_materials_unlit.ts +++ b/packages/loader/src/gltf/extensions/KHR_materials_unlit.ts @@ -1,15 +1,21 @@ import { UnlitMaterial } from "@oasis-engine/core"; -import { registerExtension } from "../parser/Parser"; -import { ParserContext } from "../parser/ParserContext"; -import { ExtensionParser } from "./ExtensionParser"; -import { IKHRMaterialsUnlit } from "./Schema"; +import { IMaterial } from "../GLTFSchema"; +import { GLTFMaterialParser } from "../parser/GLTFMaterialParser"; +import { registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFParserContext } from "../parser/GLTFParserContext"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; -@registerExtension("KHR_materials_unlit") -class KHR_materials_unlit extends ExtensionParser { - createEngineResource(schema: IKHRMaterialsUnlit, context: ParserContext): UnlitMaterial { +@registerGLTFExtension("KHR_materials_unlit", GLTFExtensionMode.CreateAndParse) +class KHR_materials_unlit extends GLTFExtensionParser { + /** + * @override + */ + createAndParse(context: GLTFParserContext, _, ownerSchema: IMaterial): UnlitMaterial { const { engine } = context.glTFResource; const material = new UnlitMaterial(engine); + material.name = ownerSchema.name; + GLTFMaterialParser._parseStandardProperty(context, material, ownerSchema); return material; } } diff --git a/packages/loader/src/gltf/extensions/KHR_materials_variants.ts b/packages/loader/src/gltf/extensions/KHR_materials_variants.ts index 7f542af3d2..234baff165 100644 --- a/packages/loader/src/gltf/extensions/KHR_materials_variants.ts +++ b/packages/loader/src/gltf/extensions/KHR_materials_variants.ts @@ -1,12 +1,21 @@ -import { Renderer } from "@oasis-engine/core"; -import { registerExtension } from "../parser/Parser"; -import { ParserContext } from "../parser/ParserContext"; -import { ExtensionParser } from "./ExtensionParser"; -import { IKHRMaterialVariants_Mapping } from "./Schema"; +import { Material, Renderer } from "@oasis-engine/core"; +import { registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFParserContext } from "../parser/GLTFParserContext"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; +import { IKHRMaterialVariants_Mapping } from "./GLTFExtensionSchema"; -@registerExtension("KHR_materials_variants") -class KHR_materials_variants extends ExtensionParser { - parseEngineResource(schema: IKHRMaterialVariants_Mapping, renderer: Renderer, context: ParserContext): void { +export type IGLTFExtensionVariants = Array<{ + renderer: Renderer; + material: Material; + variants: string[]; +}>; + +@registerGLTFExtension("KHR_materials_variants", GLTFExtensionMode.AdditiveParse) +class KHR_materials_variants extends GLTFExtensionParser { + /** + * @override + */ + additiveParse(context: GLTFParserContext, renderer: Renderer, schema: IKHRMaterialVariants_Mapping): void { const { gltf: { extensions: { @@ -17,10 +26,13 @@ class KHR_materials_variants extends ExtensionParser { } = context; const { mappings } = schema; + if (!glTFResource.extensionsData) glTFResource.extensionsData = {}; + const extensionData: IGLTFExtensionVariants = []; + glTFResource.extensionsData.variants = extensionData; + for (let i = 0; i < mappings.length; i++) { const { material, variants } = mappings[i]; - if (!glTFResource.variants) glTFResource.variants = []; - glTFResource.variants.push({ + extensionData.push({ renderer, material: glTFResource.materials[material], variants: variants.map((index) => variantNames[index].name) diff --git a/packages/loader/src/gltf/extensions/KHR_mesh_quantization.ts b/packages/loader/src/gltf/extensions/KHR_mesh_quantization.ts index bf5bcbab2f..789dc4e274 100644 --- a/packages/loader/src/gltf/extensions/KHR_mesh_quantization.ts +++ b/packages/loader/src/gltf/extensions/KHR_mesh_quantization.ts @@ -1,5 +1,5 @@ -import { registerExtension } from "../parser/Parser"; -import { ExtensionParser } from "./ExtensionParser"; +import { registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; -@registerExtension("KHR_mesh_quantization") -class KHR_mesh_quantization extends ExtensionParser {} +@registerGLTFExtension("KHR_mesh_quantization", GLTFExtensionMode.AdditiveParse) +class KHR_mesh_quantization extends GLTFExtensionParser {} diff --git a/packages/loader/src/gltf/extensions/KHR_texture_transform.ts b/packages/loader/src/gltf/extensions/KHR_texture_transform.ts index ec2b7facb1..ccd1a19d35 100644 --- a/packages/loader/src/gltf/extensions/KHR_texture_transform.ts +++ b/packages/loader/src/gltf/extensions/KHR_texture_transform.ts @@ -1,15 +1,19 @@ import { Logger, PBRBaseMaterial, UnlitMaterial } from "@oasis-engine/core"; -import { registerExtension } from "../parser/Parser"; -import { ParserContext } from "../parser/ParserContext"; -import { ExtensionParser } from "./ExtensionParser"; -import { IKHRTextureTransform } from "./Schema"; +import { registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFParserContext } from "../parser/GLTFParserContext"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; +import { IKHRTextureTransform } from "./GLTFExtensionSchema"; -@registerExtension("KHR_texture_transform") -class KHR_texture_transform extends ExtensionParser { - parseEngineResource( - schema: IKHRTextureTransform, +@registerGLTFExtension("KHR_texture_transform", GLTFExtensionMode.AdditiveParse) +class KHR_texture_transform extends GLTFExtensionParser { + + /** + * @override + */ + additiveParse( + context: GLTFParserContext, material: PBRBaseMaterial | UnlitMaterial, - context: ParserContext + schema: IKHRTextureTransform ): void { const { offset, rotation, scale, texCoord } = schema; diff --git a/packages/loader/src/gltf/extensions/OASIS_materials_remap.ts b/packages/loader/src/gltf/extensions/OASIS_materials_remap.ts index d653028800..3c992e8f65 100644 --- a/packages/loader/src/gltf/extensions/OASIS_materials_remap.ts +++ b/packages/loader/src/gltf/extensions/OASIS_materials_remap.ts @@ -1,12 +1,15 @@ import { Material } from "@oasis-engine/core"; -import { registerExtension } from "../parser/Parser"; -import { ParserContext } from "../parser/ParserContext"; -import { ExtensionParser } from "./ExtensionParser"; -import { IOasisMaterialRemap } from "./Schema"; +import { registerGLTFExtension } from "../parser/GLTFParser"; +import { GLTFParserContext } from "../parser/GLTFParserContext"; +import { GLTFExtensionMode, GLTFExtensionParser } from "./GLTFExtensionParser"; +import { IOasisMaterialRemap } from "./GLTFExtensionSchema"; -@registerExtension("OASIS_materials_remap") -class OasisMaterialsRemap extends ExtensionParser { - createEngineResource(schema: IOasisMaterialRemap, context: ParserContext): Promise { +@registerGLTFExtension("OASIS_materials_remap", GLTFExtensionMode.CreateAndParse) +class OasisMaterialsRemap extends GLTFExtensionParser { + /** + * @override + */ + createAndParse(context: GLTFParserContext, schema: IOasisMaterialRemap): Promise { const { engine } = context.glTFResource; // @ts-ignore return engine.resourceManager.getResourceByRef(schema); diff --git a/packages/loader/src/gltf/extensions/index.ts b/packages/loader/src/gltf/extensions/index.ts index a9ee9e029c..d5791a43f2 100644 --- a/packages/loader/src/gltf/extensions/index.ts +++ b/packages/loader/src/gltf/extensions/index.ts @@ -6,9 +6,12 @@ import "./KHR_materials_pbrSpecularGlossiness"; import "./KHR_materials_sheen"; import "./KHR_materials_transmission"; import "./KHR_materials_unlit"; -import "./KHR_materials_variants"; +export type { IGLTFExtensionVariants } from "./KHR_materials_variants"; import "./KHR_materials_volume"; import "./KHR_mesh_quantization"; import "./KHR_texture_basisu"; import "./KHR_texture_transform"; import "./OASIS_materials_remap"; + +export { GLTFExtensionParser, GLTFExtensionMode } from "./GLTFExtensionParser"; +export * from "./GLTFExtensionSchema"; diff --git a/packages/loader/src/gltf/index.ts b/packages/loader/src/gltf/index.ts new file mode 100644 index 0000000000..e42469dcbf --- /dev/null +++ b/packages/loader/src/gltf/index.ts @@ -0,0 +1,6 @@ +export { GLTFPipeline } from "./GLTFPipeline"; +export { GLTFResource } from "./GLTFResource"; +export { GLTFUtil } from "./GLTFUtil"; +export * from "./parser"; +export * from "./extensions/index"; +export type { IMaterial, IMeshPrimitive, ITextureInfo, INode, GLTFExtensionOwnerSchema } from "./GLTFSchema"; diff --git a/packages/loader/src/gltf/parser/AnimationParser.ts b/packages/loader/src/gltf/parser/GLTFAnimationParser.ts similarity index 96% rename from packages/loader/src/gltf/parser/AnimationParser.ts rename to packages/loader/src/gltf/parser/GLTFAnimationParser.ts index fa6556f674..00e94930d9 100644 --- a/packages/loader/src/gltf/parser/AnimationParser.ts +++ b/packages/loader/src/gltf/parser/GLTFAnimationParser.ts @@ -14,12 +14,12 @@ import { } from "@oasis-engine/core"; import { Quaternion, Vector3, Vector4 } from "@oasis-engine/math"; import { GLTFUtil } from "../GLTFUtil"; -import { AccessorType, AnimationChannelTargetPath, AnimationSamplerInterpolation, IAnimationChannel } from "../Schema"; -import { Parser } from "./Parser"; -import { ParserContext } from "./ParserContext"; +import { AccessorType, AnimationChannelTargetPath, AnimationSamplerInterpolation, IAnimationChannel } from "../GLTFSchema"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFParserContext } from "./GLTFParserContext"; -export class AnimationParser extends Parser { - parse(context: ParserContext): AssetPromise { +export class GLTFAnimationParser extends GLTFParser { + parse(context: GLTFParserContext): AssetPromise { const { gltf, buffers, glTFResource } = context; const { entities } = glTFResource; const { animations, accessors } = gltf; diff --git a/packages/loader/src/gltf/parser/BufferParser.ts b/packages/loader/src/gltf/parser/GLTFBufferParser.ts similarity index 79% rename from packages/loader/src/gltf/parser/BufferParser.ts rename to packages/loader/src/gltf/parser/GLTFBufferParser.ts index 92ceeb4cee..a92a6fdf2e 100644 --- a/packages/loader/src/gltf/parser/BufferParser.ts +++ b/packages/loader/src/gltf/parser/GLTFBufferParser.ts @@ -1,11 +1,11 @@ import { AssetPromise, request } from "@oasis-engine/core"; import { GLTFUtil } from "../GLTFUtil"; -import { IBuffer, IGLTF } from "../Schema"; -import { Parser } from "./Parser"; -import { ParserContext } from "./ParserContext"; +import { IBuffer, IGLTF } from "../GLTFSchema"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFParserContext } from "./GLTFParserContext"; -export class BufferParser extends Parser { - parse(context: ParserContext): AssetPromise { +export class GLTFBufferParser extends GLTFParser { + parse(context: GLTFParserContext): AssetPromise { const glTFResource = context.glTFResource; const { url } = glTFResource; diff --git a/packages/loader/src/gltf/parser/EntityParser.ts b/packages/loader/src/gltf/parser/GLTFEntityParser.ts similarity index 82% rename from packages/loader/src/gltf/parser/EntityParser.ts rename to packages/loader/src/gltf/parser/GLTFEntityParser.ts index cdc1ec079c..b5e9dfd6d4 100644 --- a/packages/loader/src/gltf/parser/EntityParser.ts +++ b/packages/loader/src/gltf/parser/GLTFEntityParser.ts @@ -1,13 +1,13 @@ import { Entity } from "@oasis-engine/core"; import { GLTFResource } from "../GLTFResource"; -import { Parser } from "./Parser"; -import { ParserContext } from "./ParserContext"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFParserContext } from "./GLTFParserContext"; -export class EntityParser extends Parser { +export class GLTFEntityParser extends GLTFParser { /** @internal */ static _defaultName: String = "_GLTF_ENTITY_"; - parse(context: ParserContext): void { + parse(context: GLTFParserContext): void { const { glTFResource, gltf: { nodes } @@ -22,7 +22,7 @@ export class EntityParser extends Parser { for (let i = 0; i < nodes.length; i++) { const gltfNode = nodes[i]; const { matrix, translation, rotation, scale } = gltfNode; - const entity = new Entity(engine, gltfNode.name || `${EntityParser._defaultName}${i}`); + const entity = new Entity(engine, gltfNode.name || `${GLTFEntityParser._defaultName}${i}`); const { transform } = entity; if (matrix) { @@ -49,7 +49,7 @@ export class EntityParser extends Parser { this._createSceneRoots(context, glTFResource); } - private _buildEntityTree(context: ParserContext, glTFResource: GLTFResource): void { + private _buildEntityTree(context: GLTFParserContext, glTFResource: GLTFResource): void { const { gltf: { nodes } } = context; @@ -69,7 +69,7 @@ export class EntityParser extends Parser { } } - private _createSceneRoots(context: ParserContext, glTFResource: GLTFResource): void { + private _createSceneRoots(context: GLTFParserContext, glTFResource: GLTFResource): void { const { scene: sceneID = 0, scenes } = context.gltf; const { engine, entities } = glTFResource; diff --git a/packages/loader/src/gltf/parser/GLTFMaterialParser.ts b/packages/loader/src/gltf/parser/GLTFMaterialParser.ts new file mode 100644 index 0000000000..991ff3799b --- /dev/null +++ b/packages/loader/src/gltf/parser/GLTFMaterialParser.ts @@ -0,0 +1,166 @@ +import { + AssetPromise, + Logger, + Material, + PBRMaterial, + PBRSpecularMaterial, + RenderFace, + TextureCoordinate, + UnlitMaterial +} from "@oasis-engine/core"; +import { Color } from "@oasis-engine/math"; +import { IMaterial, ITextureInfo, MaterialAlphaMode } from "../GLTFSchema"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFParserContext } from "./GLTFParserContext"; + +export class GLTFMaterialParser extends GLTFParser { + /** + * @internal + */ + static _checkOtherTextureTransform(texture: ITextureInfo, textureName: string): void { + if (texture.extensions?.KHR_texture_transform) { + Logger.warn(`${textureName} texture always use the KHR_texture_transform of the base texture.`); + } + } + + /** + * @internal + */ + static _parseStandardProperty( + context: GLTFParserContext, + material: UnlitMaterial | PBRMaterial | PBRSpecularMaterial, + materialInfo: IMaterial + ) { + const { textures } = context.glTFResource; + const { + pbrMetallicRoughness, + normalTexture, + occlusionTexture, + emissiveTexture, + emissiveFactor, + alphaMode, + alphaCutoff, + doubleSided + } = materialInfo; + + if (pbrMetallicRoughness) { + const { baseColorFactor, baseColorTexture, metallicFactor, roughnessFactor, metallicRoughnessTexture } = + pbrMetallicRoughness; + + if (baseColorFactor) { + material.baseColor = new Color( + Color.linearToGammaSpace(baseColorFactor[0]), + Color.linearToGammaSpace(baseColorFactor[1]), + Color.linearToGammaSpace(baseColorFactor[2]), + baseColorFactor[3] + ); + } + if (baseColorTexture) { + material.baseTexture = textures[baseColorTexture.index]; + GLTFParser.executeExtensionsAdditiveAndParse(baseColorTexture.extensions, context, material, baseColorTexture); + } + + if (material.constructor === PBRMaterial) { + material.metallic = metallicFactor ?? 1; + material.roughness = roughnessFactor ?? 1; + if (metallicRoughnessTexture) { + material.roughnessMetallicTexture = textures[metallicRoughnessTexture.index]; + GLTFMaterialParser._checkOtherTextureTransform(metallicRoughnessTexture, "Roughness metallic"); + } + } + } + + if (material.constructor === PBRMaterial || material.constructor === PBRSpecularMaterial) { + if (emissiveTexture) { + material.emissiveTexture = textures[emissiveTexture.index]; + GLTFMaterialParser._checkOtherTextureTransform(emissiveTexture, "Emissive"); + } + + if (emissiveFactor) { + material.emissiveColor = new Color( + Color.linearToGammaSpace(emissiveFactor[0]), + Color.linearToGammaSpace(emissiveFactor[1]), + Color.linearToGammaSpace(emissiveFactor[2]) + ); + } + + if (normalTexture) { + const { index, scale } = normalTexture; + material.normalTexture = textures[index]; + GLTFMaterialParser._checkOtherTextureTransform(normalTexture, "Normal"); + + if (scale !== undefined) { + material.normalTextureIntensity = scale; + } + } + + if (occlusionTexture) { + const { index, strength, texCoord } = occlusionTexture; + material.occlusionTexture = textures[index]; + GLTFMaterialParser._checkOtherTextureTransform(occlusionTexture, "Occlusion"); + + if (strength !== undefined) { + material.occlusionTextureIntensity = strength; + } + if (texCoord === TextureCoordinate.UV1) { + material.occlusionTextureCoord = TextureCoordinate.UV1; + } else if (texCoord > TextureCoordinate.UV1) { + Logger.warn("Occlusion texture uv coordinate must be UV0 or UV1."); + } + } + } + + if (doubleSided) { + material.renderFace = RenderFace.Double; + } else { + material.renderFace = RenderFace.Front; + } + + switch (alphaMode) { + case MaterialAlphaMode.OPAQUE: + material.isTransparent = false; + break; + case MaterialAlphaMode.BLEND: + material.isTransparent = true; + break; + case MaterialAlphaMode.MASK: + material.alphaCutoff = alphaCutoff ?? 0.5; + break; + } + } + + parse(context: GLTFParserContext): AssetPromise { + const { gltf, glTFResource, materialsPromiseInfo } = context; + if (!gltf.materials) return; + + const { engine } = glTFResource; + + let materialPromises = []; + + for (let i = 0; i < gltf.materials.length; i++) { + const materialInfo = gltf.materials[i]; + + let material = >( + GLTFParser.executeExtensionsCreateAndParse(materialInfo.extensions, context, materialInfo) + ); + + if (!material) { + material = new PBRMaterial(engine); + material.name = materialInfo.name; + GLTFMaterialParser._parseStandardProperty(context, material as PBRMaterial, materialInfo); + } + + materialPromises.push(material); + } + + return AssetPromise.all(materialPromises).then((materials) => { + glTFResource.materials = materials; + for (let i = 0; i < gltf.materials.length; i++) { + const materialInfo = gltf.materials[i]; + GLTFParser.executeExtensionsAdditiveAndParse(materialInfo.extensions, context, materials[i], materialInfo); + } + materialsPromiseInfo.resolve(materials); + return materialsPromiseInfo.promise; + }); + } +} diff --git a/packages/loader/src/gltf/parser/MeshParser.ts b/packages/loader/src/gltf/parser/GLTFMeshParser.ts similarity index 52% rename from packages/loader/src/gltf/parser/MeshParser.ts rename to packages/loader/src/gltf/parser/GLTFMeshParser.ts index 8795bf03f8..ff54988955 100644 --- a/packages/loader/src/gltf/parser/MeshParser.ts +++ b/packages/loader/src/gltf/parser/GLTFMeshParser.ts @@ -4,118 +4,24 @@ import { Buffer, BufferBindFlag, BufferUsage, - EngineObject, ModelMesh, TypedArray, VertexElement } from "@oasis-engine/core"; import { Vector3 } from "@oasis-engine/math"; +import { IGLTF, IMesh, IMeshPrimitive } from "../GLTFSchema"; import { GLTFUtil } from "../GLTFUtil"; -import { AccessorType, IGLTF, IMesh, IMeshPrimitive } from "../Schema"; -import { Parser } from "./Parser"; -import { ParserContext } from "./ParserContext"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFParserContext } from "./GLTFParserContext"; -export class MeshParser extends Parser { +export class GLTFMeshParser extends GLTFParser { private static _tempVector3 = new Vector3(); - parse(context: ParserContext) { - const { gltf, buffers, glTFResource } = context; - const { engine } = glTFResource; - if (!gltf.meshes) return; - - const meshesPromiseInfo = context.meshesPromiseInfo; - const meshPromises: Promise[] = []; - - for (let i = 0; i < gltf.meshes.length; i++) { - const gltfMesh = gltf.meshes[i]; - const primitivePromises: Promise[] = []; - - for (let j = 0; j < gltfMesh.primitives.length; j++) { - const gltfPrimitive = gltfMesh.primitives[j]; - const { extensions = {} } = gltfPrimitive; - const { KHR_draco_mesh_compression } = extensions; - - primitivePromises[j] = new Promise((resolve) => { - const mesh = new ModelMesh(engine, gltfMesh.name || j + ""); - - if (KHR_draco_mesh_compression) { - (>( - Parser.createEngineResource( - "KHR_draco_mesh_compression", - KHR_draco_mesh_compression, - context, - gltfPrimitive - ) - )) - .then((decodedGeometry: any) => { - return this._parseMeshFromGLTFPrimitiveDraco( - mesh, - gltfMesh, - gltfPrimitive, - gltf, - (attributeSemantic) => { - for (let j = 0; j < decodedGeometry.attributes.length; j++) { - if (decodedGeometry.attributes[j].name === attributeSemantic) { - return decodedGeometry.attributes[j].array; - } - } - return null; - }, - (attributeSemantic, shapeIndex) => { - throw "BlendShape animation is not supported when using draco."; - }, - () => { - return decodedGeometry.index.array; - }, - context.keepMeshData - ); - }) - .then(resolve); - } else { - this._parseMeshFromGLTFPrimitive( - context, - mesh, - gltfMesh, - gltfPrimitive, - gltf, - (attributeSemantic) => { - return null; - }, - (attributeName, shapeIndex) => { - const shapeAccessorIdx = gltfPrimitive.targets[shapeIndex]; - const attributeAccessorIdx = shapeAccessorIdx[attributeName]; - if (attributeAccessorIdx) { - const accessor = gltf.accessors[attributeAccessorIdx]; - return GLTFUtil.getAccessorData(gltf, accessor, buffers); - } else { - return null; - } - }, - () => { - const indexAccessor = gltf.accessors[gltfPrimitive.indices]; - return GLTFUtil.getAccessorData(gltf, indexAccessor, buffers); - }, - context.keepMeshData - ).then(resolve); - } - }); - } - - meshPromises[i] = Promise.all(primitivePromises); - } - - AssetPromise.all(meshPromises) - .then((meshes: ModelMesh[][]) => { - glTFResource.meshes = meshes; - meshesPromiseInfo.resolve(meshes); - }) - .catch(meshesPromiseInfo.reject); - - return meshesPromiseInfo.promise; - } - - private _parseMeshFromGLTFPrimitive( - context: ParserContext, + /** + * @internal + */ + static _parseMeshFromGLTFPrimitive( + context: GLTFParserContext, mesh: ModelMesh, gltfMesh: IMesh, gltfPrimitive: IMeshPrimitive, @@ -182,7 +88,7 @@ export class MeshParser extends Parser { min.copyFromArray(accessor.min); max.copyFromArray(accessor.max); } else { - const position = MeshParser._tempVector3; + const position = GLTFMeshParser._tempVector3; min.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); max.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); @@ -215,13 +121,16 @@ export class MeshParser extends Parser { } // BlendShapes - targets && this._createBlendShape(mesh, gltfMesh, targets, getBlendShapeData); + targets && GLTFMeshParser._createBlendShape(mesh, gltfMesh, targets, getBlendShapeData); mesh.uploadData(!keepMeshData); return Promise.resolve(mesh); } - private _createBlendShape( + /** + * @internal + */ + static _createBlendShape( mesh: ModelMesh, glTFMesh: IMesh, glTFTargets: { @@ -246,131 +155,73 @@ export class MeshParser extends Parser { } } - /** - * @deprecated - */ - private _parseMeshFromGLTFPrimitiveDraco( - mesh: ModelMesh, - gltfMesh: IMesh, - gltfPrimitive: IMeshPrimitive, - gltf: IGLTF, - getVertexBufferData: (semantic: string) => TypedArray, - getBlendShapeData: (semantic: string, shapeIndex: number) => TypedArray, - getIndexBufferData: () => TypedArray, - keepMeshData: boolean - ): Promise { - const { attributes, targets, indices, mode } = gltfPrimitive; - let vertexCount: number; - - const { accessors } = gltf; - const accessor = accessors[attributes["POSITION"]]; - const positionBuffer = getVertexBufferData("POSITION"); - const positions = GLTFUtil.floatBufferToVector3Array(positionBuffer); - mesh.setPositions(positions); + parse(context: GLTFParserContext) { + const { gltf, buffers, glTFResource } = context; + const { engine } = glTFResource; + if (!gltf.meshes) return; - const { bounds } = mesh; - vertexCount = accessor.count; - if (accessor.min && accessor.max) { - bounds.min.copyFromArray(accessor.min); - bounds.max.copyFromArray(accessor.max); - } else { - const position = MeshParser._tempVector3; - const { min, max } = bounds; + const meshesPromiseInfo = context.meshesPromiseInfo; + const meshPromises: Promise[] = []; - min.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); - max.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); + for (let i = 0; i < gltf.meshes.length; i++) { + const gltfMesh = gltf.meshes[i]; + const primitivePromises: Promise[] = []; - const stride = positionBuffer.length / vertexCount; - for (let j = 0; j < vertexCount; j++) { - const offset = j * stride; - position.copyFromArray(positionBuffer, offset); - Vector3.min(min, position, min); - Vector3.max(max, position, max); - } - } + for (let j = 0; j < gltfMesh.primitives.length; j++) { + const gltfPrimitive = gltfMesh.primitives[j]; - for (const attributeSemantic in attributes) { - if (attributeSemantic === "POSITION") { - continue; - } - const bufferData = getVertexBufferData(attributeSemantic); - switch (attributeSemantic) { - case "NORMAL": - const normals = GLTFUtil.floatBufferToVector3Array(bufferData); - mesh.setNormals(normals); - break; - case "TEXCOORD_0": - const texturecoords = GLTFUtil.floatBufferToVector2Array(bufferData); - mesh.setUVs(texturecoords, 0); - break; - case "TEXCOORD_1": - const texturecoords1 = GLTFUtil.floatBufferToVector2Array(bufferData); - mesh.setUVs(texturecoords1, 1); - break; - case "TEXCOORD_2": - const texturecoords2 = GLTFUtil.floatBufferToVector2Array(bufferData); - mesh.setUVs(texturecoords2, 2); - break; - case "TEXCOORD_3": - const texturecoords3 = GLTFUtil.floatBufferToVector2Array(bufferData); - mesh.setUVs(texturecoords3, 3); - break; - case "TEXCOORD_4": - const texturecoords4 = GLTFUtil.floatBufferToVector2Array(bufferData); - mesh.setUVs(texturecoords4, 4); - break; - case "TEXCOORD_5": - const texturecoords5 = GLTFUtil.floatBufferToVector2Array(bufferData); - mesh.setUVs(texturecoords5, 5); - break; - case "TEXCOORD_6": - const texturecoords6 = GLTFUtil.floatBufferToVector2Array(bufferData); - mesh.setUVs(texturecoords6, 6); - break; - case "TEXCOORD_7": - const texturecoords7 = GLTFUtil.floatBufferToVector2Array(bufferData); - mesh.setUVs(texturecoords7, 7); - break; - case "COLOR_0": - const colors = GLTFUtil.floatBufferToColorArray( - bufferData, - accessors[attributes["COLOR_0"]].type === AccessorType.VEC3 + primitivePromises[j] = new Promise((resolve) => { + const mesh = >( + GLTFParser.executeExtensionsCreateAndParse(gltfPrimitive.extensions, context, gltfPrimitive, gltfMesh) ); - mesh.setColors(colors); - break; - case "TANGENT": - const tangents = GLTFUtil.floatBufferToVector4Array(bufferData); - mesh.setTangents(tangents); - break; - case "JOINTS_0": - const joints = GLTFUtil.floatBufferToVector4Array(bufferData); - mesh.setBoneIndices(joints); - break; - case "WEIGHTS_0": - const weights = GLTFUtil.floatBufferToVector4Array(bufferData); - mesh.setBoneWeights(weights); - break; - default: - // console.warn(`Unsupport attribute semantic ${attributeSemantic}.`); - break; + if (mesh) { + if (mesh instanceof ModelMesh) { + resolve(mesh); + } else { + mesh.then((mesh) => resolve(mesh)); + } + } else { + const mesh = new ModelMesh(engine, gltfMesh.name || j + ""); + GLTFMeshParser._parseMeshFromGLTFPrimitive( + context, + mesh, + gltfMesh, + gltfPrimitive, + gltf, + (attributeSemantic) => { + return null; + }, + (attributeName, shapeIndex) => { + const shapeAccessorIdx = gltfPrimitive.targets[shapeIndex]; + const attributeAccessorIdx = shapeAccessorIdx[attributeName]; + if (attributeAccessorIdx) { + const accessor = gltf.accessors[attributeAccessorIdx]; + return GLTFUtil.getAccessorData(gltf, accessor, buffers); + } else { + return null; + } + }, + () => { + const indexAccessor = gltf.accessors[gltfPrimitive.indices]; + return GLTFUtil.getAccessorData(gltf, indexAccessor, buffers); + }, + context.keepMeshData + ).then(resolve); + } + }); } - } - // Indices - if (indices !== undefined) { - const indexAccessor = gltf.accessors[indices]; - const indexData = getIndexBufferData(); - mesh.setIndices(indexData); - mesh.addSubMesh(0, indexAccessor.count, mode); - } else { - mesh.addSubMesh(0, vertexCount, mode); + meshPromises[i] = Promise.all(primitivePromises); } - // BlendShapes - targets && this._createBlendShape(mesh, gltfMesh, targets, getBlendShapeData); + AssetPromise.all(meshPromises) + .then((meshes: ModelMesh[][]) => { + glTFResource.meshes = meshes; + meshesPromiseInfo.resolve(meshes); + }) + .catch(meshesPromiseInfo.reject); - mesh.uploadData(!keepMeshData); - return Promise.resolve(mesh); + return meshesPromiseInfo.promise; } } diff --git a/packages/loader/src/gltf/parser/GLTFParser.ts b/packages/loader/src/gltf/parser/GLTFParser.ts new file mode 100644 index 0000000000..f9704785e8 --- /dev/null +++ b/packages/loader/src/gltf/parser/GLTFParser.ts @@ -0,0 +1,160 @@ +import { AnimationClip, AssetPromise, EngineObject, Material, Mesh } from "@oasis-engine/core"; +import { GLTFExtensionMode, GLTFExtensionParser } from "../extensions/GLTFExtensionParser"; +import { GLTFExtensionSchema } from "../extensions/GLTFExtensionSchema"; +import { GLTFExtensionOwnerSchema } from "../GLTFSchema"; +import { GLTFParserContext } from "./GLTFParserContext"; + +/** + * Base class of glTF parser. + */ +export abstract class GLTFParser { + private static readonly _extensionParsers: Record = {}; + + /** + * Execute all parses of extension to initialize plugin. + * @remarks Some plugins require initialization. + * @returns The void or promise + */ + static executeExtensionsInitialize(extensionName: string): void | Promise { + const parsers = GLTFParser._extensionParsers[extensionName]; + const length = parsers?.length; + + if (length) { + return parsers[length - 1].initialize(); + } + } + + /** + * Execute all parses of extension to create resource. + * @param extensions - Related extensions field + * @param context - The parser context + * @param ownerSchema - The extension owner schema + * @param extra - Extra params + * @returns + */ + static executeExtensionsCreateAndParse( + extensions: { [key: string]: any } = {}, + context: GLTFParserContext, + ownerSchema: GLTFExtensionOwnerSchema, + ...extra + ): EngineObject | void | Promise { + let resource: EngineObject | Promise = null; + + const extensionArray = Object.keys(extensions); + for (let i = extensionArray.length - 1; i >= 0; --i) { + const extensionName = extensionArray[i]; + const extensionSchema = extensions[extensionName]; + + resource = >( + GLTFParser._createAndParse(extensionName, context, extensionSchema, ownerSchema, ...extra) + ); + if (resource) { + return resource; + } + } + } + + /** + * Execute all parses of extension to parse resource. + * @param extensions - Related extensions field + * @param context - The parser context + * @param parseResource - The parsed resource + * @param ownerSchema - The extension owner schema + * @param extra - Extra params + */ + static executeExtensionsAdditiveAndParse( + extensions: { [key: string]: any }, + context: GLTFParserContext, + parseResource: EngineObject, + ownerSchema: GLTFExtensionOwnerSchema, + ...extra + ): void { + for (let extensionName in extensions) { + const extensionSchema = extensions[extensionName]; + GLTFParser._additiveParse(extensionName, context, parseResource, extensionSchema, ownerSchema, ...extra); + } + } + + /** + * Whether the plugin is registered. + * @param extensionName - Extension name + * @returns Boolean + */ + static hasExtensionParser(extensionName: string): boolean { + return !!GLTFParser._extensionParsers[extensionName]?.length; + } + + /** + * Get the last plugin by glTF extension mode. + * @param extensionName - Extension name + * @param mode - GLTF extension mode + * @returns GLTF extension parser + */ + static getExtensionParser(extensionName: string, mode: GLTFExtensionMode): GLTFExtensionParser | undefined { + const parsers = GLTFParser._extensionParsers[extensionName]; + const length = parsers?.length; + + if (length) { + // only use the last parser. + for (let i = length - 1; i >= 0; --i) { + const currentParser = parsers[i]; + if (currentParser._mode === mode) { + return currentParser; + } + } + } + } + + /** + * @internal + */ + static _addExtensionParser(extensionName: string, extensionParser: GLTFExtensionParser) { + if (!GLTFParser._extensionParsers[extensionName]) { + GLTFParser._extensionParsers[extensionName] = []; + } + GLTFParser._extensionParsers[extensionName].push(extensionParser); + } + + private static _createAndParse( + extensionName: string, + context: GLTFParserContext, + extensionSchema: GLTFExtensionSchema, + ownerSchema: GLTFExtensionOwnerSchema, + ...extra + ): EngineObject | Promise { + const parser = GLTFParser.getExtensionParser(extensionName, GLTFExtensionMode.CreateAndParse); + + if (parser) { + return parser.createAndParse(context, extensionSchema, ownerSchema, ...extra); + } + } + + private static _additiveParse( + extensionName: string, + context: GLTFParserContext, + parseResource: EngineObject, + extensionSchema: GLTFExtensionSchema, + ownerSchema: GLTFExtensionOwnerSchema, + ...extra + ): void { + const parser = GLTFParser.getExtensionParser(extensionName, GLTFExtensionMode.AdditiveParse); + + if (parser) { + parser.additiveParse(context, parseResource, extensionSchema, ownerSchema, ...extra); + } + } + + abstract parse(context: GLTFParserContext): AssetPromise | void | Material | AnimationClip | Mesh; +} + +/** + * Declare ExtensionParser's decorator. + * @param extensionName - Extension name + */ +export function registerGLTFExtension(extensionName: string, mode: GLTFExtensionMode) { + return (parser: new () => GLTFExtensionParser) => { + const extensionParser = new parser(); + extensionParser._mode = mode; + GLTFParser._addExtensionParser(extensionName, extensionParser); + }; +} diff --git a/packages/loader/src/gltf/parser/ParserContext.ts b/packages/loader/src/gltf/parser/GLTFParserContext.ts similarity index 97% rename from packages/loader/src/gltf/parser/ParserContext.ts rename to packages/loader/src/gltf/parser/GLTFParserContext.ts index 3b8c1a4620..8159b4374c 100644 --- a/packages/loader/src/gltf/parser/ParserContext.ts +++ b/packages/loader/src/gltf/parser/GLTFParserContext.ts @@ -9,12 +9,12 @@ import { TypedArray } from "@oasis-engine/core"; import { GLTFResource } from "../GLTFResource"; -import { IGLTF } from "../Schema"; +import { IGLTF } from "../GLTFSchema"; /** * @internal */ -export class ParserContext { +export class GLTFParserContext { gltf: IGLTF; buffers: ArrayBuffer[]; glTFResource: GLTFResource; diff --git a/packages/loader/src/gltf/parser/SceneParser.ts b/packages/loader/src/gltf/parser/GLTFSceneParser.ts similarity index 66% rename from packages/loader/src/gltf/parser/SceneParser.ts rename to packages/loader/src/gltf/parser/GLTFSceneParser.ts index bec4fd40a9..c3ea3c9071 100644 --- a/packages/loader/src/gltf/parser/SceneParser.ts +++ b/packages/loader/src/gltf/parser/GLTFSceneParser.ts @@ -3,7 +3,6 @@ import { AnimatorController, AnimatorControllerLayer, AnimatorStateMachine, - AssetPromise, BlinnPhongMaterial, Camera, Engine, @@ -11,24 +10,23 @@ import { MeshRenderer, SkinnedMeshRenderer } from "@oasis-engine/core"; -import { IKHRLightsPunctual, IKHRLightsPunctual_LightNode } from "../extensions/Schema"; import { GLTFResource } from "../GLTFResource"; -import { CameraType, ICamera, INode } from "../Schema"; -import { Parser } from "./Parser"; -import { ParserContext } from "./ParserContext"; +import { CameraType, ICamera, INode } from "../GLTFSchema"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFParserContext } from "./GLTFParserContext"; -export class SceneParser extends Parser { +export class GLTFSceneParser extends GLTFParser { private static _defaultMaterial: BlinnPhongMaterial; private static _getDefaultMaterial(engine: Engine): BlinnPhongMaterial { - if (!SceneParser._defaultMaterial) { - SceneParser._defaultMaterial = new BlinnPhongMaterial(engine); + if (!GLTFSceneParser._defaultMaterial) { + GLTFSceneParser._defaultMaterial = new BlinnPhongMaterial(engine); } - return SceneParser._defaultMaterial; + return GLTFSceneParser._defaultMaterial; } - parse(context: ParserContext) { + parse(context: GLTFParserContext) { const { glTFResource, gltf } = context; const { entities } = glTFResource; const { nodes, cameras: gltfCameras } = gltf; @@ -36,12 +34,10 @@ export class SceneParser extends Parser { if (!nodes) return; const defaultSceneRootPromiseInfo = context.defaultSceneRootPromiseInfo; - const promises = []; - for (let i = 0; i < nodes.length; i++) { const gltfNode = nodes[i]; - const { camera: cameraID, mesh: meshID, extensions = {} } = gltfNode; - const KHR_lights_punctual = extensions.KHR_lights_punctual; + const { camera: cameraID, mesh: meshID, extensions } = gltfNode; + const entity = entities[i]; if (cameraID !== undefined) { @@ -49,26 +45,17 @@ export class SceneParser extends Parser { } if (meshID !== undefined) { - promises.push(this._createRenderer(context, gltfNode, entity)); + this._createRenderer(context, gltfNode, entity); } - if (KHR_lights_punctual) { - const lightIndex = KHR_lights_punctual.light; - const lights = (gltf.extensions.KHR_lights_punctual as IKHRLightsPunctual).lights; - - Parser.parseEngineResource("KHR_lights_punctual", lights[lightIndex], entity, context); - } + GLTFParser.executeExtensionsAdditiveAndParse(extensions, context, entity, gltfNode); } if (glTFResource.defaultSceneRoot) { this._createAnimator(context); } - gltf.extensions && delete gltf.extensions["OASIS_materials_remap"]; - - AssetPromise.all(promises) - .then(() => defaultSceneRootPromiseInfo.resolve(glTFResource.defaultSceneRoot)) - .catch(defaultSceneRootPromiseInfo.reject); + defaultSceneRootPromiseInfo.resolve(glTFResource.defaultSceneRoot); return defaultSceneRootPromiseInfo.promise; } @@ -113,7 +100,7 @@ export class SceneParser extends Parser { camera.enabled = false; } - private _createRenderer(context: ParserContext, gltfNode: INode, entity: Entity) { + private _createRenderer(context: GLTFParserContext, gltfNode: INode, entity: Entity) { const { glTFResource, gltf } = context; const { meshes: gltfMeshes } = gltf; @@ -123,8 +110,8 @@ export class SceneParser extends Parser { const gltfMeshPrimitives = glTFMesh.primitives; const blendShapeWeights = gltfNode.weights || glTFMesh.weights; - const promises = []; for (let i = 0; i < gltfMeshPrimitives.length; i++) { + const gltfPrimitive = gltfMeshPrimitives[i]; const mesh = meshes[meshID][i]; let renderer: MeshRenderer | SkinnedMeshRenderer; @@ -144,29 +131,15 @@ export class SceneParser extends Parser { renderer.mesh = mesh; } - const materialIndex = gltfMeshPrimitives[i].material; - const remapMaterials = gltf.extensions && gltf.extensions["OASIS_materials_remap"]; - if (remapMaterials && remapMaterials[materialIndex]) { - promises.push( - remapMaterials[materialIndex].then((mtl) => { - renderer.setMaterial(mtl); - }) - ); - } else { - const material = materials?.[materialIndex] || SceneParser._getDefaultMaterial(engine); - renderer.setMaterial(material); - } + const materialIndex = gltfPrimitive.material; + const material = materials?.[materialIndex] || GLTFSceneParser._getDefaultMaterial(engine); + renderer.setMaterial(material); - const { extensions = {} } = gltfMeshPrimitives[i]; - const { KHR_materials_variants } = extensions; - if (KHR_materials_variants) { - Parser.parseEngineResource("KHR_materials_variants", KHR_materials_variants, renderer, context); - } + GLTFParser.executeExtensionsAdditiveAndParse(gltfPrimitive.extensions, context, renderer, gltfPrimitive); } - return Promise.all(promises); } - private _createAnimator(context: ParserContext): void { + private _createAnimator(context: GLTFParserContext): void { if (!context.hasSkinned && !context.glTFResource.animations) { return; } diff --git a/packages/loader/src/gltf/parser/SkinParser.ts b/packages/loader/src/gltf/parser/GLTFSkinParser.ts similarity index 92% rename from packages/loader/src/gltf/parser/SkinParser.ts rename to packages/loader/src/gltf/parser/GLTFSkinParser.ts index 58d57d3787..ac7ad15b53 100644 --- a/packages/loader/src/gltf/parser/SkinParser.ts +++ b/packages/loader/src/gltf/parser/GLTFSkinParser.ts @@ -1,11 +1,11 @@ import { Entity, Skin } from "@oasis-engine/core"; import { Matrix } from "@oasis-engine/math"; import { GLTFUtil } from "../GLTFUtil"; -import { Parser } from "./Parser"; -import { ParserContext } from "./ParserContext"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFParserContext } from "./GLTFParserContext"; -export class SkinParser extends Parser { - parse(context: ParserContext): void { +export class GLTFSkinParser extends GLTFParser { + parse(context: GLTFParserContext): void { const { glTFResource, gltf, buffers } = context; const { entities } = glTFResource; const gltfSkins = gltf.skins; diff --git a/packages/loader/src/gltf/parser/TextureParser.ts b/packages/loader/src/gltf/parser/GLTFTextureParser.ts similarity index 89% rename from packages/loader/src/gltf/parser/TextureParser.ts rename to packages/loader/src/gltf/parser/GLTFTextureParser.ts index 3c52d9d34c..543f8e4d0e 100644 --- a/packages/loader/src/gltf/parser/TextureParser.ts +++ b/packages/loader/src/gltf/parser/GLTFTextureParser.ts @@ -1,17 +1,17 @@ import { AssetPromise, AssetType, Texture2D, TextureFilterMode, TextureWrapMode } from "@oasis-engine/core"; import { GLTFUtil } from "../GLTFUtil"; -import { ISampler, TextureMagFilter, TextureMinFilter, TextureWrapMode as GLTFTextureWrapMode } from "../Schema"; -import { Parser } from "./Parser"; -import { ParserContext } from "./ParserContext"; +import { ISampler, TextureMagFilter, TextureMinFilter, TextureWrapMode as GLTFTextureWrapMode } from "../GLTFSchema"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFParserContext } from "./GLTFParserContext"; -export class TextureParser extends Parser { +export class GLTFTextureParser extends GLTFParser { private static _wrapMap = { [GLTFTextureWrapMode.CLAMP_TO_EDGE]: TextureWrapMode.Clamp, [GLTFTextureWrapMode.MIRRORED_REPEAT]: TextureWrapMode.Mirror, [GLTFTextureWrapMode.REPEAT]: TextureWrapMode.Repeat }; - parse(context: ParserContext): AssetPromise { + parse(context: GLTFParserContext): AssetPromise { const { glTFResource, gltf, buffers } = context; const { engine, url } = glTFResource; @@ -78,11 +78,11 @@ export class TextureParser extends Parser { } if (wrapS) { - texture.wrapModeU = TextureParser._wrapMap[wrapS]; + texture.wrapModeU = GLTFTextureParser._wrapMap[wrapS]; } if (wrapT) { - texture.wrapModeV = TextureParser._wrapMap[wrapT]; + texture.wrapModeV = GLTFTextureParser._wrapMap[wrapT]; } } } diff --git a/packages/loader/src/gltf/parser/Validator.ts b/packages/loader/src/gltf/parser/GLTFValidator.ts similarity index 51% rename from packages/loader/src/gltf/parser/Validator.ts rename to packages/loader/src/gltf/parser/GLTFValidator.ts index 4dc49907f2..d7ec5520d5 100644 --- a/packages/loader/src/gltf/parser/Validator.ts +++ b/packages/loader/src/gltf/parser/GLTFValidator.ts @@ -1,9 +1,9 @@ -import { Logger } from "@oasis-engine/core"; -import { Parser } from "./Parser"; -import { ParserContext } from "./ParserContext"; +import { AssetPromise, Logger } from "@oasis-engine/core"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFParserContext } from "./GLTFParserContext"; -export class Validator extends Parser { - parse(context: ParserContext): void { +export class GLTFValidator extends GLTFParser { + parse(context: GLTFParserContext): AssetPromise { const { asset: { version }, extensionsUsed, @@ -14,12 +14,13 @@ export class Validator extends Parser { if (!(gltfVersion >= 2 && gltfVersion < 3)) { throw "Only support gltf 2.x."; } - + const promises = []; if (extensionsUsed) { Logger.info("extensionsUsed: ", extensionsUsed); for (let i = 0; i < extensionsUsed.length; i++) { - if (!Parser.hasExtensionParser(extensionsUsed[i])) { - Logger.warn(`Extension ${extensionsUsed[i]} is not implemented, you can customize this extension in gltf.`); + const extensionUsed = extensionsUsed[i]; + if (!GLTFParser.hasExtensionParser(extensionUsed)) { + Logger.warn(`Extension ${extensionUsed} is not implemented, you can customize this extension in gltf.`); } } } @@ -29,12 +30,14 @@ export class Validator extends Parser { for (let i = 0; i < extensionsRequired.length; i++) { const extensionRequired = extensionsRequired[i]; - if (!Parser.hasExtensionParser(extensionRequired)) { + if (!GLTFParser.hasExtensionParser(extensionRequired)) { Logger.error(`GLTF parser has not supported required extension ${extensionRequired}.`); } else { - Parser.initialize(extensionRequired); + promises.push(GLTFParser.executeExtensionsInitialize(extensionRequired)); } } } + + return AssetPromise.all(promises).then(null); } } diff --git a/packages/loader/src/gltf/parser/MaterialParser.ts b/packages/loader/src/gltf/parser/MaterialParser.ts deleted file mode 100644 index d98340f6a0..0000000000 --- a/packages/loader/src/gltf/parser/MaterialParser.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { - AssetPromise, - Logger, - Material, - PBRMaterial, - PBRSpecularMaterial, - RenderFace, - TextureCoordinate, - UnlitMaterial -} from "@oasis-engine/core"; -import { Color } from "@oasis-engine/math"; -import { ITextureInfo, MaterialAlphaMode } from "../Schema"; -import { Parser } from "./Parser"; -import { ParserContext } from "./ParserContext"; - -export class MaterialParser extends Parser { - /** - * @internal - */ - static _checkOtherTextureTransform(texture: ITextureInfo, textureName: string): void { - if (texture.extensions?.KHR_texture_transform) { - Logger.warn(`${textureName} texture always use the KHR_texture_transform of the base texture.`); - } - } - - parse(context: ParserContext): AssetPromise { - const { gltf, glTFResource } = context; - - const { engine, textures } = glTFResource; - if (!gltf.materials) return; - - const materialsPromiseInfo = context.materialsPromiseInfo; - const materials: Material[] = []; - - for (let i = 0; i < gltf.materials.length; i++) { - const { - extensions = {}, - pbrMetallicRoughness, - normalTexture, - occlusionTexture, - emissiveTexture, - emissiveFactor, - alphaMode, - alphaCutoff, - doubleSided, - name = "" - } = gltf.materials[i]; - - const { - KHR_materials_unlit, - KHR_materials_pbrSpecularGlossiness, - KHR_materials_clearcoat, - OASIS_materials_remap - } = extensions; - - let material: UnlitMaterial | PBRMaterial | PBRSpecularMaterial = null; - - if (KHR_materials_unlit) { - material = Parser.createEngineResource("KHR_materials_unlit", KHR_materials_unlit, context); - } else if (KHR_materials_pbrSpecularGlossiness) { - material = ( - Parser.createEngineResource( - "KHR_materials_pbrSpecularGlossiness", - KHR_materials_pbrSpecularGlossiness, - context - ) - ); - } else { - material = new PBRMaterial(engine); - } - - material.name = name; - - if (KHR_materials_clearcoat) { - Parser.parseEngineResource("KHR_materials_clearcoat", KHR_materials_clearcoat, material, context); - } - - if (pbrMetallicRoughness) { - const { baseColorFactor, baseColorTexture, metallicFactor, roughnessFactor, metallicRoughnessTexture } = - pbrMetallicRoughness; - - if (baseColorFactor) { - material.baseColor = new Color( - Color.linearToGammaSpace(baseColorFactor[0]), - Color.linearToGammaSpace(baseColorFactor[1]), - Color.linearToGammaSpace(baseColorFactor[2]), - baseColorFactor[3] - ); - } - if (baseColorTexture) { - material.baseTexture = textures[baseColorTexture.index]; - const KHR_texture_transform = baseColorTexture.extensions?.KHR_texture_transform; - if (KHR_texture_transform) { - Parser.parseEngineResource("KHR_texture_transform", KHR_texture_transform, material, context); - } - } - - if (!KHR_materials_unlit && !KHR_materials_pbrSpecularGlossiness) { - const m = material as PBRMaterial; - m.metallic = metallicFactor ?? 1; - m.roughness = roughnessFactor ?? 1; - if (metallicRoughnessTexture) { - m.roughnessMetallicTexture = textures[metallicRoughnessTexture.index]; - MaterialParser._checkOtherTextureTransform(metallicRoughnessTexture, "Roughness metallic"); - } - } - } - - if (!KHR_materials_unlit) { - const m = material as PBRMaterial | PBRSpecularMaterial; - - if (emissiveTexture) { - m.emissiveTexture = textures[emissiveTexture.index]; - MaterialParser._checkOtherTextureTransform(emissiveTexture, "Emissive"); - } - - if (emissiveFactor) { - m.emissiveColor = new Color( - Color.linearToGammaSpace(emissiveFactor[0]), - Color.linearToGammaSpace(emissiveFactor[1]), - Color.linearToGammaSpace(emissiveFactor[2]) - ); - } - - if (normalTexture) { - const { index, scale } = normalTexture; - m.normalTexture = textures[index]; - MaterialParser._checkOtherTextureTransform(normalTexture, "Normal"); - - if (scale !== undefined) { - m.normalTextureIntensity = scale; - } - } - - if (occlusionTexture) { - const { index, strength, texCoord } = occlusionTexture; - m.occlusionTexture = textures[index]; - MaterialParser._checkOtherTextureTransform(occlusionTexture, "Occlusion"); - - if (strength !== undefined) { - m.occlusionTextureIntensity = strength; - } - if (texCoord === TextureCoordinate.UV1) { - m.occlusionTextureCoord = TextureCoordinate.UV1; - } else if (texCoord > TextureCoordinate.UV1) { - Logger.warn("Occlusion texture uv coordinate must be UV0 or UV1."); - } - } - } - - if (OASIS_materials_remap) { - gltf.extensions = gltf.extensions ?? {}; - gltf.extensions["OASIS_materials_remap"] = gltf.extensions["OASIS_materials_remap"] ?? {}; - gltf.extensions["OASIS_materials_remap"][i] = Parser.createEngineResource( - "OASIS_materials_remap", - OASIS_materials_remap, - context - ); - } - - if (doubleSided) { - material.renderFace = RenderFace.Double; - } else { - material.renderFace = RenderFace.Front; - } - - switch (alphaMode) { - case MaterialAlphaMode.OPAQUE: - material.isTransparent = false; - break; - case MaterialAlphaMode.BLEND: - material.isTransparent = true; - break; - case MaterialAlphaMode.MASK: - material.alphaCutoff = alphaCutoff ?? 0.5; - break; - } - - materials[i] = material; - } - - glTFResource.materials = materials; - materialsPromiseInfo.resolve(materials); - return materialsPromiseInfo.promise; - } -} diff --git a/packages/loader/src/gltf/parser/Parser.ts b/packages/loader/src/gltf/parser/Parser.ts deleted file mode 100644 index f838910942..0000000000 --- a/packages/loader/src/gltf/parser/Parser.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { AnimationClip, AssetPromise, EngineObject, Material, Mesh } from "@oasis-engine/core"; -import { ExtensionParser } from "../extensions/ExtensionParser"; -import { ExtensionSchema } from "../extensions/Schema"; -import { ParserContext } from "./ParserContext"; - -export abstract class Parser { - private static _extensionParsers: Record = {}; - - static parseEngineResource( - extensionName: string, - extensionSchema: ExtensionSchema, - parseResource: EngineObject, - context: ParserContext, - ...extra - ): void { - const parsers = Parser._extensionParsers[extensionName]; - - if (parsers?.length) { - for (let i = 0; i < parsers.length; i++) { - parsers[i].parseEngineResource(extensionSchema, parseResource, context, ...extra); - } - } - } - - static createEngineResource( - extensionName: string, - extensionSchema: ExtensionSchema, - context: ParserContext, - ...extra - ): T | Promise { - const parsers = Parser._extensionParsers[extensionName]; - - if (parsers?.length) { - return parsers[0].createEngineResource(extensionSchema, context, ...extra) as T; - } - } - - static hasExtensionParser(extensionName: string): boolean { - const parsers = Parser._extensionParsers[extensionName]; - return !!parsers?.length; - } - - static initialize(extensionName: string) { - const parsers = Parser._extensionParsers[extensionName]; - - if (parsers?.length) { - for (let i = 0; i < parsers.length; i++) { - parsers[i].initialize(); - } - } - } - - /** - * @internal - */ - static _addExtensionParser(extensionName: string, extensionParser: ExtensionParser) { - if (!Parser._extensionParsers[extensionName]) { - Parser._extensionParsers[extensionName] = []; - } - Parser._extensionParsers[extensionName].push(extensionParser); - } - - abstract parse(context: ParserContext): AssetPromise | void | Material | AnimationClip | Mesh; -} - -/** - * Declare ExtensionParser's decorator. - * @param extensionName - Extension name - */ -export function registerExtension(extensionName: string) { - return (parser: new () => ExtensionParser) => { - const extensionParser = new parser(); - - Parser._addExtensionParser(extensionName, extensionParser); - }; -} diff --git a/packages/loader/src/gltf/parser/index.ts b/packages/loader/src/gltf/parser/index.ts new file mode 100644 index 0000000000..f016b6b5f9 --- /dev/null +++ b/packages/loader/src/gltf/parser/index.ts @@ -0,0 +1,11 @@ +export { GLTFAnimationParser } from "./GLTFAnimationParser"; +export { GLTFBufferParser } from "./GLTFBufferParser"; +export { GLTFEntityParser } from "./GLTFEntityParser"; +export { GLTFMaterialParser } from "./GLTFMaterialParser"; +export { GLTFMeshParser } from "./GLTFMeshParser"; +export { GLTFParser, registerGLTFExtension } from "./GLTFParser"; +export { GLTFSceneParser } from "./GLTFSceneParser"; +export { GLTFSkinParser } from "./GLTFSkinParser"; +export { GLTFTextureParser } from "./GLTFTextureParser"; +export { GLTFValidator } from "./GLTFValidator"; +export { GLTFParserContext } from "./GLTFParserContext"; diff --git a/packages/loader/src/index.ts b/packages/loader/src/index.ts index 2f46972392..5e593ad254 100644 --- a/packages/loader/src/index.ts +++ b/packages/loader/src/index.ts @@ -2,7 +2,6 @@ import "./AnimatorControllerLoader"; import "./BufferLoader"; import "./EnvLoader"; import "./FontLoader"; -import "./gltf/extensions/index"; import "./GLTFLoader"; import "./HDRLoader"; import "./JSONLoader"; @@ -18,9 +17,8 @@ import "./TextureCubeLoader"; import "./AnimationClipLoader"; export { parseSingleKTX } from "./compressed-texture"; -export { GLTFResource } from "./gltf/GLTFResource"; export type { GLTFParams } from "./GLTFLoader"; export * from "./resource-deserialize"; export * from "./SceneLoader"; export type { Texture2DParams } from "./Texture2DLoader"; - +export * from "./gltf"; From b5cef2aaf94ecc3aaa82bc846c2d584bc6be42eb Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Thu, 2 Mar 2023 11:43:22 +0800 Subject: [PATCH 10/11] "v1.0.0-alpha.0" --- packages/core/package.json | 2 +- packages/design/package.json | 2 +- packages/draco/package.json | 2 +- packages/loader/package.json | 2 +- packages/math/package.json | 2 +- packages/oasis-engine/package.json | 2 +- packages/physics-lite/package.json | 2 +- packages/physics-physx/package.json | 2 +- packages/rhi-webgl/package.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 0cf01fe160..99a55c8b64 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/core", - "version": "0.9.0-beta.66", + "version": "1.0.0-alpha.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/design/package.json b/packages/design/package.json index 669043c0e3..6556b3bfe6 100644 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/design", - "version": "0.9.0-beta.66", + "version": "1.0.0-alpha.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/draco/package.json b/packages/draco/package.json index f4bcb81c89..3f76fd5b26 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/draco", - "version": "0.9.0-beta.66", + "version": "1.0.0-alpha.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/loader/package.json b/packages/loader/package.json index 5e37e73c64..cd243837da 100644 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/loader", - "version": "0.9.0-beta.66", + "version": "1.0.0-alpha.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/math/package.json b/packages/math/package.json index 3a4f3e7730..a03dadd11c 100644 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/math", - "version": "0.9.0-beta.66", + "version": "1.0.0-alpha.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index e066efe7fd..6c62c55ec6 100644 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,6 @@ { "name": "oasis-engine", - "version": "0.9.0-beta.66", + "version": "1.0.0-alpha.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index 89f40334c9..892c00db10 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.9.0-beta.66", + "version": "1.0.0-alpha.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index 63a94c8a72..04c8ee33d2 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.9.0-beta.66", + "version": "1.0.0-alpha.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index f7f637d2cb..bd9892b2d9 100644 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.9.0-beta.66", + "version": "1.0.0-alpha.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" From add6e916a8327e492f8fec16bc0e7cd543a59566 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 2 Mar 2023 15:39:07 +0800 Subject: [PATCH 11/11] Move font map cache from `Font` to `Engine` (#1387) * refactor(font): move font map from Font to Engine --- packages/core/src/2d/text/Font.ts | 6 ++---- packages/core/src/Engine.ts | 5 ++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/core/src/2d/text/Font.ts b/packages/core/src/2d/text/Font.ts index 6e1e7b1634..4b27bb71f3 100644 --- a/packages/core/src/2d/text/Font.ts +++ b/packages/core/src/2d/text/Font.ts @@ -7,8 +7,6 @@ import { SubFont } from "./SubFont"; * Font. */ export class Font extends RefObject { - private static _fontMap: Record = {}; - /** * Create a system font. * @param engine - Engine to which the font belongs @@ -17,7 +15,7 @@ export class Font extends RefObject { */ static createFromOS(engine: Engine, name: string): Font { if (name) { - const fontMap = Font._fontMap; + const fontMap = engine._fontMap; let font = fontMap[name]; if (font) { return font; @@ -68,6 +66,6 @@ export class Font extends RefObject { subFontMap[k].destroy(); } this._subFontMap = null; - delete Font._fontMap[this._name]; + delete this.engine._fontMap[this._name]; } } diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index ed06e29a4f..01808337a9 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -88,6 +88,8 @@ export class Engine extends EventDispatcher { _spriteMaskManager: SpriteMaskManager; /** @internal */ _canSpriteBatch: boolean = true; + /** @internal */ + _fontMap: Record = {}; /** @internal @todo: temporary solution */ _macroCollection: ShaderMacroCollection = new ShaderMacroCollection(); @@ -328,7 +330,8 @@ export class Engine extends EventDispatcher { this._resourceManager._destroy(); this._magentaTexture2D.destroy(true); this._magentaTextureCube.destroy(true); - this._textDefaultFont.destroy(true); + this._textDefaultFont = null; + this._fontMap = null; this.inputManager._destroy(); this.trigger(new Event("shutdown", this));