Skip to content

Commit

Permalink
Fix physics contact point normal (#2512)
Browse files Browse the repository at this point in the history
* fix: physics contact point normal
  • Loading branch information
luzhuang authored Jan 15, 2025
1 parent 200cfc0 commit 393f8e3
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 42 deletions.
4 changes: 2 additions & 2 deletions packages/core/src/physics/Collision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export class Collision {
*/
getContacts(outContacts: ContactPoint[]): number {
const nativeCollision = this._nativeCollision;
const factor = nativeCollision.shape0Id < nativeCollision.shape1Id ? 1 : -1;

const smallerShapeId = Math.min(nativeCollision.shape0Id, nativeCollision.shape1Id);
const factor = this.shape.id === smallerShapeId ? 1 : -1;
const nativeContactPoints = nativeCollision.getContacts();
const length = nativeContactPoints.size();
for (let i = 0; i < length; i++) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/physics/ContactPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Vector3 } from "@galacean/engine-math";
export class ContactPoint {
/** The position of the contact point between the shapes, in world space. */
readonly position = new Vector3();
/** The normal of the contacting surfaces at the contact point. The normal direction points from the second shape to the first shape. */
/** The normal of the contacting surfaces at the contact point. The normal direction points from the other shape to the self shape. */
readonly normal = new Vector3();
/** The impulse applied at the contact point, in world space. Divide by the simulation time step to get a force value. */
readonly impulse = new Vector3();
Expand Down
60 changes: 30 additions & 30 deletions packages/physics-physx/libs/physx.release.downgrade.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/physics-physx/libs/physx.release.js

Large diffs are not rendered by default.

Binary file modified packages/physics-physx/libs/physx.release.wasm
100644 → 100755
Binary file not shown.
4 changes: 2 additions & 2 deletions packages/physics-physx/src/PhysXPhysics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ export class PhysXPhysics implements IPhysics {
}

if (runtimeMode == PhysXRuntimeMode.JavaScript) {
script.src = `https://mdn.alipayobjects.com/rms/afts/file/A*CfV8RrDQk5oAAAAAAAAAAAAAARQnAQ/physx.release.downgrade.js`;
script.src = `https://mdn.alipayobjects.com/rms/afts/file/A*PXxaQrGL0XsAAAAAAAAAAAAAARQnAQ/physx.release.downgrade.js`;
} else if (runtimeMode == PhysXRuntimeMode.WebAssembly) {
script.src = `https://mdn.alipayobjects.com/rms/afts/file/A*ZDDgR4ERdfwAAAAAAAAAAAAAARQnAQ/physx.release.js`;
script.src = `https://mdn.alipayobjects.com/rms/afts/file/A*0Qq8Rob3_5oAAAAAAAAAAAAAARQnAQ/physx.release.js`;
}
});

Expand Down
3 changes: 3 additions & 0 deletions tests/src/core/physics/CharacterController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ describe("CharacterController", function () {
capsuleColliderShape.contactOffset = 0.1;
capsuleColliderShape.radius = 0.2;
capsuleColliderShape.height = 1;

controller.enabled = true;

expect(capsuleColliderShape.contactOffset).eq(0.1);
expect(capsuleColliderShape.radius).eq(0.2);
expect(capsuleColliderShape.height).eq(1);
Expand Down
110 changes: 104 additions & 6 deletions tests/src/core/physics/Collision.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,122 @@ describe("Collision", function () {
engine.sceneManager.activeScene.physics.gravity = new Vector3(0, -9.81, 0);
});

it("collision info", function () {
it("collision shape1", function () {
engine.sceneManager.activeScene.physics.gravity = new Vector3(0, 0, 0);
const box1 = addBox(new Vector3(1, 1, 1), DynamicCollider, new Vector3(-3, 0, 0));
const box2 = addBox(new Vector3(1, 1, 1), DynamicCollider, new Vector3(0, 0, 0));

box1.transform.rotate(45, 45, 0);

return new Promise<void>((done) => {
box1.addComponent(
class extends Script {
onCollisionEnter(other: Collision): void {
expect(other.shape).toBe(box2.getComponent(DynamicCollider).shapes[0]);
expect(other.contactCount).toBe(4);
expect(other.contactCount).toBe(3);
const contacts = [];
other.getContacts(contacts);
expect(contacts.length).toBe(4);
expect(formatValue(contacts[0].position.x)).toBe(-0.27778);
expect(formatValue(contacts[0].separation)).toBe(-0.22222);
expect(contacts.length).toBe(3);
expect(formatValue(contacts[0].position.x)).closeTo(-0.5, 0.1);
expect(formatValue(contacts[0].separation)).toBe(-0.02022);
expect(formatValue(contacts[0].normal.x)).toBe(-1);
expect(formatValue(contacts[0].impulse.x)).toBe(-2.93748);
expect(formatValue(contacts[0].impulse.x)).toBe(-7.38326);

done();
}
}
);

box1.getComponent(DynamicCollider).applyForce(new Vector3(1000, 0, 0));
// @ts-ignore
engine.sceneManager.activeScene.physics._update(1);
});
});

it("collision shape1 inv", function () {
engine.sceneManager.activeScene.physics.gravity = new Vector3(0, 0, 0);
const box2 = addBox(new Vector3(1, 1, 1), DynamicCollider, new Vector3(0, 0, 0));
const box1 = addBox(new Vector3(1, 1, 1), DynamicCollider, new Vector3(-3, 0, 0));

box1.transform.rotate(45, 45, 0);

return new Promise<void>((done) => {
box1.addComponent(
class extends Script {
onCollisionEnter(other: Collision): void {
expect(other.shape).toBe(box2.getComponent(DynamicCollider).shapes[0]);
expect(other.contactCount).toBe(3);
const contacts = [];
other.getContacts(contacts);
expect(contacts.length).toBe(3);
expect(formatValue(contacts[0].position.x)).closeTo(-0.5, 0.1);
expect(formatValue(contacts[0].separation)).toBe(-0.02022);
expect(formatValue(contacts[0].normal.x)).toBe(-1);
expect(formatValue(contacts[0].impulse.x)).toBe(-7.38326);

done();
}
}
);

box1.getComponent(DynamicCollider).applyForce(new Vector3(1000, 0, 0));
// @ts-ignore
engine.sceneManager.activeScene.physics._update(1);
});
});

it("collision shape2", function () {
engine.sceneManager.activeScene.physics.gravity = new Vector3(0, 0, 0);
const box1 = addBox(new Vector3(1, 1, 1), DynamicCollider, new Vector3(-3, 0, 0));
const box2 = addBox(new Vector3(1, 1, 1), DynamicCollider, new Vector3(0, 0, 0));

box1.transform.rotate(45, 45, 0);

return new Promise<void>((done) => {
box2.addComponent(
class extends Script {
onCollisionEnter(other: Collision): void {
expect(other.shape).toBe(box1.getComponent(DynamicCollider).shapes[0]);
expect(other.contactCount).toBe(3);
const contacts = [];
other.getContacts(contacts);
expect(contacts.length).toBe(3);
expect(formatValue(contacts[0].position.x)).closeTo(-0.5, 0.1);
expect(formatValue(contacts[0].separation)).toBe(-0.02022);
expect(formatValue(contacts[0].normal.x)).toBe(1);
expect(formatValue(contacts[0].impulse.x)).toBe(7.38326);

done();
}
}
);

box1.getComponent(DynamicCollider).applyForce(new Vector3(1000, 0, 0));
// @ts-ignore
engine.sceneManager.activeScene.physics._update(1);
});
});

it("collision shape2 inv", function () {
engine.sceneManager.activeScene.physics.gravity = new Vector3(0, 0, 0);
const box2 = addBox(new Vector3(1, 1, 1), DynamicCollider, new Vector3(0, 0, 0));
const box1 = addBox(new Vector3(1, 1, 1), DynamicCollider, new Vector3(-3, 0, 0));

box1.transform.rotate(45, 45, 0);

return new Promise<void>((done) => {
box2.addComponent(
class extends Script {
onCollisionEnter(other: Collision): void {
expect(other.shape).toBe(box1.getComponent(DynamicCollider).shapes[0]);
expect(other.contactCount).toBe(3);
const contacts = [];
other.getContacts(contacts);
expect(contacts.length).toBe(3);
expect(formatValue(contacts[0].position.x)).closeTo(-0.5, 0.1);
expect(formatValue(contacts[0].separation)).toBe(-0.02022);
expect(formatValue(contacts[0].normal.x)).toBe(1);
expect(formatValue(contacts[0].impulse.x)).toBe(7.38326);

done();
}
Expand Down

0 comments on commit 393f8e3

Please sign in to comment.