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
13 changes: 7 additions & 6 deletions packages/dev/addons/src/atmosphere/atmosphere.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,12 @@ export class Atmosphere implements IDisposable {
/**
* Called before the LUTs are rendered for this camera. This happens after the per-camera UBO update.
*/
public readonly onBeforeRenderLutsForCameraObservable = new Observable<void>();
public readonly onBeforeRenderLutsForCameraObservable = new Observable<Camera>();

/**
* Called after the LUTs were rendered.
*/
public readonly onAfterRenderLutsForCameraObservable = new Observable<void>();
public readonly onAfterRenderLutsForCameraObservable = new Observable<Camera>();

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

{
Expand Down Expand Up @@ -1207,8 +1207,9 @@ export class Atmosphere implements IDisposable {
/**
* Renders the lookup tables, some of which can vary per-camera.
* It is expected that updatePerCameraVariables was previously called.
* @param camera - The camera to render the LUTs for.
*/
private _renderLutsForCamera(): void {
private _renderLutsForCamera(camera: Camera): void {
{
this.onBeforeLightVariablesUpdateObservable.notifyObservers();

Expand All @@ -1228,7 +1229,7 @@ export class Atmosphere implements IDisposable {
// Render the LUTs.
const isEnabled = this.isEnabled();
{
this.onBeforeRenderLutsForCameraObservable.notifyObservers();
this.onBeforeRenderLutsForCameraObservable.notifyObservers(camera);

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

this.onAfterRenderLutsForCameraObservable.notifyObservers();
this.onAfterRenderLutsForCameraObservable.notifyObservers(camera);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ export class AtmospherePBRMaterialPlugin extends MaterialPluginBase {
this._atmosphere.bindUniformBufferToEffect(effect);
}

// Need the offset to apply which will take a world space position and convert it to a global space position in the atmosphere.
// If floating origin mode is enabled, that offset is the floating origin offset.
// If not, it's an offset up the Y-axis by the planet radius.
uniformBuffer.updateVector3(
OriginOffsetUniformName,
scene.floatingOriginMode
Expand Down
50 changes: 35 additions & 15 deletions packages/dev/addons/src/atmosphere/atmospherePerCameraVariables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,18 @@ export class AtmospherePerCameraVariables {

/**
* The camera position in global space kilometers.
*
* The behavior of this value depends on whether floating origin mode is enabled:
* - 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.
* - If floating origin mode is disabled, the camera's y position is offset by the planet radius plus any origin height.
*/
public get cameraPositionGlobal(): IVector3Like {
return this._cameraPositionGlobal;
}

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

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

const engine = camera.getScene().getEngine();
const scene = camera.getScene();
const engine = scene.getEngine();
this._viewport.copyFromFloats(0.0, 0.0, engine.getRenderWidth(), engine.getRenderHeight());

// Compute inverse view projection matrix, but remove the translational component to increase precision.
const viewMatrix = camera.getViewMatrix();
const projectionMatrix = camera.getProjectionMatrix();
if (!this._lastViewMatrix.equals(viewMatrix) || !this._lastProjectionMatrix.equals(projectionMatrix)) {
this._lastViewMatrix.copyFrom(viewMatrix);
this._lastViewMatrix.setTranslation(Vector3.ZeroReadOnly);
this._lastViewMatrix.invertToRef(this._inverseViewMatrixWithoutTranslation);

this._lastProjectionMatrix.copyFrom(projectionMatrix);
this._lastProjectionMatrix.invertToRef(this._inverseProjectionMatrix);
const lastViewMatrix = this._lastViewMatrix;
const lastProjectionMatrix = this._lastProjectionMatrix;
if (!lastViewMatrix.equals(viewMatrix) || !lastProjectionMatrix.equals(projectionMatrix)) {
lastViewMatrix.copyFrom(viewMatrix);
lastViewMatrix.setTranslation(Vector3.ZeroReadOnly);
lastViewMatrix.invertToRef(this._inverseViewMatrixWithoutTranslation);

lastProjectionMatrix.copyFrom(projectionMatrix);
lastProjectionMatrix.invertToRef(this._inverseProjectionMatrix);
this._inverseProjectionMatrix.multiplyToRef(this._inverseViewMatrixWithoutTranslation, this._inverseViewProjectionMatrixWithoutTranslation);
}

// Compute the global space position of the camera in kilometers.
this._cameraPosition.copyFrom(camera.globalPosition);
this._cameraPosition.scaleToRef(1.0 / 1000.0, this._cameraPositionGlobal);
this._cameraPositionGlobal.y += planetRadius + originHeight;
this._cameraHeight = this._cameraPositionGlobal.y - planetRadius;
const cameraPositionGlobal = this._cameraPosition.copyFrom(camera.globalPosition).scaleToRef(0.001, this._cameraPositionGlobal); // scale to kilometers

// Apply the origin height to the camera position, and in doing so, compute the camera geocentric normal.
if (scene.floatingOriginMode) {
// When in floating origin mode, assume world space origin is at the planet center.
// Therefore "up" is away from the planet center (0, 0, 0).
cameraPositionGlobal.normalizeToRef(this._cameraGeocentricNormal);
this._cameraGeocentricNormal.scaleAndAddToRef(originHeight, cameraPositionGlobal);
} else {
// If not in floating origin mode, offset the camera position by the origin height.
// Assume the origin is directly above the planet surface along the up axis (y axis).
cameraPositionGlobal.y += planetRadius + originHeight;
cameraPositionGlobal.normalizeToRef(this._cameraGeocentricNormal);
}

this._cameraRadius = cameraPositionGlobal.length(); // distance from planet center
this._cameraHeight = this._cameraRadius - planetRadius; // height above planet surface

// Clamp the camera parameters.
this._cameraRadius = this._cameraPositionGlobal.length();
this._clampedCameraRadius = this._cameraRadius;
this._cameraPositionGlobal.normalizeToRef(this._cameraGeocentricNormal);
if (this._clampedCameraRadius < planetRadiusWithOffset) {
this._clampedCameraRadius = planetRadiusWithOffset;
this._cameraGeocentricNormal.scaleToRef(planetRadiusWithOffset, this._clampedCameraPositionGlobal);
} else {
this._clampedCameraPositionGlobal.copyFrom(this._cameraPositionGlobal);
this._clampedCameraPositionGlobal.copyFrom(cameraPositionGlobal);
}

this._cosCameraHorizonAngleFromZenith = ComputeCosHorizonAngleFromZenith(planetRadius, this._clampedCameraRadius);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { IColor3Like, IColor4Like, IVector2Like, IVector3Like } from "core/
import type { Nullable } from "core/types";
import { RenderTargetTexture } from "core/Materials/Textures/renderTargetTexture";
import { Sample2DRgbaToRef } from "./sampling";
import { Vector3Dot } from "core/Maths/math.vector.functions";
import "./Shaders/diffuseSkyIrradiance.fragment";
import "./Shaders/fullscreenTriangle.vertex";

Expand Down Expand Up @@ -161,7 +162,7 @@ export class DiffuseSkyIrradianceLut {
return result;
}

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

Expand Down
4 changes: 2 additions & 2 deletions packages/dev/addons/src/atmosphere/transmittanceLut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { Nullable } from "core/types";
import { Observable } from "core/Misc/observable";
import { RenderTargetTexture } from "core/Materials/Textures/renderTargetTexture";
import { Sample2DRgbaToRef } from "./sampling";
import { Vector3Dot } from "core/Maths/math.vector.functions";
import "./Shaders/fullscreenTriangle.vertex";
import "./Shaders/transmittance.fragment";

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