playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
216 lines (215 loc) • 8.59 kB
TypeScript
/**
* Frame pass implementation of volumetric fog lit by a directional light. A reduced resolution
* raymarch pass accumulates in-scattered light and transmittance along each view ray, sampling
* the light's cascaded shadow map to form visible light shafts, and a combine pass blends the
* result over the scene render target using a depth-aware upsample.
*
* Algorithm details:
*
* The raymarch pass renders a full-screen quad into an RGBA16F texture sized as a fraction
* (scale) of the scene render target, storing the in-scattered light in rgb and the
* transmittance in alpha. For each pixel, a world space view ray is reconstructed from the
* camera's inverse view matrix and projection scale, and marched from the camera to the scene
* surface - the distance is derived from the linear depth prepass texture and clamped to
* maxDistance. The march uses a fixed number of steps, with the sample positions offset along
* the ray by per-pixel interleaved gradient noise to hide banding. When TAA is enabled, the
* noise pattern additionally cycles each frame using a golden-ratio sequence, and TAA
* accumulates the dithered results into a smooth solution over time.
*
* The fog media is modeled as exponential height fog: the density is constant below heightBase
* and decays exponentially above it, controlled by heightFalloff. At each step, the light
* visibility is evaluated with a single tap of the directional light's cascaded shadow map -
* the cascade is selected from the sample's view depth, and the tap uses hardware depth
* comparison for depth-format shadow maps (PCF) or a manual comparison for color-format maps
* storing depth (PCSS / VSM). The in-scattered radiance combines the light color scaled by the
* Henyey-Greenstein phase function (evaluated once per ray, as the light direction is constant)
* with an ambient term that keeps fog in shadowed areas visible. The scattering is accumulated
* front-to-back weighted by the current transmittance, and the transmittance is attenuated per
* step using Beer-Lambert extinction, with an early out once it becomes negligible.
*
* The combine pass runs at full resolution and blends the fog texture over the scene render
* target as scene * transmittance + inscatter, using alpha blending so no extra copy of the
* scene is needed. To upsample the low resolution fog without leaking across geometry edges,
* it takes the 4 nearest fog texels and weights them by their bilinear factors multiplied by
* the depth similarity between the full resolution pixel and each low resolution sample. The
* pass executes before TAA and bloom in the frame, so the fog participates in temporal
* anti-aliasing and bright shafts contribute to the bloom.
*
* @category Graphics
* @ignore
*/
export class FramePassVolumetricFog extends FramePass {
/**
* @param {GraphicsDevice} device - The graphics device.
* @param {CameraComponent} cameraComponent - The camera component.
* @param {Texture} sceneTexture - The scene color texture, used to size the fog texture.
* @param {RenderTarget} sceneRenderTarget - The scene render target the fog is blended into.
*/
constructor(device: GraphicsDevice, cameraComponent: CameraComponent, sceneTexture: Texture, sceneRenderTarget: RenderTarget);
/**
* The directional light providing the scattered light, or null for unlit (ambient only) fog.
*
* @type {Light|null}
*/
light: Light | null;
/**
* The fog albedo.
*
* @type {Color}
*/
tint: Color;
/**
* The fog density at the base height.
*/
density: number;
/**
* The world space height at which the density starts to falloff. Below it the density is
* constant.
*/
heightBase: number;
/**
* The exponential falloff of the density with height.
*/
heightFalloff: number;
/**
* The anisotropy of the Henyey-Greenstein phase function, 0..1 range, larger values scatter
* more light forward, making the fog brighter when looking towards the light.
*/
anisotropy: number;
/**
* The intensity of the light scattering.
*/
intensity: number;
/**
* The color of the ambient in-scattered light, allowing the fog in shadowed areas to remain
* visible.
*
* @type {Color}
*/
ambientColor: Color;
/**
* The intensity of the ambient in-scattered light.
*/
ambientIntensity: number;
/**
* The maximum world space distance the fog is raymarched to.
*/
maxDistance: number;
/**
* The number of raymarching steps.
*/
steps: number;
/**
* True when the noise pattern changes each frame, to be resolved by TAA.
*/
temporalDither: boolean;
/** @type {number} */
_scale: number;
/** @type {number} */
_frameIndex: number;
cameraComponent: CameraComponent;
fogTexture: Texture;
fogRenderTarget: RenderTarget;
fogPass: RenderPassVolumetricFog;
combinePass: RenderPassVolumetricFogCombine;
/**
* Sets the resolution scale of the fog texture, relative to the scene render target.
*
* @type {number}
*/
set scale(value: number);
/**
* Gets the resolution scale of the fog texture.
*
* @type {number}
*/
get scale(): number;
}
import { FramePass } from '../../platform/graphics/frame-pass.js';
import type { Light } from '../../scene/light.js';
import { Color } from '../../core/math/color.js';
import type { CameraComponent } from '../../framework/components/camera/component.js';
import { Texture } from '../../platform/graphics/texture.js';
import { RenderTarget } from '../../platform/graphics/render-target.js';
/**
* Render pass implementing the volumetric fog raymarch. Renders in-scattered light (rgb) and
* transmittance (a) into a reduced resolution texture, sampling the directional light's cascaded
* shadow map along the ray.
*
* @ignore
*/
declare class RenderPassVolumetricFog extends RenderPassShaderQuad {
constructor(device: any, cameraComponent: any);
/** @type {Light|null} */
light: Light | null;
shadowsEnabled: boolean;
/**
* The shadow data of the light for the fog camera, when the shadow map is available.
*
* @type {LightRenderData|null}
*/
lightRenderData: LightRenderData | null;
tint: Color;
density: number;
heightBase: number;
heightFalloff: number;
anisotropy: number;
intensity: number;
ambientColor: Color;
ambientIntensity: number;
maxDistance: number;
steps: number;
noiseOffset: number;
exposure: number;
/** @type {string|null} */
_variantKey: string | null;
cameraComponent: any;
cameraPosId: any;
cameraFwdId: any;
invViewId: any;
projScaleId: any;
tintId: any;
lightColorId: any;
lightDirId: any;
ambientId: any;
fogParamsId: any;
scatterParamsId: any;
shadowMapId: any;
shadowMatrixPaletteId: any;
shadowCascadeDistancesId: any;
shadowParamsId: any;
_cameraPos: Float32Array<ArrayBuffer>;
_cameraFwd: Float32Array<ArrayBuffer>;
_projScale: Float32Array<ArrayBuffer>;
_tint: Float32Array<ArrayBuffer>;
_lightColor: Float32Array<ArrayBuffer>;
_lightDir: Float32Array<ArrayBuffer>;
_ambient: Float32Array<ArrayBuffer>;
_fogParams: Float32Array<ArrayBuffer>;
_scatterParams: Float32Array<ArrayBuffer>;
_shadowParams: Float32Array<ArrayBuffer>;
/**
* Creates the shader matching the shadow sampling requirements, when those change.
*
* @param {boolean} shadows - True if the shadow map should be sampled.
* @param {boolean} pcf - True if the shadow map is a depth format texture using hardware
* comparison, false when it stores depth in a color texture (PCSS / VSM).
*/
updateShaderVariant(shadows: boolean, pcf: boolean): void;
}
/**
* Render pass which composites the volumetric fog texture over the scene render target, using a
* depth-aware upsample, blending as scene * transmittance + inscatter.
*
* @ignore
*/
declare class RenderPassVolumetricFogCombine extends RenderPassShaderQuad {
constructor(device: any, cameraComponent: any, fogTexture: any);
fogTexture: any;
fogTextureId: any;
fogTextureSizeId: any;
_fogTextureSize: Float32Array<ArrayBuffer>;
}
import type { GraphicsDevice } from '../../platform/graphics/graphics-device.js';
import { RenderPassShaderQuad } from '../../scene/graphics/render-pass-shader-quad.js';
export {};