Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commitdd348ac6c3

README.md

PBR Parallax Occlusion

Surface shader that extends the engine's Cook-Torrance PBR pipeline with Parallax Occlusion Mapping. Per fragment it ray-marches a height texture in tangent space, discards pixels whose intersection escapes the [0,1] UV tile, softly fades a horizon margin so the discard isn't a hard step, and runs a second short ray-march toward the directional light for self-shadowing. The rest of the fragment shader is the standard PBR you get from @builtin::shaders.standard — directional + point lights + their shadows + procedural-sky IBL approximation — so a material using this shader still receives full scene lighting.

Domain

surface — bind to a .material.

Files

  • shader.wgsl — vertex + fragment shader. Naga-validated.
  • README.md — this file.

Texture slots

Standard PBR slots plus a sixth height_texture:

@group(1) bindingSlot nameNotes
1/2base_color_texturealbedo
3/4normal_texturetangent-space normals
5/6roughness_metallic_textureG = roughness, B = metallic (glTF)
7/8emissive_textureoptional emissive
9/10occlusion_textureoptional AO
11/12height_textureR = depth into surface (0 = at face, 1 = deep)

The engine reflects @group(1) bindings via naga and builds the bind-group layout per shader, so adding the sixth slot needs no Rust changes.

Parameters

The standard StandardMaterial uniform fields apply unchanged; the two fields that drive POM are:

  • parallax_depth_scale: f32 — max UV offset, in UV-space units. Useful range ~0.05–0.15. POM is gated on this being > 0 — set it to 0 and the shader degrades to plain textured PBR. It is also the width of the band the tile clip trims inward from the border of the [0,1] tile, since the march never offsets the UV further.
  • max_parallax_layer_count: f32 — ray-march iteration cap. 16 reads as stair-stepped at oblique angles; 48–64 is the smooth-quality band; 128 is the cost ceiling.

Notes

  • Heightmap convention: black = at surface, white = deep. If you bring in a heightmap authored the other way (white = high), invert it in your import step or you'll get inside-out parallax.
  • The vertex shader is the engine-standard one; the parallax effect is entirely in the fragment shader and uses no extra vertex attributes.
  • The march runs in the forward fragment entry point, so a material using this shader under a deferred camera renders as plain textured PBR.
  • For curved meshes, tangent-space POM produces mild distortion at high curvature. For roughly-planar surfaces (walls, floors, signs) it looks correct.