Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 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
140 changes: 81 additions & 59 deletions packages/physics-physx/src/PhysXPhysicsScene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,24 @@ export class PhysXPhysicsScene implements IPhysicsScene {
private _physXPhysics: PhysXPhysics;
private _physXManager: PhysXPhysicsManager;
private _pxRaycastHit: any;
private _pxSweepHit: any;
private _pxFilterData: any;
private _pxRaycastSweepFilterData: any;

private _pxScene: any;
private _physXSimulationCallbackInstance: any;

// A single persistent PhysX query filter callback is shared by raycast,
// sweep and overlap. PhysX SDK guarantees that `postFilter` is only invoked
// when `PxQueryFlag::ePOSTFILTER` is set on the query's filter data, so
// overlap (whose filter data omits POST_FILTER) safely uses the same
// callback that also handles the raycast/sweep initial-overlap skip.
// The user-supplied predicate is stored in `_currentOnQuery`; reentrant
// calls save the previous value on the call stack via a local in each
// query method, recreating C++-style RAII without an explicit stack array.
private _pxQueryCallback: any;
private _currentOnQuery: (obj: number) => boolean = null;

private _activeTriggers: DisorderedArray<TriggerEvent> = new DisorderedArray<TriggerEvent>();
private _contactEvents: ContactEvent[] = [];
private _contactEventCount = 0;
Expand All @@ -49,8 +62,13 @@ export class PhysXPhysicsScene implements IPhysicsScene {
const physX = physXPhysics._physX;

this._pxRaycastHit = new physX.PxRaycastHit();
this._pxSweepHit = new physX.PxSweepHit();
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 +109,15 @@ export class PhysXPhysicsScene implements IPhysicsScene {
);
this._pxScene = pxPhysics.createScene(sceneDesc);
sceneDesc.delete();

const scene = this;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const scene = this; 是冗余 — 箭头函数已经从构造器的 lexical scope capture 了 this,直接 this._currentOnQuery(index) 即可。

-    const scene = this;
-    this._pxQueryCallback = physX.PxQueryFilterCallback.implement({
-      preFilter: (_filterData: any, index: number, _actor: any) =>
-        scene._currentOnQuery(index) ? QueryHitType.BLOCK : QueryHitType.NONE,
+    this._pxQueryCallback = physX.PxQueryFilterCallback.implement({
+      preFilter: (_filterData: any, index: number, _actor: any) =>
+        this._currentOnQuery(index) ? QueryHitType.BLOCK : QueryHitType.NONE,

看着像在绕什么 this 绑定坑,实际上没有。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

第一性原理核实正确:同文件 73-101 行的 triggerCallback 早就在 physX.PxSimulationEventCallback.implement() 里用 this._bufferContactEvent(...) 等直接调用,证明 emscripten .implement() 不破坏箭头函数 thisconst scene = this 是孤例残留。已 push 修复(eb3a7e930)。

this._pxQueryCallback = physX.PxQueryFilterCallback.implement({
preFilter: (_filterData: any, index: number, _actor: any) =>
scene._currentOnQuery(index) ? QueryHitType.BLOCK : QueryHitType.NONE,
// distance <= 0 means initial overlap — drop the hit so subsequent hits can be considered.
// Only invoked when the query's filter data includes POST_FILTER (raycast/sweep, not overlap).
postFilter: (_filterData: any, distance: number) => (distance <= 0 ? QueryHitType.NONE : QueryHitType.BLOCK)
});
}

/**
Expand Down Expand Up @@ -207,27 +234,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 prevOnQuery = this._currentOnQuery;
this._currentOnQuery = onRaycast;
let result: boolean;
try {
result = this._pxScene.raycastSingle(
ray.origin,
ray.direction,
distance,
pxHitResult,
this._pxRaycastSweepFilterData,
this._pxQueryCallback
);
} finally {
this._currentOnQuery = prevOnQuery;
}

if (result && hit != undefined) {
const { _tempPosition: position, _tempNormal: normal } = PhysXPhysicsScene;
Expand Down Expand Up @@ -390,8 +411,12 @@ export class PhysXPhysicsScene implements IPhysicsScene {

this._physXSimulationCallbackInstance.delete();
this._pxRaycastHit.delete();
this._pxSweepHit.delete();
this._pxFilterData.flags.delete();
this._pxFilterData.delete();
this._pxRaycastSweepFilterData.flags.delete();
this._pxRaycastSweepFilterData.delete();
this._pxQueryCallback.delete();
// Need to release the controller manager before release the scene.
this._pxControllerManager?.release();
this._pxScene.release();
Expand Down Expand Up @@ -443,29 +468,25 @@ export class PhysXPhysicsScene implements IPhysicsScene {
onSweep: (obj: number) => boolean,
outHitResult?: (shapeUniqueID: number, distance: number, position: Vector3, normal: Vector3) => void
): boolean {
const { _pxSweepHit: pxSweepHit } = this;
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 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
);
const prevOnQuery = this._currentOnQuery;
this._currentOnQuery = onSweep;
let result: boolean;
try {
result = this._pxScene.sweepSingle(
geometry,
pose,
direction,
distance,
pxSweepHit,
this._pxRaycastSweepFilterData,
this._pxQueryCallback
);
} finally {
this._currentOnQuery = prevOnQuery;
}

if (result && outHitResult != undefined) {
const { _tempPosition: position, _tempNormal: normal } = PhysXPhysicsScene;
Expand All @@ -474,10 +495,6 @@ export class PhysXPhysicsScene implements IPhysicsScene {
normal.set(pxNormal.x, pxNormal.y, pxNormal.z);
outHitResult(pxSweepHit.getShape().getUUID(), pxSweepHit.distance, position, normal);
}

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

return result;
}

Expand All @@ -486,19 +503,15 @@ export class PhysXPhysicsScene implements IPhysicsScene {
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 prevOnQuery = this._currentOnQuery;
this._currentOnQuery = 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._pxQueryCallback);
} finally {
this._currentOnQuery = prevOnQuery;
}

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

pxOverlapCallback.delete();
hits?.delete();
return result;
}
Expand Down Expand Up @@ -570,6 +582,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