gbuffer_material.shaderModule
The G-buffer's surface description, and the one encoding of it.
gbuffer_material
The G-buffer's surface description, and the one encoding of it.
@scene.shaded carries what a surface sent — the light the geometry pass shaded
it to, scene-referred and unbounded above 1. @scene.material carries what the
surface is: the base colour it reflects, how metallic it is, and how rough. A
screen-space pass that multiplies incoming light by a reflectance — a bounce
multiplier, a Fresnel tint, an ambient floor — reads the second.
The channel is Rgba8Uint. The G-buffer's five colour attachments spend the
whole 32-byte maxColorAttachmentBytesPerSample a conformant device guarantees,
and this attachment's four bytes come out of alignment padding the set
otherwise burns, so 32 bits is the entire budget:
| Lane | Content |
|---|---|
.r | base colour, RGB565 low byte |
.g | base colour, RGB565 high byte |
.b | metallic |
.a | perceptual roughness |
Base colour lands at 5/6/5 — steps of about 3% per channel. Metallic and roughness keep a full byte each.
The geometry pass packs through zero_gbuffer_pack_material; every reader
unpacks through this module, so the layout is stated once.
Pure math, no bindings.
#include "@builtin::shaderModules.gbuffer_material"
// bindings.yaml: - { name: scene_material, kind: texture2d, sample: uint }
let m = zero_gbuffer_material(scene_material, coord);
let bounce = incoming * m.base_color;
One value at a time:
let base = zero_gbuffer_base_color(scene_material, coord);
let metallic = zero_gbuffer_metallic(scene_material, coord);
let roughness = zero_gbuffer_roughness(scene_material, coord);
A .computeShader reading the channel declares its slot kind: texture2d with
sample: uint, because an Rgba8Uint texture binds as texture_2d<u32>. The
engine refuses the pass when the declared sample type and the bound texture's
format disagree, and names both.
Signatures
struct ZeroGbufferMaterial {
base_color: vec3<f32>,
metallic: f32,
perceptual_roughness: f32,
}
fn zero_gbuffer_unpack_material(texel: vec4<u32>) -> ZeroGbufferMaterial
fn zero_gbuffer_material(t: texture_2d<u32>, coord: vec2<i32>) -> ZeroGbufferMaterial
fn zero_gbuffer_base_color(t: texture_2d<u32>, coord: vec2<i32>) -> vec3<f32>
fn zero_gbuffer_metallic(t: texture_2d<u32>, coord: vec2<i32>) -> f32
fn zero_gbuffer_roughness(t: texture_2d<u32>, coord: vec2<i32>) -> f32
texel is one textureLoad result off @scene.material — the four raw
u32 lanes before this module gives them meaning. t is the bound
@scene.material slot itself (texture_2d<u32>, declared sample: uint);
coord is the pixel to read, an integer texel coordinate (vec2<i32>) — the
same textureLoad-shaped argument every accessor and zero_gbuffer_material
take. The three single-value accessors are zero_gbuffer_material narrowed to
one field, for a caller that wants only one of the three.
The channel is a G-buffer channel, so the deferred G-buffer fragment entry is what writes it: an opaque draw on the deferred path. A pixel no geometry wrote reads a black surface at metallic 0 and mid roughness.
Scoped to this part · feeds back into the world's score.