Vixen
dd8b0a81
csharp
public record class ParallaxOcclusionFeature

Parallax occlusion: a height map read as depth, and the coordinate moved to where the eye really sees the surface.

Read the guide page for this →

Remarks

⚠ The only feature in the library that writes the coordinate rather than reading it, which is why Coordinate exists and why this declares it. Listed behind a feature that samples, it displaces the coordinate that feature has already read — half a parallaxed surface, on every device, with nothing reported — so MaterialCompiler refuses the material rather than reordering it. See #1065.

⚠ Not the same map as HeightMap, and the names are deliberately different for it. That one is a four-channel per-layer bundle whose channel i is layer i's height; this samples one material's single channel, which is what MaterialMapTarget.Height bakes. Two textures, one English word — and giving them one parameter name would fill both indices from one texture, which shades and does not fail.

The budget is steps, never time. MinSteps is the walk head-on and MaxSteps is the walk edge-on, where the ray crosses the most surface per unit of depth. A wall-clock budget would be a different picture on every machine, which is a property this repository has already paid for in flakes.

Same conditions as every other sampling feature: a name rather than a handle, a device with HasBindless, and a host that paired the name through MaterialRenderFeature.TextureIndices. Without the pairing the index stays zero, the march reads the fallback checker's red channel as a height field, and the surface swims.

⚠ It is the flat-surface case and says so. A displaced coordinate that leaves 0..1 samples the map's wrap rather than showing the surface's edge fall away; fixing that needs a discard, and IMaterialSurface.Compute contributes to a struct while the pass owns coverage. Walls, floors and roads are what this is for.

⚠ "The wrap" is two artefacts and only one of them is about the silhouette. At a genuine silhouette — a cylinder's edge — the surface should fall away and instead more surface arrives, which is the paragraph above and is not fixable from here. The other is at the boundary of an unwrap, where the wrap is the far side of the same island landing in the seam. ⚠ That second one does not exist on a material whose map tiles: there the neighbouring tile really is what is next to this one. Which is why a box-projected wall — Samples/13-ThirdPersonShooter's, in metres of world — carries this feature with no seam, and a hero prop on a single 0..1 unwrap would not. Neither half is diagnosable from the material, which knows nothing about the mesh it is put on; see #1104.

⚠ And the silhouette is decided rather than owed, because a discard in the shading pass would not produce one. Coverage for this surface is settled in more passes than the one that shades it: a depth prepass and every shadow caster rasterise it too, and DepthOnly and ShadowCaster deliberately compose no material chain — ComposeFromMaterial is false for both, because handing them a material's features splits their variant cache once per material for shaders that compile to the same bytes. So a forward pass that cut the silhouette away would leave the prepass's depth written across the hole and the shadow uncut: a notch that occludes what is behind it and still shades nothing. Fixing it properly means making those two passes material-composed and marching the height field two more times per frame per light, in the two passes whose whole purpose is to be cheap. That is the cost, and it buys a case no shipped material is in — the artefact needs a genuine silhouette and a single 0..1 island, and this feature's carrier is a box-projected wall.

Fields and properties (7)

  • public const int StepCeiling

    The most steps the march is allowed, and the fewest it is worth.

  • public string HeightMap

    What the material calls the single-channel height map it wants marched.

  • public float HeightScale

    How deep the field's floor is, in the surface's own UV units.

  • public int MinSteps

    How many steps the march takes with the eye straight on.

  • public int MaxSteps

    And with the eye edge-on, where a coarse walk steps over a ridge.

  • public string ShaderName

    The Raven shader implementing this feature, from Raven/Library/Material.

  • public MaterialFeatureStage Stage

Methods (2)

  • public static string HeightIndexParameter(string path)

    What the shader calls the slot, under a composition path.

  • public void Compile(MaterialCompilationContext context)

    Writes this feature's parameters, and fills any slots of its own.

Used by (14)

  • FrameDocumentTestsThirdPersonShooter.Frame.Tests
  • MaterialCompilerTestsVixen.Rendering.Tests
  • ParallaxMaterialImageTestsVixen.Graphics.Golden.Tests
  • TexturedMaterialTestsVixen.Rendering.Tests
  • TypeRegistrationVixen.Rendering
  • Vixen_Rendering_Materials_ParallaxOcclusionFeatureSerializerVixen.Rendering
  • WorldRendererVixen.Engine.Renderer
  • MaterialBakeVixen.Editor.Assets
  • MaterialBakeAssetTestsVixen.Editor.Assets.Tests
  • MaterialBakeParallaxVixen.Editor.Assets
  • MaterialBakeTestsVixen.Editor.Assets.Tests
  • ParallaxBakeDeviceTestsVixen.Editor.Texturing.Tests
  • ProjectMaterialBakerVixen.Editor.Assets
  • TextureCommandTestsVixen.Cli.Tests