Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
29 changes: 23 additions & 6 deletions packages/dev/core/src/Physics/v2/Plugins/havokPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,12 @@ export interface HavokPluginParameters {
* Maximum number of raycast hits to process
*/
maxQueryCollectorHits?: number;
/**
* Whether to disable Havok world regions when floating origin mode is enabled.
* Set this when the application manages physics precision through its own rebasing system.
* Default is false.
*/
disableWorldRegions?: boolean;
/**
* Radius of each floating origin world region.
* Bodies within this radius of a world region's origin will use that world.
Expand Down Expand Up @@ -403,6 +409,18 @@ export class HavokPlugin implements IPhysicsEnginePluginV2 {
* Bodies within this radius of a world region's origin will use that world.
*/
private _floatingOriginWorldRadius: number = 100000;
/**
* Whether Havok world regions are disabled.
*/
private _disableWorldRegions: boolean = false;

/**
* Whether floating origin world regions are enabled for the current scene.
* @returns true when the scene uses floating origin mode and world regions are not disabled
*/
private _areFloatingOriginWorldRegionsEnabled(): boolean {
return !this._disableWorldRegions && !!FloatingOriginCurrentScene.getScene()?.floatingOriginMode;
}

/**
* Finds an existing world region that contains the given world position,
Expand All @@ -417,8 +435,7 @@ export class HavokPlugin implements IPhysicsEnginePluginV2 {
*/
private _getOrCreateWorldRegion(worldPosition: Vector3): PhysicsWorldRegion {
// Check if floating origin mode is enabled
const scene = FloatingOriginCurrentScene.getScene();
if (!scene?.floatingOriginMode) {
if (!this._areFloatingOriginWorldRegionsEnabled()) {
// When floating origin mode is disabled, use the default world region
return this._worldRegions[0];
}
Expand Down Expand Up @@ -533,8 +550,7 @@ export class HavokPlugin implements IPhysicsEnginePluginV2 {
* @returns null if no existing region contains it (does NOT create a new one).
*/
private _findExistingRegion(worldPosition: Vector3): PhysicsWorldRegion | null {
const scene = FloatingOriginCurrentScene.getScene();
if (!scene?.floatingOriginMode) {
if (!this._areFloatingOriginWorldRegionsEnabled()) {
return this._worldRegions[0];
}

Expand Down Expand Up @@ -612,6 +628,7 @@ export class HavokPlugin implements IPhysicsEnginePluginV2 {

this._queryCollector = this._hknp.HP_QueryCollector_Create(1)[1];
this.setMaxQueryCollectorHits(parameters.maxQueryCollectorHits ?? 1);
this._disableWorldRegions = parameters.disableWorldRegions ?? false;
this._floatingOriginWorldRadius = parameters.floatingOriginWorldRadius ?? 100000;
}
/**
Expand Down Expand Up @@ -727,7 +744,7 @@ export class HavokPlugin implements IPhysicsEnginePluginV2 {
// Re-region bodies that have moved outside their current world region
// BEFORE pre-step and stepping, so the body participates in the correct
// world's step and its body buffer transform is valid when sync reads it.
if (this._worldRegions.length > 1 || FloatingOriginCurrentScene.getScene()?.floatingOriginMode) {
if (this._areFloatingOriginWorldRegionsEnabled()) {
for (const physicsBody of physicsBodies) {
if (physicsBody._pluginDataInstances.length > 0) {
for (const instance of physicsBody._pluginDataInstances) {
Expand Down Expand Up @@ -1587,7 +1604,7 @@ export class HavokPlugin implements IPhysicsEnginePluginV2 {
// the transform node) immediately land in the correct region with
// correct local coordinates, avoiding a one-frame precision glitch.
const pluginData = body._pluginData;
if (pluginData.worldRegion && (this._worldRegions.length > 1 || FloatingOriginCurrentScene.getScene()?.floatingOriginMode)) {
if (pluginData.worldRegion && this._areFloatingOriginWorldRegionsEnabled()) {
// Get world position of the node
const worldPos = TmpVectors.Vector3[3];
if (node.parent) {
Expand Down
23 changes: 23 additions & 0 deletions packages/dev/core/test/unit/Physics/havokPlugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ function createPlugin(worldRegions: TestWorldRegion[], initialBodyCounts: Readon
_bodies: new Map(),
_fixedTimeStep: 1 / 60,
_floatingOriginWorldRadius: 100_000,
_disableWorldRegions: false,
_useDeltaForWorldStep: false,
}) as HavokPlugin;

Expand All @@ -74,6 +75,28 @@ function createBody(worldRegion: TestWorldRegion): PhysicsBody {
} as unknown as PhysicsBody;
}

describe("HavokPlugin world region configuration", () => {
afterEach(() => {
vi.restoreAllMocks();
});

it("uses the default world when floating origin world regions are disabled", () => {
const defaultWorld = 1n;
const hknp = {
HP_QueryCollector_Create: vi.fn(() => [0, 2n]),
HP_World_Create: vi.fn(() => [0, defaultWorld]),
HP_World_SetGravity: vi.fn(),
};
const plugin = new HavokPlugin(true, hknp, { disableWorldRegions: true });
vi.spyOn(FloatingOriginCurrentScene, "getScene").mockReturnValue({ floatingOriginMode: true } as Scene);

plugin.setGravity(new Vector3(0, -9.81, 0), new Vector3(200_000, 0, 0));

expect(hknp.HP_World_Create).toHaveBeenCalledOnce();
expect(hknp.HP_World_SetGravity).toHaveBeenCalledExactlyOnceWith(defaultWorld, [0, -9.81, 0]);
});
});

describe("HavokPlugin world region lifecycle", () => {
afterEach(() => {
vi.restoreAllMocks();
Expand Down