From 809ddf2dc2626ced605515c86452075ef7d9444b Mon Sep 17 00:00:00 2001 From: AZhan Date: Mon, 26 Feb 2024 14:34:41 +0800 Subject: [PATCH 1/2] Fix `IPhysicsScene.removeColliderShape` not cleaned up `eventMap` (#2008) * fix: physic remove shape bug --- packages/physics-lite/src/LitePhysicsScene.ts | 15 ++-- .../physics-physx/src/PhysXPhysicsScene.ts | 12 ++- tests/src/core/physics/PhysicsManager.test.ts | 86 +++++++++++++++++-- 3 files changed, 96 insertions(+), 17 deletions(-) diff --git a/packages/physics-lite/src/LitePhysicsScene.ts b/packages/physics-lite/src/LitePhysicsScene.ts index d7b8290c9..f5806a1bc 100644 --- a/packages/physics-lite/src/LitePhysicsScene.ts +++ b/packages/physics-lite/src/LitePhysicsScene.ts @@ -1,5 +1,5 @@ -import { ICharacterController, IPhysicsScene } from "@galacean/engine-design"; import { BoundingBox, BoundingSphere, CollisionUtil, Ray, Vector3 } from "@galacean/engine"; +import { ICharacterController, IPhysicsScene } from "@galacean/engine-design"; import { DisorderedArray } from "./DisorderedArray"; import { LiteCollider } from "./LiteCollider"; import { LiteHitResult } from "./LiteHitResult"; @@ -65,16 +65,21 @@ export class LitePhysicsScene implements IPhysicsScene { * {@inheritDoc IPhysicsManager.removeColliderShape } */ removeColliderShape(colliderShape: LiteColliderShape): void { - const { _eventPool: eventPool, _currentEvents: currentEvents } = this; - const { _id: shapeID } = colliderShape; + const { _eventPool: eventPool, _currentEvents: currentEvents, _eventMap: eventMap } = this; + const { _id: id } = colliderShape; for (let i = currentEvents.length - 1; i >= 0; i--) { const event = currentEvents.get(i); - if (event.index1 == shapeID || event.index2 == shapeID) { + if (event.index1 == id) { currentEvents.deleteByIndex(i); eventPool.push(event); + } else if (event.index2 == id) { + currentEvents.deleteByIndex(i); + eventPool.push(event); + // If the shape is big index, should clear from the small index shape subMap + eventMap[event.index1][id] = undefined; } } - delete this._eventMap[shapeID]; + delete eventMap[id]; } /** diff --git a/packages/physics-physx/src/PhysXPhysicsScene.ts b/packages/physics-physx/src/PhysXPhysicsScene.ts index 58e6c26f9..c1432f754 100644 --- a/packages/physics-physx/src/PhysXPhysicsScene.ts +++ b/packages/physics-physx/src/PhysXPhysicsScene.ts @@ -116,15 +116,21 @@ export class PhysXPhysicsScene implements IPhysicsScene { */ removeColliderShape(colliderShape: PhysXColliderShape) { const { _eventPool: eventPool, _currentEvents: currentEvents } = this; - const { _id: shapeID } = colliderShape; + const { _id: id } = colliderShape; + const { _eventMap: eventMap } = this._physXManager; for (let i = currentEvents.length - 1; i >= 0; i--) { const event = currentEvents.get(i); - if (event.index1 == shapeID || event.index2 == shapeID) { + if (event.index1 == id) { currentEvents.deleteByIndex(i); eventPool.push(event); + } else if (event.index2 == id) { + currentEvents.deleteByIndex(i); + eventPool.push(event); + // If the shape is big index, should clear from the small index shape subMap + eventMap[event.index1][id] = undefined; } } - delete this._physXManager._eventMap[shapeID]; + delete eventMap[id]; } /** diff --git a/tests/src/core/physics/PhysicsManager.test.ts b/tests/src/core/physics/PhysicsManager.test.ts index 422767344..fe22fffaf 100644 --- a/tests/src/core/physics/PhysicsManager.test.ts +++ b/tests/src/core/physics/PhysicsManager.test.ts @@ -1,17 +1,16 @@ import { - Camera, BoxColliderShape, - Layer, - StaticCollider, - DynamicCollider, - HitResult, + Camera, CharacterController, - CapsuleColliderShape, - SphereColliderShape, - Script, + Collider, ColliderShape, + DynamicCollider, Entity, - Collider + HitResult, + Layer, + Script, + SphereColliderShape, + StaticCollider } from "@galacean/engine-core"; import { Ray, Vector3 } from "@galacean/engine-math"; import { LitePhysics } from "@galacean/engine-physics-lite"; @@ -136,6 +135,75 @@ describe("Physics Test", () => { engineLite.run(); }); + it("removeShape", () => { + const scene = engineLite.sceneManager.activeScene; + const root = scene.createRootEntity("root"); + const removeShapeRoot1 = root.createChild("root"); + removeShapeRoot1.transform.position = new Vector3(1000, 1000, 1000); + + const enterEvent = []; + const collider1 = removeShapeRoot1.addComponent(StaticCollider); + const box1 = new BoxColliderShape(); + enterEvent[box1.id] = []; + collider1.addShape(box1); + removeShapeRoot1.addComponent( + class extends Script { + onTriggerEnter(other: ColliderShape): void { + ++enterEvent[box1.id][other.id]; + } + } + ); + const removeShapeRoot2 = root.createChild("root"); + removeShapeRoot2.transform.position = new Vector3(1000, 1000, 1000); + const collider2 = removeShapeRoot2.addComponent(StaticCollider); + const box2 = new BoxColliderShape(); + enterEvent[box2.id] = []; + collider2.addShape(box2); + removeShapeRoot2.addComponent( + class extends Script { + onTriggerEnter(other: ColliderShape) { + ++enterEvent[box2.id][other.id]; + } + } + ); + // @ts-ignore + engineLite.physicsManager._update(8); + // Remove collider shape. + removeShapeRoot2.isActive = false; + const removeShapeRoot3 = root.createChild("root"); + removeShapeRoot3.transform.position = new Vector3(1000, 1000, 1000); + const collider3 = removeShapeRoot3.addComponent(StaticCollider); + const box3 = new BoxColliderShape(); + enterEvent[box3.id] = []; + collider3.addShape(box3); + removeShapeRoot3.addComponent( + class extends Script { + onTriggerEnter(other: ColliderShape) { + ++enterEvent[box3.id][other.id]; + } + } + ); + removeShapeRoot2.isActive = true; + enterEvent[box1.id][box2.id] = 0; + enterEvent[box1.id][box3.id] = 0; + enterEvent[box2.id][box1.id] = 0; + enterEvent[box2.id][box3.id] = 0; + enterEvent[box3.id][box1.id] = 0; + enterEvent[box3.id][box2.id] = 0; + // @ts-ignore + engineLite.physicsManager._update(8); + expect(enterEvent[box1.id][box2.id]).to.eq(1); + expect(enterEvent[box1.id][box3.id]).to.eq(1); + expect(enterEvent[box2.id][box1.id]).to.eq(1); + expect(enterEvent[box2.id][box3.id]).to.eq(1); + expect(enterEvent[box3.id][box1.id]).to.eq(1); + expect(enterEvent[box3.id][box2.id]).to.eq(1); + + removeShapeRoot1.destroy(); + removeShapeRoot2.destroy(); + removeShapeRoot3.destroy(); + }); + it("constructor", () => { expect(engineLite.physicsManager.gravity.y).to.eq(-9.81); expect(engineLite.physicsManager.fixedTimeStep).to.eq(1 / 60); From 57f6c8a4155d1c5785e96c86563da20f02cc4a05 Mon Sep 17 00:00:00 2001 From: Hu Song Date: Tue, 27 Feb 2024 19:21:40 +0800 Subject: [PATCH 2/2] Fix gltf accessor's bufferView could be undefined (#2013) * fix: gltf accessor's bufferView could be undefined --- packages/loader/src/gltf/GLTFUtils.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/loader/src/gltf/GLTFUtils.ts b/packages/loader/src/gltf/GLTFUtils.ts index 0d8e3f7b9..967b03ff3 100644 --- a/packages/loader/src/gltf/GLTFUtils.ts +++ b/packages/loader/src/gltf/GLTFUtils.ts @@ -134,7 +134,8 @@ export class GLTFUtils { accessor: IAccessor ): Promise { const componentType = accessor.componentType; - const bufferView = bufferViews[accessor.bufferView]; + const bufferViewIndex = accessor.bufferView ?? 0; + const bufferView = bufferViews[bufferViewIndex]; return context.get(GLTFParserType.Buffer).then((buffers) => { const bufferIndex = bufferView.buffer; @@ -153,7 +154,7 @@ export class GLTFUtils { // According to the glTF official documentation only byteStride not undefined is allowed if (bufferStride !== undefined && bufferStride !== elementStride) { const bufferSlice = Math.floor(byteOffset / bufferStride); - const bufferCacheKey = accessor.bufferView + ":" + componentType + ":" + bufferSlice + ":" + accessorCount; + const bufferCacheKey = bufferViewIndex + ":" + componentType + ":" + bufferSlice + ":" + accessorCount; const accessorBufferCache = context.accessorBufferCache; bufferInfo = accessorBufferCache[bufferCacheKey]; if (!bufferInfo) { @@ -206,7 +207,7 @@ export class GLTFUtils { */ static getAccessorData(glTF: IGLTF, accessor: IAccessor, buffers: ArrayBuffer[]): TypedArray { const bufferViews = glTF.bufferViews; - const bufferView = bufferViews[accessor.bufferView]; + const bufferView = bufferViews[accessor.bufferView ?? 0]; const arrayBuffer = buffers[bufferView.buffer]; const accessorByteOffset = accessor.hasOwnProperty("byteOffset") ? accessor.byteOffset : 0; const bufferViewByteOffset = bufferView.hasOwnProperty("byteOffset") ? bufferView.byteOffset : 0;