Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e/.dev/physx.release.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion e2e/.dev/physx.release.simd.js

Large diffs are not rendered by default.

Binary file modified e2e/.dev/physx.release.simd.wasm
Binary file not shown.
Binary file modified e2e/.dev/physx.release.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/physics-physx/libs/physx.release.js

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

Binary file modified packages/physics-physx/libs/physx.release.simd.wasm
Binary file not shown.
Binary file modified packages/physics-physx/libs/physx.release.wasm
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 @@ -67,10 +67,10 @@ export class PhysXPhysics implements IPhysics {
this._runTimeMode = runtimeMode;
this._wasmSIMDModeUrl =
runtimeUrls?.wasmSIMDModeUrl ??
"https://mdn.alipayobjects.com/rms/afts/file/A*FHYHS4_ZL5UAAAAAQ4AAAAgAehQnAQ/physx.release.simd.js";
"https://mdn.alipayobjects.com/rms/afts/file/A*iHrYQKBrgTAAAAAAQ4AAAAgAehQnAQ/physx.release.simd.js";
this._wasmModeUrl =
runtimeUrls?.wasmModeUrl ??
"https://mdn.alipayobjects.com/rms/afts/file/A*2fv0RLMK1d0AAAAAQ4AAAAgAehQnAQ/physx.release.js";
"https://mdn.alipayobjects.com/rms/afts/file/A*DFuvR6Mv5C0AAAAAQ4AAAAgAehQnAQ/physx.release.js";
}

