// 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. // SPHERE objects use ray-sphere impostor (correct silhouette + normal + depth). #include "common_uniforms" #include "math/normal" #include "ray_sphere" @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, } @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: use model matrix (correct for uniform scale + rotation). let world_normal = normalize((obj.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 @builtin(frag_depth) depth: f32, // corrected depth (sphere impostor) } @fragment fn fs_main(in: VertexOutput) -> GBufOutput { let obj = object_data.objects[in.instance_index]; let obj_type = u32(obj.params.x); let mat_id = f32(in.instance_index) / 255.0; var world_normal = normalize(in.world_normal); var frag_depth = in.position.z; // default: hardware depth // Sphere impostor: ray-sphere intersection for correct silhouette and normal. if (obj_type == 1u) { let sphere_center = obj.model[3].xyz; let sphere_radius = length(obj.model[0].xyz); // uniform scale in col0 let cam_pos = globals.camera_pos_time.xyz; let rd = normalize(in.world_pos - cam_pos); let isect = ray_sphere_intersection(cam_pos, rd, sphere_center, sphere_radius); if (!isect.hit) { discard; } let hit = cam_pos + rd * isect.t; world_normal = normalize(hit - sphere_center); // Reproject hit point to get correct clip-space depth. let clip_hit = globals.view_proj * vec4f(hit, 1.0); frag_depth = clip_hit.z / clip_hit.w; } let oct = oct_encode_unorm(world_normal); var out: GBufOutput; out.albedo = vec4f(in.color.rgb, 1.0); out.normal_mat = vec4f(oct.x, oct.y, mat_id, 0.0); out.depth = frag_depth; return out; }