Vixen
c7401864
csharp
public sealed class VolumetricFogRenderer

Froxel volumetric fog: three compute dispatches that fill a volume, which !Fog reads.

Read the guide page for this →

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 Media

    The name the medium volume is published under.

  • public string Scattered

    The name the lit volume is published under.

  • public string Volume

    The name the marched volume is published under. !Fog reads this one.

  • public RenderView? View

    The view whose camera the froxels are laid out in front of.

  • public Int3 Resolution

    How many froxels across, down and deep.

  • public float Near

    Where the grid's first slice begins, in metres of view depth.

  • public float Far

    Where its last slice ends. Beyond this !Fog's analytic falloff carries on.

  • public float Density

    How much light a metre of the medium takes out of a ray, at the reference altitude.

  • public Vector3 ScatteringAlbedo

    What fraction of that is scattered rather than absorbed, per channel.

  • public bool HeightFalloff

    Whether density thins with altitude.

  • public float Height

    The altitude the authored density holds at.

  • public float HeightFalloffRate

    How fast it thins above that, per world unit.

  • public Vector3 SunDirection

    Which way the light travels.

  • public Vector3 SunColour

    What it carries.

  • public float PhaseG

    Henyey–Greenstein anisotropy. Air's forward peak is what makes a beam a beam.

  • public Vector3 AmbientColour

    What arrives from the whole sky.

  • public string ShadowAtlas

    The cascade atlas the frame's shadow node rendered.

  • public string ShadowStandIn

    The 1×1 texture bound into the shadow slot on a frame that has no atlas.

  • public string LightStandIn

    The name of the buffer bound into both light slots on a frame that culled nothing.

  • public string ScenePass

    Where the shading pass published its cascades — ShadowMapRenderer.ShaderName.

  • public SceneConstants? Frame

    The frame's constants, which is where the cascades and the biases were published.

  • public bool Shadows

    Whether the froxels may be shadowed at all — the tier's ceiling.

  • public bool Shadowed

    Whether the last build found everything a shadowed march needs.

  • public bool Clustered

    Whether the last build found a light list and cluster lists to index it by.

  • public float Feedback

    How much of the reprojected history survives into this frame's scattering volume.

  • public bool Reprojects

    Whether the last build alternated a pair of volumes and reprojected between them.

  • public bool HasHistory

    Whether there is a previous frame's volume worth blending with.

  • public TextureHandle ScatteringTarget

    The volume this frame's scattering is written into.

  • public TextureHandle ScatteringHistory

    The one it reprojects out of.

  • public IGraphicsDevice? Device

    The device this node's own resources are created on. Falls back to the frame's.

  • public DescriptorAllocator? Allocator

    Where descriptor sets come from.

  • public SamplerCache? Samplers

    Where samplers come from.

  • public ComputePipelineCache? Pipelines

    Where compute pipelines come from.

  • public ShaderComposition Composition

    What fills the library's compose slots. See Composition.

  • public IReadOnlyList<ComputeRenderer> Steps

    The three dispatches, in the order they run.

  • public Int3 Dispatched

    The 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