public sealed class VolumetricFogRendererFroxel volumetric fog: three compute dispatches that fill a volume, which !Fog reads.
Remarks
Fog that a shadow can fall through. The analytic falloff FogRenderer applies is a function of distance and altitude and nothing else, so it cannot know that a wall is between this pixel and the sun — which is why a valley lit by an analytic fog has no beams in it. Marching a volume is what buys that, and the volume is what the marching needs somewhere to live in.
Where it runs, and why there. The three dispatches go between the shadow passes and the main pass: they need shadows and lights, not scene colour, and declaring that is what puts the barriers in. The composite is a permutation on !Fog in the "Air" seat, which is after the temporal accumulation — the documented TAA-before-fog invariant, and it is safe here for a reason that is not obvious: the volume does its own temporal work in its own space, so it must not be inside a screen-space accumulator that would reproject it as though it were a surface.
⚠ That last sentence was an assertion before it was a fact. The seat was argued for on the grounds of a self-reprojecting volume while the volume answered every frame from scratch — which made the seat convenient rather than earned, and left every shadow edge crawling at the sampling rate of a 160 × 90 × 64 grid. Reprojects is what closed it: a pair of volumes this node owns and alternates, a sample point offset within each froxel per frame, and the previous frame's answer found through ViewConstants.PreviousViewProjection in the grid's coordinates — tile from xy/w, slice from the grid's own logarithmic distribution applied to w. A screen-space reprojection would find where a froxel's pixel was and know nothing about which slice it was in, which is the axis a shaft's edge actually lives on.
⚠ The volumes are declared only if the document did not. A document that names FogMedia and FogScattered re-points them — at a different resolution, or at an import a host owns — and this stands aside, which is GraphicsCompositor's own rule about a declaration an import already covers. The extent then comes back out of the frame rather than from this node's own copy of the numbers, so a dispatch cannot cover part of a volume the document sized differently.
Its far plane is its own and not the camera's, which is the number to reach for first when tuning. Sixty-four metres of grid at sixty-four slices puts the nearest slice about a centimetre deep and the furthest about four metres — spending the resolution where a beam is actually visible. A grid stretched over a kilometre spends almost all of it on distance the analytic fallback describes perfectly well.
Fields and properties (36)
public string MediaThe name the medium volume is published under.
public string ScatteredThe name the lit volume is published under.
public string VolumeThe name the marched volume is published under. !Fog reads this one.
public RenderView? ViewThe view whose camera the froxels are laid out in front of.
public Int3 ResolutionHow many froxels across, down and deep.
public float NearWhere the grid's first slice begins, in metres of view depth.
public float FarWhere its last slice ends. Beyond this !Fog's analytic falloff carries on.
public float DensityHow much light a metre of the medium takes out of a ray, at the reference altitude.
public Vector3 ScatteringAlbedoWhat fraction of that is scattered rather than absorbed, per channel.
public bool HeightFalloffWhether density thins with altitude.
public float HeightThe altitude the authored density holds at.
public float HeightFalloffRateHow fast it thins above that, per world unit.
public Vector3 SunDirectionWhich way the light travels.
public Vector3 SunColourWhat it carries.
public float PhaseGHenyey–Greenstein anisotropy. Air's forward peak is what makes a beam a beam.
public Vector3 AmbientColourWhat arrives from the whole sky.
public string ShadowAtlasThe cascade atlas the frame's shadow node rendered.
public string ShadowStandInThe 1×1 texture bound into the shadow slot on a frame that has no atlas.
public string LightStandInThe name of the buffer bound into both light slots on a frame that culled nothing.
public string ScenePassWhere the shading pass published its cascades — ShadowMapRenderer.ShaderName.
public SceneConstants? FrameThe frame's constants, which is where the cascades and the biases were published.
public bool ShadowsWhether the froxels may be shadowed at all — the tier's ceiling.
public bool ShadowedWhether the last build found everything a shadowed march needs.
public bool ClusteredWhether the last build found a light list and cluster lists to index it by.
public float FeedbackHow much of the reprojected history survives into this frame's scattering volume.
public bool ReprojectsWhether the last build alternated a pair of volumes and reprojected between them.
public bool HasHistoryWhether there is a previous frame's volume worth blending with.
public TextureHandle ScatteringTargetThe volume this frame's scattering is written into.
public TextureHandle ScatteringHistoryThe one it reprojects out of.
public IGraphicsDevice? DeviceThe device this node's own resources are created on. Falls back to the frame's.
public DescriptorAllocator? AllocatorWhere descriptor sets come from.
public SamplerCache? SamplersWhere samplers come from.
public ComputePipelineCache? PipelinesWhere compute pipelines come from.
public ShaderComposition CompositionWhat fills the library's compose slots. See Composition.
public IReadOnlyList<ComputeRenderer> StepsThe three dispatches, in the order they run.
public Int3 DispatchedThe volume's shape as the last build actually dispatched it.
Methods (4)
public void Apply(in PostProcessOverlay overlay)protected override void Build(GraphicsCompositor compositor, CompositorFrame frame)Declares this node's render-graph passes.
public static Vector3 Jitter(int frameIndex)The subpixel offset to sample a froxel at, in froxels, for a frame index.
public void Dispose()Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
Used by (3)
- HarnessVixen.Rendering.PostFx.Tests
- PostEffectFactoryVixen.Rendering.PostFx
- VolumetricFogIntegrationTestsVixen.Rendering.PostFx.Tests