diff --git a/crates/voltex_renderer/src/deferred_gbuffer.wgsl b/crates/voltex_renderer/src/deferred_gbuffer.wgsl new file mode 100644 index 0000000..c4397da --- /dev/null +++ b/crates/voltex_renderer/src/deferred_gbuffer.wgsl @@ -0,0 +1,94 @@ +// G-Buffer pass shader for deferred rendering. +// Writes geometry data to multiple render targets. + +struct CameraUniform { + view_proj: mat4x4, + model: mat4x4, + camera_pos: vec3, +}; + +struct MaterialUniform { + base_color: vec4, + metallic: f32, + roughness: f32, + ao: f32, +}; + +@group(0) @binding(0) var camera: CameraUniform; + +@group(1) @binding(0) var t_albedo: texture_2d; +@group(1) @binding(1) var s_albedo: sampler; +@group(1) @binding(2) var t_normal: texture_2d; +@group(1) @binding(3) var s_normal: sampler; + +@group(2) @binding(0) var material: MaterialUniform; + +struct VertexInput { + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) tangent: vec4, +}; + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) world_pos: vec3, + @location(1) world_normal: vec3, + @location(2) uv: vec2, + @location(3) world_tangent: vec3, + @location(4) world_bitangent: vec3, +}; + +@vertex +fn vs_main(v: VertexInput) -> VertexOutput { + var out: VertexOutput; + + let world_pos4 = camera.model * vec4(v.position, 1.0); + out.world_pos = world_pos4.xyz; + out.clip_position = camera.view_proj * world_pos4; + out.uv = v.uv; + + let N = normalize((camera.model * vec4(v.normal, 0.0)).xyz); + let T = normalize((camera.model * vec4(v.tangent.xyz, 0.0)).xyz); + let B = cross(N, T) * v.tangent.w; + + out.world_normal = N; + out.world_tangent = T; + out.world_bitangent = B; + + return out; +} + +struct GBufferOutput { + @location(0) position: vec4, + @location(1) normal: vec4, + @location(2) albedo: vec4, + @location(3) material_data: vec4, +}; + +@fragment +fn fs_main(in: VertexOutput) -> GBufferOutput { + // Sample albedo texture + let tex_color = textureSample(t_albedo, s_albedo, in.uv); + let albedo = material.base_color.rgb * tex_color.rgb; + + // Normal mapping via TBN matrix + let T = normalize(in.world_tangent); + let B = normalize(in.world_bitangent); + let N_geom = normalize(in.world_normal); + + let normal_sample = textureSample(t_normal, s_normal, in.uv).rgb; + let tangent_normal = normal_sample * 2.0 - 1.0; + + // TBN: tangent space → world space + let TBN = mat3x3(T, B, N_geom); + let N = normalize(TBN * tangent_normal); + + var out: GBufferOutput; + out.position = vec4(in.world_pos, 1.0); + out.normal = vec4(N * 0.5 + 0.5, 1.0); + out.albedo = vec4(albedo, material.base_color.a * tex_color.a); + out.material_data = vec4(material.metallic, material.roughness, material.ao, 1.0); + + return out; +}