// G-buffer rasterization shader for CNN v3 // Pass 1: Proxy geometry → MRT (albedo rgba16float, normal_mat rgba16float, depth32) // Uses GlobalUniforms, ObjectData, ObjectsBuffer from common_uniforms. #include "common_uniforms" @group(0) @binding(0) var globals: GlobalUniforms; @group(0) @binding(1) var object_data: ObjectsBuffer; struct VertexOutput { @builtin(position) position: vec4f, @location(0) world_pos: vec3f, @location(1) world_normal: vec3f, @location(2) color: vec4f, @location(3) @interpolate(flat) instance_index: u32, } // Octahedral encoding: maps unit normal to [-1,1]^2 fn oct_encode(n: vec3f) -> vec2f { let inv_l1 = 1.0 / (abs(n.x) + abs(n.y) + abs(n.z)); var p = n.xy * inv_l1; // Fold lower hemisphere if (n.z < 0.0) { let s = vec2f( select(-1.0, 1.0, p.x >= 0.0), select(-1.0, 1.0, p.y >= 0.0) ); p = (1.0 - abs(p.yx)) * s; } return p; // in [-1, 1] } @vertex fn vs_main( @builtin(vertex_index) vertex_index: u32, @builtin(instance_index) instance_index: u32 ) -> VertexOutput { // Proxy box vertices (same as renderer_3d.wgsl) var pos = array( vec3f(-1.0, -1.0, 1.0), vec3f( 1.0, -1.0, 1.0), vec3f( 1.0, 1.0, 1.0), vec3f(-1.0, -1.0, 1.0), vec3f( 1.0, 1.0, 1.0), vec3f(-1.0, 1.0, 1.0), vec3f(-1.0, -1.0, -1.0), vec3f(-1.0, 1.0, -1.0), vec3f( 1.0, 1.0, -1.0), vec3f(-1.0, -1.0, -1.0), vec3f( 1.0, 1.0, -1.0), vec3f( 1.0, -1.0, -1.0), vec3f(-1.0, 1.0, -1.0), vec3f(-1.0, 1.0, 1.0), vec3f( 1.0, 1.0, 1.0), vec3f(-1.0, 1.0, -1.0), vec3f( 1.0, 1.0, 1.0), vec3f( 1.0, 1.0, -1.0), vec3f(-1.0, -1.0, -1.0), vec3f( 1.0, -1.0, -1.0), vec3f( 1.0, -1.0, 1.0), vec3f(-1.0, -1.0, -1.0), vec3f( 1.0, -1.0, 1.0), vec3f(-1.0, -1.0, 1.0), vec3f( 1.0, -1.0, -1.0), vec3f( 1.0, 1.0, -1.0), vec3f( 1.0, 1.0, 1.0), vec3f( 1.0, -1.0, -1.0), vec3f( 1.0, 1.0, 1.0), vec3f( 1.0, -1.0, 1.0), vec3f(-1.0, -1.0, -1.0), vec3f(-1.0, -1.0, 1.0), vec3f(-1.0, 1.0, 1.0), vec3f(-1.0, -1.0, -1.0), vec3f(-1.0, 1.0, 1.0), vec3f(-1.0, 1.0, -1.0) ); // Proxy face normals (one per 2 triangles = 6 faces × 6 verts = 36) var nrm = array( vec3f(0,0,1), vec3f(0,0,1), vec3f(0,0,1), vec3f(0,0,1), vec3f(0,0,1), vec3f(0,0,1), vec3f(0,0,-1), vec3f(0,0,-1), vec3f(0,0,-1), vec3f(0,0,-1), vec3f(0,0,-1), vec3f(0,0,-1), vec3f(0,1,0), vec3f(0,1,0), vec3f(0,1,0), vec3f(0,1,0), vec3f(0,1,0), vec3f(0,1,0), vec3f(0,-1,0), vec3f(0,-1,0), vec3f(0,-1,0), vec3f(0,-1,0), vec3f(0,-1,0), vec3f(0,-1,0), vec3f(1,0,0), vec3f(1,0,0), vec3f(1,0,0), vec3f(1,0,0), vec3f(1,0,0), vec3f(1,0,0), vec3f(-1,0,0), vec3f(-1,0,0), vec3f(-1,0,0), vec3f(-1,0,0), vec3f(-1,0,0), vec3f(-1,0,0) ); let obj = object_data.objects[instance_index]; let p = pos[vertex_index]; let n = nrm[vertex_index]; let world_pos = obj.model * vec4f(p, 1.0); let clip_pos = globals.view_proj * world_pos; // Transform normal by inverse-transpose (upper-left 3×3 of inv_model^T) let world_normal = normalize((obj.inv_model * vec4f(n, 0.0)).xyz); var out: VertexOutput; out.position = clip_pos; out.world_pos = world_pos.xyz; out.world_normal = world_normal; out.color = obj.color; out.instance_index = instance_index; return out; } struct GBufOutput { @location(0) albedo: vec4f, // rgba16float: material color @location(1) normal_mat: vec4f, // rgba16float: oct-normal XY in RG, mat_id/255 in B } @fragment fn fs_main(in: VertexOutput) -> GBufOutput { let obj = object_data.objects[in.instance_index]; let mat_id = f32(in.instance_index) / 255.0; // Oct-encode world normal, remap [-1,1] → [0,1] for storage let oct = oct_encode(normalize(in.world_normal)) * 0.5 + vec2f(0.5); var out: GBufOutput; out.albedo = vec4f(in.color.rgb, 1.0); out.normal_mat = vec4f(oct.x, oct.y, mat_id, 0.0); return out; }