Skip to content

Commit dd61227

Browse files
georginahalpernGeorgina Halpern
andauthored
useLargeWorldRendering on engine enables floatingOrigin and highMatrixPrecision. Add ability to useFloatingOrigin per-scene (#17334)
This PR solves 2 major bugs in floatingoriginmode. - Previously I was updating the creationOptions object but that didn't actually update the underlying performanceConfigurator's precision, so we were getting CPU-side calculation imprecision. - Additionally, the floatingOriginOffset value was tied to the most recently created scene's active camera, and didn't support multi-scene. After this change: - engine creation **useLargeWorldRendering** will both set useHighPrecisionMatrix on engine and set all scenes to useFloatingOrigin upon creation - scene creation **useFloatingOrigin** can be used instead of the above if user wants only some scenes to useFloatingOrigin (doing this can improve perf for scenes that are not large worlds as we skip matrix offsetting). If this option is used, must be used in conjunction with engine's useHighPrecisionMatrix to achieve full precision) - offset will always be tied to the current rendering scene's active camera Tested with this playground [#P3E9YP#255 ](https://playground.babylonjs.com/?snapshot=refs/pull/17334/merge#P3E9YP#255) which enables swapping between scenes and testing combinations of floatingOrigin on / off --------- Co-authored-by: Georgina Halpern <[email protected]>
1 parent 836516f commit dd61227

File tree

4 files changed

+71
-33
lines changed

4 files changed

+71
-33
lines changed

packages/dev/core/src/Engines/abstractEngine.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,22 @@ export interface AbstractEngineOptions {
132132
doNotHandleTouchAction?: boolean;
133133

134134
/**
135-
* Make the matrix computations to be performed in 64 bits instead of 32 bits. False by default
135+
* Make the matrix computations to be performed in 64 bits instead of 32 bits. False by default.
136+
* Note that setting useLargeWorldRendering will also set high precision matrices
136137
*/
137138
useHighPrecisionMatrix?: boolean;
138139

140+
/**
141+
* @experimental
142+
* LargeWorldRendering helps avoid floating point imprecision of rendering large worlds by
143+
* 1. Forcing highPrecisionMatrices (matrix computations in 64 bits instead of 32)
144+
* 2. Enabling floatingOriginMode in all scenes -- offsetting position-related uniform and attribute values before passing to shader so that active camera is centered at origin and world is offset by active camera position
145+
*
146+
* NOTE that if this mode is set during engineCreation, all scenes will have floatingOrigin offset and you do not need to send floatingOriginMode option to each scene creation.
147+
* If you'd like to have only specific scenes using the offset logic, you can set the flag on those scenes directly -- however, to achieve proper large world rendering, you must also set the useHighPrecisionMatrix option on engine.
148+
*/
149+
readonly useLargeWorldRendering?: boolean;
150+
139151
/**
140152
* Defines whether to adapt to the device's viewport characteristics (default: false)
141153
*/
@@ -2019,6 +2031,7 @@ export abstract class AbstractEngine {
20192031

20202032
/**
20212033
* Gets the options used for engine creation
2034+
* NOTE that modifying the object after engine creation will have no effect
20222035
* @returns EngineOptions object
20232036
*/
20242037
public getCreationOptions() {
@@ -2037,7 +2050,9 @@ export abstract class AbstractEngine {
20372050

20382051
this._stencilStateComposer.stencilGlobal = this._stencilState;
20392052

2040-
PerformanceConfigurator.SetMatrixPrecision(!!options.useHighPrecisionMatrix);
2053+
// LargeWorldRendering set to true will set high precision matrix, regardless of useHighPrecisionMatrix value
2054+
// It will also set all scenes to use floatingOriginMode upon their creation
2055+
PerformanceConfigurator.SetMatrixPrecision(!!options.useLargeWorldRendering || !!options.useHighPrecisionMatrix);
20412056

20422057
if (IsNavigatorAvailable() && navigator.userAgent) {
20432058
// Detect if we are running on a faulty buggy OS.

packages/dev/core/src/Materials/floatingOriginMatrixOverrides.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import { UniformBuffer } from "./uniformBuffer";
99
const TempFinalMat: Matrix = new Matrix();
1010
const TempMat1: Matrix = new Matrix();
1111
const TempMat2: Matrix = new Matrix();
12+
/**
13+
* When rendering, each scene will reset this to ensure the correct floating origin offset is when overriding the below functions
14+
*/
15+
export const FloatingOriginCurrentScene = {
16+
getScene: () => undefined as Scene | undefined,
17+
};
1218

1319
function OffsetWorldToRef(offset: IVector3Like, world: DeepImmutable<IMatrixLike>, ref: Matrix): DeepImmutable<IMatrixLike> {
1420
const refArray = ref.asArray();
@@ -75,19 +81,25 @@ function OffsetWorldViewProjectionToRef(
7581
return ref;
7682
}
7783

78-
function GetOffsetMatrix(uniformName: string, mat: IMatrixLike, scene: Scene): IMatrixLike {
84+
function GetOffsetMatrix(uniformName: string, mat: IMatrixLike): IMatrixLike {
7985
TempFinalMat.updateFlag = mat.updateFlag;
86+
const scene = FloatingOriginCurrentScene.getScene();
87+
// Early out for scenes that don't have floatingOriginMode enabled
88+
if (!scene) {
89+
return mat;
90+
}
91+
const offset = scene.floatingOriginOffset;
8092
switch (uniformName) {
8193
case "world":
82-
return OffsetWorldToRef(scene.floatingOriginOffset, mat, TempFinalMat);
94+
return OffsetWorldToRef(offset, mat, TempFinalMat);
8395
case "view":
8496
return OffsetViewToRef(mat, TempFinalMat);
8597
case "worldView":
86-
return OffsetWorldViewToRef(scene.floatingOriginOffset, mat, scene.getViewMatrix(), TempFinalMat);
98+
return OffsetWorldViewToRef(offset, mat, scene.getViewMatrix(), TempFinalMat);
8799
case "viewProjection":
88100
return OffsetViewProjectionToRef(scene.getViewMatrix(), scene.getProjectionMatrix(), TempFinalMat);
89101
case "worldViewProjection":
90-
return OffsetWorldViewProjectionToRef(scene.floatingOriginOffset, mat, scene.getTransformMatrix(), scene.getViewMatrix(), scene.getProjectionMatrix(), TempFinalMat);
102+
return OffsetWorldViewProjectionToRef(offset, mat, scene.getTransformMatrix(), scene.getViewMatrix(), scene.getProjectionMatrix(), TempFinalMat);
91103
default:
92104
return mat;
93105
}
@@ -106,14 +118,14 @@ export function ResetMatrixFunctions() {
106118
UniformBufferInternal.prototype._updateMatrixForUniformOverride = undefined;
107119
}
108120

109-
export function OverrideMatrixFunctions(scene: Scene) {
110-
EffectInternal.prototype._setMatrixOverride = Effect.prototype.setMatrix;
121+
export function OverrideMatrixFunctions() {
122+
EffectInternal.prototype._setMatrixOverride = OriginalSetMatrix;
111123
EffectInternal.prototype.setMatrix = function (uniformName: string, matrix: IMatrixLike) {
112-
this._setMatrixOverride(uniformName, GetOffsetMatrix(uniformName, matrix, scene));
124+
this._setMatrixOverride(uniformName, GetOffsetMatrix(uniformName, matrix));
113125
return this;
114126
};
115-
UniformBufferInternal.prototype._updateMatrixForUniformOverride = UniformBufferInternal.prototype._updateMatrixForUniform;
127+
UniformBufferInternal.prototype._updateMatrixForUniformOverride = OriginalUpdateMatrixForUniform;
116128
UniformBufferInternal.prototype._updateMatrixForUniform = function (uniformName: string, matrix: IMatrixLike) {
117-
this._updateMatrixForUniformOverride(uniformName, GetOffsetMatrix(uniformName, matrix, scene));
129+
this._updateMatrixForUniformOverride(uniformName, GetOffsetMatrix(uniformName, matrix));
118130
};
119131
}

packages/dev/core/src/scene.ts

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import type { KeyboardInfoPre, KeyboardInfo } from "./Events/keyboardEvents";
2121
import { ActionEvent } from "./Actions/actionEvent";
2222
import { PostProcessManager } from "./PostProcesses/postProcessManager";
2323
import type { IOfflineProvider } from "./Offline/IOfflineProvider";
24-
import { OverrideMatrixFunctions, ResetMatrixFunctions } from "./Materials/floatingOriginMatrixOverrides";
24+
import { FloatingOriginCurrentScene, OverrideMatrixFunctions, ResetMatrixFunctions } from "./Materials/floatingOriginMatrixOverrides";
2525
import type { RenderingGroupInfo, IRenderingManagerAutoClearSetup } from "./Rendering/renderingManager";
2626
import { RenderingManager } from "./Rendering/renderingManager";
2727
import type {
@@ -136,16 +136,18 @@ export interface SceneOptions {
136136
*/
137137
useClonedMeshMap?: boolean;
138138

139-
/** Defines if the creation of the scene should impact the engine (Eg. UtilityLayer's scene) */
140-
virtual?: boolean;
141-
142139
/**
143140
* @experimental
144-
* FloatingOriginMode helps avoid floating point imprecision of rendering large worlds by
145-
* 1. Forcing the engine to use doublePrecision mode
146-
* 2. Offsetting uniform values before passing to shader so that camera is centered at origin and world is offset by camera position
141+
* When enabled, the scene can handle large world coordinate rendering without jittering caused by floating point imprecision on the GPU.
142+
* This mode offsets matrices and position-related attribute values before passing to shaders, centering camera at origin and offsetting other scene objects by camera active position.
143+
*
144+
* IMPORTANT: Only use this scene-level option if you intend to enable floating origin on a per-scene basis. Must use in conjunction with engine creation option 'useHighPrecisionMatrix' to fix CPU-side floating point imprecision.
145+
* HOWEVER if you want largeWorldRendering on ALL scenes, set the useLargeWorldRendering flag on the engine instead of this scene-level flag. Doing so will automatically set useHighPrecisionMatrix on the engine as well.
147146
*/
148-
floatingOriginMode?: boolean;
147+
useFloatingOrigin?: boolean;
148+
149+
/** Defines if the creation of the scene should impact the engine (Eg. UtilityLayer's scene) */
150+
virtual?: boolean;
149151
}
150152

151153
/**
@@ -2016,10 +2018,9 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer {
20162018
engine.scenes.push(this);
20172019
}
20182020

2019-
if (options?.floatingOriginMode) {
2020-
engine.getCreationOptions().useHighPrecisionMatrix = true;
2021-
OverrideMatrixFunctions(this);
2022-
this._floatingOriginMode = true;
2021+
if (engine.getCreationOptions().useLargeWorldRendering || options?.useFloatingOrigin) {
2022+
OverrideMatrixFunctions();
2023+
this._floatingOriginScene = this;
20232024
}
20242025

20252026
this._uid = null;
@@ -2779,15 +2780,14 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer {
27792780
this._projectionUpdateFlag = -1;
27802781
}
27812782

2782-
private _floatingOriginMode: boolean = false;
2783+
private _floatingOriginScene: Scene | undefined = undefined;
27832784
/**
27842785
* @experimental
2785-
* When true, enables floatingOriginMode which helps avoid floating point imprecision when using huge coordinate system by
2786-
* 1. Forcing the engine to use doublePrecision mode
2787-
* 2. Offsetting uniform values before passing to shader so that camera is centered at origin and world is offset by camera position
2786+
* True if floatingOriginMode was passed to engine or this scene creation otions.
2787+
* This mode avoids floating point imprecision in huge coordinate system by offsetting uniform values before passing to shader, centering camera at origin and displacing rest of scene by camera position
27882788
*/
27892789
public get floatingOriginMode(): boolean {
2790-
return this._floatingOriginMode;
2790+
return this._floatingOriginScene !== undefined;
27912791
}
27922792

27932793
private _floatingOriginOffsetDefault: Vector3 = Vector3.Zero();
@@ -5340,6 +5340,9 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer {
53405340
this._intermediateRendering = false;
53415341
}
53425342

5343+
private _getFloatingOriginScene = (): Scene | undefined => {
5344+
return this._floatingOriginScene;
5345+
};
53435346
/**
53445347
* Render the scene
53455348
* @param updateCameras defines a boolean indicating if cameras must update according to their inputs (true by default)
@@ -5354,6 +5357,9 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer {
53545357
this._checkIsReady();
53555358
}
53565359

5360+
// Ensures that the floatingOriginOffset is grabbed from the correct scene
5361+
FloatingOriginCurrentScene.getScene = this._getFloatingOriginScene;
5362+
53575363
this._frameId++;
53585364
this._defaultFrameBufferCleared = false;
53595365
this._checkCameraRenderTarget(this.activeCamera);
@@ -5684,6 +5690,13 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer {
56845690
this._engine.scenes.splice(index, 1);
56855691
}
56865692

5693+
this._floatingOriginScene = undefined;
5694+
if (this._engine.scenes.length === 0) {
5695+
// If this is the last scene to be disposed, reset matrix overrides
5696+
// Cannot reset from within engine class due floatingOriginMatrixOverrides file import side effects
5697+
ResetMatrixFunctions();
5698+
}
5699+
56875700
if (EngineStore._LastCreatedScene === this) {
56885701
EngineStore._LastCreatedScene = null;
56895702
let engineIndex = EngineStore.Instances.length - 1;
@@ -5758,8 +5771,6 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer {
57585771
this.onClearColorChangedObservable.clear();
57595772
this.onEnvironmentTextureChangedObservable.clear();
57605773
this.onMeshUnderPointerUpdatedObservable.clear();
5761-
5762-
ResetMatrixFunctions();
57635774
this._isDisposed = true;
57645775
}
57655776

packages/tools/tests/test/visualization/config.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2857,7 +2857,7 @@
28572857
},
28582858
{
28592859
"title": "Atmosphere Day (Planet Origin)",
2860-
"playgroundId": "#VO1Z0C#10",
2860+
"playgroundId": "#VO1Z0C#30",
28612861
"referenceImage": "atmosphere-day.png",
28622862
"excludedEngines": ["webgl1", "webgpu"],
28632863
"renderCount": 2
@@ -2871,7 +2871,7 @@
28712871
},
28722872
{
28732873
"title": "Atmosphere Sunset (Planet Origin)",
2874-
"playgroundId": "#VO1Z0C#11",
2874+
"playgroundId": "#VO1Z0C#31",
28752875
"referenceImage": "atmosphere-sunset.png",
28762876
"excludedEngines": ["webgl1", "webgpu"],
28772877
"renderCount": 2
@@ -2885,7 +2885,7 @@
28852885
},
28862886
{
28872887
"title": "Atmosphere Night (Planet Origin)",
2888-
"playgroundId": "#VO1Z0C#12",
2888+
"playgroundId": "#VO1Z0C#32",
28892889
"referenceImage": "atmosphere-night.png",
28902890
"excludedEngines": ["webgl1", "webgpu"],
28912891
"renderCount": 2

0 commit comments

Comments
 (0)