From 0e5c60c6cfd844203e22b5fc60dab4097ac7d6cb Mon Sep 17 00:00:00 2001 From: kircher1 <20366429+kircher1@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:21:53 -0700 Subject: [PATCH 1/3] Use engine capabilities for determining texture types --- packages/dev/addons/src/atmosphere/atmosphere.ts | 16 +++++++++++----- .../src/atmosphere/diffuseSkyIrradianceLut.ts | 6 ++++-- .../addons/src/atmosphere/transmittanceLut.ts | 5 +++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/dev/addons/src/atmosphere/atmosphere.ts b/packages/dev/addons/src/atmosphere/atmosphere.ts index 519085f4e96..a2aed1b6ebe 100644 --- a/packages/dev/addons/src/atmosphere/atmosphere.ts +++ b/packages/dev/addons/src/atmosphere/atmosphere.ts @@ -40,6 +40,8 @@ import "./Shaders/ShadersInclude/depthFunctions"; const MaterialPlugin = "atmo-pbr"; +let UniqueId = 0; + /** * Renders a physically based atmosphere. * Use {@link IsSupported} to check if the atmosphere is supported before creating an instance. @@ -114,6 +116,11 @@ export class Atmosphere implements IDisposable { return !engine._badOS && !engine.isWebGPU && engine.version >= 2; } + /** + * The unique ID of this atmosphere instance. + */ + public readonly uniqueId = UniqueId++; + /** * Called after the atmosphere variables have been updated for the specified camera. */ @@ -637,8 +644,6 @@ export class Atmosphere implements IDisposable { return this._cameraAtmosphereVariables; } - public readonly uniqueId: number; - /** * Constructs the {@link Atmosphere}. * @param name - The name of this instance. @@ -653,7 +658,6 @@ export class Atmosphere implements IDisposable { options?: IAtmosphereOptions ) { const engine = (this._engine = scene.getEngine()); - this.uniqueId = scene.getUniqueId(); if (engine.isWebGPU) { throw new Error("Atmosphere is not supported on WebGPU."); @@ -1422,13 +1426,15 @@ const CreateRenderTargetTexture = ( scene: Scene, options?: RenderTargetTextureOptions ): RenderTargetTexture => { + const caps = scene.getEngine().getCaps(); + const textureType = caps.textureHalfFloatRender ? Constants.TEXTURETYPE_HALF_FLOAT : caps.textureFloatRender ? Constants.TEXTURETYPE_FLOAT : Constants.TEXTURETYPE_BYTE; const rtOptions: RenderTargetTextureOptions = { generateMipMaps: false, generateDepthBuffer: false, generateStencilBuffer: false, gammaSpace: false, samplingMode: Constants.TEXTURE_BILINEAR_SAMPLINGMODE, - type: Constants.TEXTURETYPE_HALF_FLOAT, + type: textureType, format: Constants.TEXTUREFORMAT_RGBA, ...options, }; @@ -1437,7 +1443,7 @@ const CreateRenderTargetTexture = ( renderTarget.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE; renderTarget.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE; renderTarget.anisotropicFilteringLevel = 1; - renderTarget.skipInitialClear = true; + //renderTarget.skipInitialClear = true; return renderTarget; }; diff --git a/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts b/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts index a8ef89effa7..332ba5c681b 100644 --- a/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts +++ b/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts @@ -83,9 +83,11 @@ export class DiffuseSkyIrradianceLut { const engine = scene.getEngine(); const name = "atmo-diffuseSkyIrradiance"; + const caps = engine.getCaps(); + const textureType = caps.textureHalfFloatRender ? Constants.TEXTURETYPE_HALF_FLOAT : caps.textureFloatRender ? Constants.TEXTURETYPE_FLOAT : Constants.TEXTURETYPE_BYTE; const renderTarget = (this._renderTarget = new RenderTargetTexture(name, { width: LutWidthPx, height: LutHeightPx }, scene, { generateMipMaps: false, - type: Constants.TEXTURETYPE_HALF_FLOAT, + type: textureType, samplingMode: Constants.TEXTURE_BILINEAR_SAMPLINGMODE, generateDepthBuffer: false, gammaSpace: false, @@ -93,7 +95,7 @@ export class DiffuseSkyIrradianceLut { renderTarget.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE; renderTarget.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE; renderTarget.anisotropicFilteringLevel = 1; - renderTarget.skipInitialClear = true; + //renderTarget.skipInitialClear = true; const useUbo = atmosphere.uniformBuffer.useUbo; diff --git a/packages/dev/addons/src/atmosphere/transmittanceLut.ts b/packages/dev/addons/src/atmosphere/transmittanceLut.ts index b3898ab36b3..88abb8ea5da 100644 --- a/packages/dev/addons/src/atmosphere/transmittanceLut.ts +++ b/packages/dev/addons/src/atmosphere/transmittanceLut.ts @@ -117,10 +117,11 @@ export class TransmittanceLut { const scene = this._atmosphere.scene; const engine = scene.getEngine(); + const useHalfFloat = UseHalfFloat && engine.getCaps().textureHalfFloatRender; const name = "atmo-transmittance"; const renderTarget = (this._renderTarget = new RenderTargetTexture(name, { width: LutWidthPx, height: LutHeightPx }, scene, { - type: UseHalfFloat ? Constants.TEXTURETYPE_HALF_FLOAT : Constants.TEXTURETYPE_UNSIGNED_BYTE, + type: useHalfFloat ? Constants.TEXTURETYPE_HALF_FLOAT : Constants.TEXTURETYPE_UNSIGNED_BYTE, samplingMode: Constants.TEXTURE_BILINEAR_SAMPLINGMODE, generateDepthBuffer: false, gammaSpace: false, @@ -128,7 +129,7 @@ export class TransmittanceLut { renderTarget.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE; renderTarget.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE; renderTarget.anisotropicFilteringLevel = 1; - renderTarget.skipInitialClear = true; + //renderTarget.skipInitialClear = true; const useUbo = this._atmosphere.uniformBuffer.useUbo; this._effectWrapper = new EffectWrapper({ From a1b54a872258aabd74089881b60740d7a962226b Mon Sep 17 00:00:00 2001 From: kircher1 <20366429+kircher1@users.noreply.github.com> Date: Tue, 23 Sep 2025 16:54:49 -0700 Subject: [PATCH 2/3] force ubyte --- packages/dev/addons/src/atmosphere/atmosphere.ts | 4 ++-- packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/dev/addons/src/atmosphere/atmosphere.ts b/packages/dev/addons/src/atmosphere/atmosphere.ts index a2aed1b6ebe..e5054a42b6b 100644 --- a/packages/dev/addons/src/atmosphere/atmosphere.ts +++ b/packages/dev/addons/src/atmosphere/atmosphere.ts @@ -1426,8 +1426,8 @@ const CreateRenderTargetTexture = ( scene: Scene, options?: RenderTargetTextureOptions ): RenderTargetTexture => { - const caps = scene.getEngine().getCaps(); - const textureType = caps.textureHalfFloatRender ? Constants.TEXTURETYPE_HALF_FLOAT : caps.textureFloatRender ? Constants.TEXTURETYPE_FLOAT : Constants.TEXTURETYPE_BYTE; + //const caps = scene.getEngine().getCaps(); + const textureType = Constants.TEXTURETYPE_UNSIGNED_BYTE; // caps.textureHalfFloatRender ? Constants.TEXTURETYPE_HALF_FLOAT : caps.textureFloatRender ? Constants.TEXTURETYPE_FLOAT : Constants.TEXTURETYPE_UNSIGNED_BYTE; const rtOptions: RenderTargetTextureOptions = { generateMipMaps: false, generateDepthBuffer: false, diff --git a/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts b/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts index 332ba5c681b..1c09b7104c0 100644 --- a/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts +++ b/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts @@ -83,8 +83,8 @@ export class DiffuseSkyIrradianceLut { const engine = scene.getEngine(); const name = "atmo-diffuseSkyIrradiance"; - const caps = engine.getCaps(); - const textureType = caps.textureHalfFloatRender ? Constants.TEXTURETYPE_HALF_FLOAT : caps.textureFloatRender ? Constants.TEXTURETYPE_FLOAT : Constants.TEXTURETYPE_BYTE; + //const caps = engine.getCaps(); + const textureType = Constants.TEXTURETYPE_UNSIGNED_BYTE; const renderTarget = (this._renderTarget = new RenderTargetTexture(name, { width: LutWidthPx, height: LutHeightPx }, scene, { generateMipMaps: false, type: textureType, From 0a450e960952b1e9da091022a3a298e773475c9d Mon Sep 17 00:00:00 2001 From: kircher1 <20366429+kircher1@users.noreply.github.com> Date: Tue, 23 Sep 2025 19:21:26 -0700 Subject: [PATCH 3/3] clear aerial perspective LUT --- .../dev/addons/src/atmosphere/atmosphere.ts | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/packages/dev/addons/src/atmosphere/atmosphere.ts b/packages/dev/addons/src/atmosphere/atmosphere.ts index e5054a42b6b..39dc9f83f7d 100644 --- a/packages/dev/addons/src/atmosphere/atmosphere.ts +++ b/packages/dev/addons/src/atmosphere/atmosphere.ts @@ -40,6 +40,8 @@ import "./Shaders/ShadersInclude/depthFunctions"; const MaterialPlugin = "atmo-pbr"; +const AerialPerspectiveLutLayers = 32; + let UniqueId = 0; /** @@ -86,6 +88,7 @@ export class Atmosphere implements IDisposable { private _aerialPerspectiveRenderingGroup: number; private _globeAtmosphereRenderingGroup: number; private _isEnabled = true; + private _aerialPerspectiveLutHasBeenRendered = false; private _hasRenderedMultiScatteringLut = false; private _multiScatteringEffectWrapper: Nullable = null; @@ -347,7 +350,7 @@ export class Atmosphere implements IDisposable { const scene = this.scene; const name = "atmo-aerialPerspective"; - const renderTarget = (this._aerialPerspectiveLutRenderTarget = CreateRenderTargetTexture(name, { width: 16, height: 64, layers: 32 }, scene, {})); + const renderTarget = (this._aerialPerspectiveLutRenderTarget = CreateRenderTargetTexture(name, { width: 16, height: 64, layers: AerialPerspectiveLutLayers }, scene, {})); this._aerialPerspectiveLutEffectWrapper = CreateAerialPerspectiveEffectWrapper(this._engine, this.uniformBuffer); return renderTarget; @@ -1237,9 +1240,19 @@ export class Atmosphere implements IDisposable { this._drawSkyViewLut(); } - // Only need to render aerial perspective LUT when inside the atmosphere. - if (this._isAerialPerspectiveLutEnabled && this._cameraAtmosphereVariables.clampedCameraRadius <= this._physicalProperties.atmosphereRadius) { - this._drawAerialPerspectiveLut(); + if (this._isAerialPerspectiveLutEnabled) { + // Only need to fully render aerial perspective LUT when inside the atmosphere, + // otherwise it won't be used for rendering so is unnecessary overhead. + if (this._cameraAtmosphereVariables.clampedCameraRadius <= this._physicalProperties.atmosphereRadius) { + this._drawAerialPerspectiveLut(); + } else { + // Make sure to clear the LUT to some initial value if this would have otherwise been the first time rendering it. + // This prevents some GL warnings about uninitialized textures when the LUT is bound to a shader (even if it's not used). + if (!this._aerialPerspectiveLutHasBeenRendered) { + this._clearAerialPerspectiveLut(); + } + } + this._aerialPerspectiveLutHasBeenRendered = true; } } @@ -1354,10 +1367,9 @@ export class Atmosphere implements IDisposable { this._aerialPerspectiveLutRenderTarget, (effectRenderer, renderTarget, effect, engine) => { this.bindUniformBufferToEffect(effect); - const layers = 32; effect.setTexture("transmittanceLut", transmittanceLut); effect.setTexture("multiScatteringLut", multiScatteringLut); - for (let layer = 0; layer < layers; layer++) { + for (let layer = 0; layer < AerialPerspectiveLutLayers; layer++) { engine.bindFramebuffer(renderTarget!, undefined, undefined, undefined, true, undefined, layer); effectRenderer.bindBuffers(effect); effect.setFloat("layerIdx", layer); @@ -1367,6 +1379,17 @@ export class Atmosphere implements IDisposable { ); } + private _clearAerialPerspectiveLut(): void { + const renderTarget = this._aerialPerspectiveLutRenderTarget?.renderTarget; + if (renderTarget) { + const engine = this._engine; + for (let layer = 0; layer < AerialPerspectiveLutLayers; layer++) { + engine.bindFramebuffer(renderTarget, undefined, undefined, undefined, true, undefined, layer); + engine.clear({ r: 0, g: 0, b: 0, a: 0 }, true, false, false); + } + } + } + /** * Draws the sky view LUT using {@link EffectWrapper} and {@link EffectRenderer}. */ @@ -1443,7 +1466,7 @@ const CreateRenderTargetTexture = ( renderTarget.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE; renderTarget.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE; renderTarget.anisotropicFilteringLevel = 1; - //renderTarget.skipInitialClear = true; + renderTarget.skipInitialClear = true; return renderTarget; };