UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

216 lines (215 loc) 8.59 kB
/** * 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 {};