/**
Expand Down
173 changes: 109 additions & 64 deletions packages/physics-physx/src/PhysXPhysicsScene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,23 @@ export class PhysXPhysicsScene implements IPhysicsScene {
private _physXManager: PhysXPhysicsManager;
private _pxRaycastHit: any;
private _pxFilterData: any;
private _pxRaycastSweepFilterData: any;

private _pxScene: any;
private _physXSimulationCallbackInstance: any;

// Persistent PhysX query filter callbacks. Reused across calls to avoid the
// wasm-boundary cost of `PxQueryFilterCallback.implement(...)` / `.delete()`
// on every raycast/sweep/overlap. The user-supplied filter function is
// pushed onto a per-type stack so reentrant calls (e.g. raycast inside a
// raycast filter) keep their own filter context.
private _pxRaycastCallback: any;
private _pxSweepCallback: any;
private _pxOverlapCallback: any;
private _onRaycastStack: Array<(obj: number) => boolean> = [];
private _onSweepStack: Array<(obj: number) => boolean> = [];
private _onOverlapStack: Array<(obj: number) => boolean> = [];

private _activeTriggers: DisorderedArray<TriggerEvent> = new DisorderedArray<TriggerEvent>();
private _contactEvents: ContactEvent[] = [];
private _contactEventCount = 0;
Expand All @@ -51,6 +64,10 @@ export class PhysXPhysicsScene implements IPhysicsScene {
this._pxRaycastHit = new physX.PxRaycastHit();
this._pxFilterData = new physX.PxQueryFilterData();
this._pxFilterData.flags = new physX.PxQueryFlags(QueryFlag.STATIC | QueryFlag.DYNAMIC | QueryFlag.PRE_FILTER);
this._pxRaycastSweepFilterData = new physX.PxQueryFilterData();
this._pxRaycastSweepFilterData.flags = new physX.PxQueryFlags(
QueryFlag.STATIC | QueryFlag.DYNAMIC | QueryFlag.PRE_FILTER | QueryFlag.POST_FILTER
);

const triggerCallback = {
onContactBegin: (collision) => {
Expand Down Expand Up @@ -91,6 +108,27 @@ export class PhysXPhysicsScene implements IPhysicsScene {
);
this._pxScene = pxPhysics.createScene(sceneDesc);
sceneDesc.delete();

const onRaycastStack = this._onRaycastStack;
this._pxRaycastCallback = physX.PxQueryFilterCallback.implement({
preFilter: (_filterData: any, index: number, _actor: any) =>
onRaycastStack[onRaycastStack.length - 1](index) ? QueryHitType.BLOCK : QueryHitType.NONE,
// distance <= 0 means initial overlap — drop the hit so subsequent hits can be considered.
postFilter: (_filterData: any, distance: number) => (distance <= 0 ? QueryHitType.NONE : QueryHitType.BLOCK)
});

const onSweepStack = this._onSweepStack;
this._pxSweepCallback = physX.PxQueryFilterCallback.implement({
preFilter: (_filterData: any, index: number, _actor: any) =>
onSweepStack[onSweepStack.length - 1](index) ? QueryHitType.BLOCK : QueryHitType.NONE,
postFilter: (_filterData: any, distance: number) => (distance <= 0 ? QueryHitType.NONE : QueryHitType.BLOCK)
});

const onOverlapStack = this._onOverlapStack;
this._pxOverlapCallback = physX.PxQueryFilterCallback.implement({
preFilter: (_filterData: any, index: number, _actor: any) =>
onOverlapStack[onOverlapStack.length - 1](index) ? QueryHitType.BLOCK : QueryHitType.NONE
});
}

/**
Expand Down Expand Up @@ -207,27 +245,21 @@ export class PhysXPhysicsScene implements IPhysicsScene {
const { _pxRaycastHit: pxHitResult } = this;
distance = Math.min(distance, 3.4e38); // float32 max value limit in physX raycast.

const raycastCallback = {
preFilter: (filterData, index, actor) => {
if (onRaycast(index)) {
return 2; // eBLOCK
} else {
return 0; // eNONE
}
}
};

const pxRaycastCallback = this._physXPhysics._physX.PxQueryFilterCallback.implement(raycastCallback);
const result = this._pxScene.raycastSingle(
ray.origin,
ray.direction,
distance,
pxHitResult,
this._pxFilterData,
pxRaycastCallback
);

pxRaycastCallback.delete();
const onRaycastStack = this._onRaycastStack;
onRaycastStack.push(onRaycast);
let result: boolean;
try {
result = this._pxScene.raycastSingle(
ray.origin,
ray.direction,
distance,
pxHitResult,
this._pxRaycastSweepFilterData,
this._pxRaycastCallback
);
} finally {
onRaycastStack.pop();
}

if (result && hit != undefined) {
const { _tempPosition: position, _tempNormal: normal } = PhysXPhysicsScene;
Expand Down Expand Up @@ -392,6 +424,11 @@ export class PhysXPhysicsScene implements IPhysicsScene {
this._pxRaycastHit.delete();
this._pxFilterData.flags.delete();
this._pxFilterData.delete();
this._pxRaycastSweepFilterData.flags.delete();
this._pxRaycastSweepFilterData.delete();
this._pxRaycastCallback.delete();
this._pxSweepCallback.delete();
this._pxOverlapCallback.delete();
// Need to release the controller manager before release the scene.
this._pxControllerManager?.release();
this._pxScene.release();
Expand Down Expand Up @@ -445,60 +482,59 @@ export class PhysXPhysicsScene implements IPhysicsScene {
): boolean {
distance = Math.min(distance, 3.4e38); // float32 max value limit in physx sweep

const sweepCallback = {
preFilter: (filterData, index, actor) => {
if (onSweep(index)) {
return 2; // eBLOCK
} else {
return 0; // eNONE
}
const onSweepStack = this._onSweepStack;
onSweepStack.push(onSweep);
const pxSweepHit = new this._physXPhysics._physX.PxSweepHit();
try {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
let result: boolean;
try {
result = this._pxScene.sweepSingle(
geometry,
pose,
direction,
distance,
pxSweepHit,
this._pxRaycastSweepFilterData,
this._pxSweepCallback
);
} finally {
onSweepStack.pop();
}
};

const pxSweepCallback = this._physXPhysics._physX.PxQueryFilterCallback.implement(sweepCallback);
const pxSweepHit = new this._physXPhysics._physX.PxSweepHit();
const result = this._pxScene.sweepSingle(
geometry,
pose,
direction,
distance,
pxSweepHit,
this._pxFilterData,
pxSweepCallback
);
if (result && outHitResult != undefined) {
const { _tempPosition: position, _tempNormal: normal } = PhysXPhysicsScene;
const { position: pxPosition, normal: pxNormal } = pxSweepHit;
position.set(pxPosition.x, pxPosition.y, pxPosition.z);
normal.set(pxNormal.x, pxNormal.y, pxNormal.z);
outHitResult(pxSweepHit.getShape().getUUID(), pxSweepHit.distance, position, normal);
}

if (result && outHitResult != undefined) {
const { _tempPosition: position, _tempNormal: normal } = PhysXPhysicsScene;
const { position: pxPosition, normal: pxNormal } = pxSweepHit;
position.set(pxPosition.x, pxPosition.y, pxPosition.z);
normal.set(pxNormal.x, pxNormal.y, pxNormal.z);
outHitResult(pxSweepHit.getShape().getUUID(), pxSweepHit.distance, position, normal);
return result;
} finally {
pxSweepHit.delete();
}

pxSweepCallback.delete();
pxSweepHit.delete();

return result;
}

private _overlapMultiple(
geometry: any,
pose: { translation: Vector3; rotation: Quaternion },
onOverlap: (obj: number) => boolean
): number[] {
const overlapCallback = {
preFilter: (filterData, index, actor) => (onOverlap(index) ? 2 : 0)
};

const pxOverlapCallback = this._physXPhysics._physX.PxQueryFilterCallback.implement(overlapCallback);
const onOverlapStack = this._onOverlapStack;
onOverlapStack.push(onOverlap);
const maxHits = 256;
const hits: any = (this._pxScene as any).overlapMultiple(
geometry,
pose,
maxHits,
this._pxFilterData,
pxOverlapCallback
);
let hits: any;
try {
hits = (this._pxScene as any).overlapMultiple(
geometry,
pose,
maxHits,
this._pxFilterData,
this._pxOverlapCallback
);
} finally {
onOverlapStack.pop();
}

const result = PhysXPhysicsScene._tempShapeIDs;
result.length = 0;
Expand All @@ -509,7 +545,6 @@ export class PhysXPhysicsScene implements IPhysicsScene {
}
}

pxOverlapCallback.delete();
hits?.delete();
return result;
}
Expand Down Expand Up @@ -570,6 +605,16 @@ enum QueryFlag {
NO_BLOCK = 1 << 5
}

/**
* Result returned from a PhysX query filter callback (mirrors `PxQueryHitType`).
*/
enum QueryHitType {
/** Filter the hit out (no further processing). */
NONE = 0,
/** Treat the hit as a blocking hit (terminates query for single-hit modes). */
BLOCK = 2
}

enum PhysicsEventState {
Enter = 0,
Stay = 1,
Expand Down
Loading
Loading