Skip to content

Commit 7282972

Browse files
authored
Atmosphere addon fixes for floating origin (#17378)
- Ensure atmosphere parameters get computed correctly when floating origin is enabled, assuming planet center is 0,0,0 in world space. - Use common dot product helper - **NOTE:** Minor breaking change to API; Include `Camera` as parameter to some existing observables that were previously `Observable<void>`.
1 parent cff1427 commit 7282972

File tree

5 files changed

+49
-24
lines changed

5 files changed

+49
-24
lines changed

packages/dev/addons/src/atmosphere/atmosphere.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,12 @@ export class Atmosphere implements IDisposable {
137137
/**
138138
* Called before the LUTs are rendered for this camera. This happens after the per-camera UBO update.
139139
*/
140-
public readonly onBeforeRenderLutsForCameraObservable = new Observable<void>();
140+
public readonly onBeforeRenderLutsForCameraObservable = new Observable<Camera>();
141141

142142
/**
143143
* Called after the LUTs were rendered.
144144
*/
145-
public readonly onAfterRenderLutsForCameraObservable = new Observable<void>();
145+
public readonly onAfterRenderLutsForCameraObservable = new Observable<Camera>();
146146

147147
/**
148148
* If provided, this is the depth texture used for composition passes.
@@ -734,7 +734,7 @@ export class Atmosphere implements IDisposable {
734734
// Before rendering, make sure the per-camera variables have been updated.
735735
this._onBeforeCameraRenderObserver = scene.onBeforeCameraRenderObservable.add((x) => {
736736
this._updatePerCameraVariables(x);
737-
this._renderLutsForCamera();
737+
this._renderLutsForCamera(x);
738738
});
739739

740740
{
@@ -1207,8 +1207,9 @@ export class Atmosphere implements IDisposable {
12071207
/**
12081208
* Renders the lookup tables, some of which can vary per-camera.
12091209
* It is expected that updatePerCameraVariables was previously called.
1210+
* @param camera - The camera to render the LUTs for.
12101211
*/
1211-
private _renderLutsForCamera(): void {
1212+
private _renderLutsForCamera(camera: Camera): void {
12121213
{
12131214
this.onBeforeLightVariablesUpdateObservable.notifyObservers();
12141215

@@ -1228,7 +1229,7 @@ export class Atmosphere implements IDisposable {
12281229
// Render the LUTs.
12291230
const isEnabled = this.isEnabled();
12301231
{
1231-
this.onBeforeRenderLutsForCameraObservable.notifyObservers();
1232+
this.onBeforeRenderLutsForCameraObservable.notifyObservers(camera);
12321233

12331234
// After UBO update we can render the global LUTs which use some of these values on the GPU.
12341235
// TODO: Could break out update and UBOs to global vs. per-camera.
@@ -1254,7 +1255,7 @@ export class Atmosphere implements IDisposable {
12541255
}
12551256
}
12561257

1257-
this.onAfterRenderLutsForCameraObservable.notifyObservers();
1258+
this.onAfterRenderLutsForCameraObservable.notifyObservers(camera);
12581259
}
12591260
}
12601261

packages/dev/addons/src/atmosphere/atmospherePBRMaterialPlugin.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ export class AtmospherePBRMaterialPlugin extends MaterialPluginBase {
152152
this._atmosphere.bindUniformBufferToEffect(effect);
153153
}
154154

155+
// Need the offset to apply which will take a world space position and convert it to a global space position in the atmosphere.
156+
// If floating origin mode is enabled, that offset is the floating origin offset.
157+
// If not, it's an offset up the Y-axis by the planet radius.
155158
uniformBuffer.updateVector3(
156159
OriginOffsetUniformName,
157160
scene.floatingOriginMode

packages/dev/addons/src/atmosphere/atmospherePerCameraVariables.ts

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,18 @@ export class AtmospherePerCameraVariables {
8686

8787
/**
8888
* The camera position in global space kilometers.
89+
*
90+
* The behavior of this value depends on whether floating origin mode is enabled:
91+
* - If floating origin mode is enabled, this is simply the camera's global position scaled to kilometers. The atmosphere's origin height is used to offset the camera position along its geocentric normal.
92+
* - If floating origin mode is disabled, the camera's y position is offset by the planet radius plus any origin height.
8993
*/
9094
public get cameraPositionGlobal(): IVector3Like {
9195
return this._cameraPositionGlobal;
9296
}
9397

9498
/**
9599
* The camera position, clamped to the planet radius offset, in global space kilometers.
100+
* See {@link cameraPositionGlobal} for details on how the value is computed.
96101
*/
97102
public get clampedCameraPositionGlobal(): IVector3Like {
98103
return this._clampedCameraPositionGlobal;
@@ -114,6 +119,7 @@ export class AtmospherePerCameraVariables {
114119

115120
/**
116121
* The geocentric normal of the camera in global space i.e., the normalization of {@link cameraPositionGlobal}.
122+
* Note the behavior of this value depends on whether floating origin mode is enabled. See {@link cameraPositionGlobal} for details.
117123
*/
118124
public get cameraGeocentricNormal(): IVector3Like {
119125
return this._cameraGeocentricNormal;
@@ -160,37 +166,51 @@ export class AtmospherePerCameraVariables {
160166
this._cameraNearPlane = camera.minZ;
161167
this._cameraForward.copyFrom(camera.getForwardRayToRef(TempRay, 1).direction);
162168

163-
const engine = camera.getScene().getEngine();
169+
const scene = camera.getScene();
170+
const engine = scene.getEngine();
164171
this._viewport.copyFromFloats(0.0, 0.0, engine.getRenderWidth(), engine.getRenderHeight());
165172

166173
// Compute inverse view projection matrix, but remove the translational component to increase precision.
167174
const viewMatrix = camera.getViewMatrix();
168175
const projectionMatrix = camera.getProjectionMatrix();
169-
if (!this._lastViewMatrix.equals(viewMatrix) || !this._lastProjectionMatrix.equals(projectionMatrix)) {
170-
this._lastViewMatrix.copyFrom(viewMatrix);
171-
this._lastViewMatrix.setTranslation(Vector3.ZeroReadOnly);
172-
this._lastViewMatrix.invertToRef(this._inverseViewMatrixWithoutTranslation);
173-
174-
this._lastProjectionMatrix.copyFrom(projectionMatrix);
175-
this._lastProjectionMatrix.invertToRef(this._inverseProjectionMatrix);
176+
const lastViewMatrix = this._lastViewMatrix;
177+
const lastProjectionMatrix = this._lastProjectionMatrix;
178+
if (!lastViewMatrix.equals(viewMatrix) || !lastProjectionMatrix.equals(projectionMatrix)) {
179+
lastViewMatrix.copyFrom(viewMatrix);
180+
lastViewMatrix.setTranslation(Vector3.ZeroReadOnly);
181+
lastViewMatrix.invertToRef(this._inverseViewMatrixWithoutTranslation);
182+
183+
lastProjectionMatrix.copyFrom(projectionMatrix);
184+
lastProjectionMatrix.invertToRef(this._inverseProjectionMatrix);
176185
this._inverseProjectionMatrix.multiplyToRef(this._inverseViewMatrixWithoutTranslation, this._inverseViewProjectionMatrixWithoutTranslation);
177186
}
178187

179188
// Compute the global space position of the camera in kilometers.
180-
this._cameraPosition.copyFrom(camera.globalPosition);
181-
this._cameraPosition.scaleToRef(1.0 / 1000.0, this._cameraPositionGlobal);
182-
this._cameraPositionGlobal.y += planetRadius + originHeight;
183-
this._cameraHeight = this._cameraPositionGlobal.y - planetRadius;
189+
const cameraPositionGlobal = this._cameraPosition.copyFrom(camera.globalPosition).scaleToRef(0.001, this._cameraPositionGlobal); // scale to kilometers
190+
191+
// Apply the origin height to the camera position, and in doing so, compute the camera geocentric normal.
192+
if (scene.floatingOriginMode) {
193+
// When in floating origin mode, assume world space origin is at the planet center.
194+
// Therefore "up" is away from the planet center (0, 0, 0).
195+
cameraPositionGlobal.normalizeToRef(this._cameraGeocentricNormal);
196+
this._cameraGeocentricNormal.scaleAndAddToRef(originHeight, cameraPositionGlobal);
197+
} else {
198+
// If not in floating origin mode, offset the camera position by the origin height.
199+
// Assume the origin is directly above the planet surface along the up axis (y axis).
200+
cameraPositionGlobal.y += planetRadius + originHeight;
201+
cameraPositionGlobal.normalizeToRef(this._cameraGeocentricNormal);
202+
}
203+
204+
this._cameraRadius = cameraPositionGlobal.length(); // distance from planet center
205+
this._cameraHeight = this._cameraRadius - planetRadius; // height above planet surface
184206

185207
// Clamp the camera parameters.
186-
this._cameraRadius = this._cameraPositionGlobal.length();
187208
this._clampedCameraRadius = this._cameraRadius;
188-
this._cameraPositionGlobal.normalizeToRef(this._cameraGeocentricNormal);
189209
if (this._clampedCameraRadius < planetRadiusWithOffset) {
190210
this._clampedCameraRadius = planetRadiusWithOffset;
191211
this._cameraGeocentricNormal.scaleToRef(planetRadiusWithOffset, this._clampedCameraPositionGlobal);
192212
} else {
193-
this._clampedCameraPositionGlobal.copyFrom(this._cameraPositionGlobal);
213+
this._clampedCameraPositionGlobal.copyFrom(cameraPositionGlobal);
194214
}
195215

196216
this._cosCameraHorizonAngleFromZenith = ComputeCosHorizonAngleFromZenith(planetRadius, this._clampedCameraRadius);

packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type { IColor3Like, IColor4Like, IVector2Like, IVector3Like } from "core/
1111
import type { Nullable } from "core/types";
1212
import { RenderTargetTexture } from "core/Materials/Textures/renderTargetTexture";
1313
import { Sample2DRgbaToRef } from "./sampling";
14+
import { Vector3Dot } from "core/Maths/math.vector.functions";
1415
import "./Shaders/diffuseSkyIrradiance.fragment";
1516
import "./Shaders/fullscreenTriangle.vertex";
1617

@@ -161,7 +162,7 @@ export class DiffuseSkyIrradianceLut {
161162
return result;
162163
}
163164

164-
const cosAngleLightToZenith = directionToLight.x * cameraGeocentricNormal.x + directionToLight.y * cameraGeocentricNormal.y + directionToLight.z * cameraGeocentricNormal.z;
165+
const cosAngleLightToZenith = Vector3Dot(directionToLight, cameraGeocentricNormal);
165166
ComputeLutUVToRef(properties, radius, cosAngleLightToZenith, UvTemp);
166167
Sample2DRgbaToRef(UvTemp.x, UvTemp.y, LutWidthPx, LutHeightPx, this._lutData, Color4Temp, FromHalfFloat);
167168

packages/dev/addons/src/atmosphere/transmittanceLut.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { Nullable } from "core/types";
1313
import { Observable } from "core/Misc/observable";
1414
import { RenderTargetTexture } from "core/Materials/Textures/renderTargetTexture";
1515
import { Sample2DRgbaToRef } from "./sampling";
16+
import { Vector3Dot } from "core/Maths/math.vector.functions";
1617
import "./Shaders/fullscreenTriangle.vertex";
1718
import "./Shaders/transmittance.fragment";
1819

@@ -162,8 +163,7 @@ export class TransmittanceLut {
162163
*/
163164
public getTransmittedColorToRef<T extends IColor3Like>(directionToLight: IVector3Like, pointRadius: number, pointGeocentricNormal: IVector3Like, result: T): T {
164165
if (this._lutData[0] !== undefined) {
165-
const cosAngleLightToZenith =
166-
directionToLight.x * pointGeocentricNormal.x + directionToLight.y * pointGeocentricNormal.y + directionToLight.z * pointGeocentricNormal.z;
166+
const cosAngleLightToZenith = Vector3Dot(directionToLight, pointGeocentricNormal);
167167
SampleLutToRef(this._atmosphere.physicalProperties, this._lutData, pointRadius, cosAngleLightToZenith, Color4Temp);
168168
result.r = Color4Temp.r;
169169
result.g = Color4Temp.g;

0 commit comments

Comments
 (0)