diff --git a/packages/dev/addons/src/atmosphere/atmosphere.ts b/packages/dev/addons/src/atmosphere/atmosphere.ts index 519085f4e96..39dc9f83f7d 100644 --- a/packages/dev/addons/src/atmosphere/atmosphere.ts +++ b/packages/dev/addons/src/atmosphere/atmosphere.ts @@ -40,6 +40,10 @@ import "./Shaders/ShadersInclude/depthFunctions"; const MaterialPlugin = "atmo-pbr"; +const AerialPerspectiveLutLayers = 32; + +let UniqueId = 0; + /** * Renders a physically based atmosphere. * Use {@link IsSupported} to check if the atmosphere is supported before creating an instance. @@ -84,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; @@ -114,6 +119,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. */ @@ -340,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; @@ -637,8 +647,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 +661,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."); @@ -1233,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; } } @@ -1350,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); @@ -1363,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}. */ @@ -1422,13 +1449,15 @@ const CreateRenderTargetTexture = ( scene: Scene, options?: RenderTargetTextureOptions ): RenderTargetTexture => { + //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, generateStencilBuffer: false, gammaSpace: false, samplingMode: Constants.TEXTURE_BILINEAR_SAMPLINGMODE, - type: Constants.TEXTURETYPE_HALF_FLOAT, + type: textureType, format: Constants.TEXTUREFORMAT_RGBA, ...options, }; diff --git a/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts b/packages/dev/addons/src/atmosphere/diffuseSkyIrradianceLut.ts index a8ef89effa7..1c09b7104c0 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 = Constants.TEXTURETYPE_UNSIGNED_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({