{ name: "deferred_indirect", configurations: [ { name: "DEFAULT" } ], uniforms: [ { name: "u_albedo", type: "sampler2D", value: 0 }, { name: "u_normal", type: "sampler2D", value: 1 }, { name: "u_emission", type: "sampler2D", value: 2 }, { name: "u_depth", type: "sampler2D", value: 3 }, { name: "u_irradiance", type: "samplerCM", value: 4 }, { name: "u_prefilter", type: "samplerCM", value: 5 }, { name: "u_scale_bias", type: "sampler2D", value: 6 }, { name: "u_inverse_projection", type: "f32x4x4" }, { name: "u_camera_position", type: "f32x3" }, { name: "u_resolution", type: "f32x2" } ], shaders: [ { type: "vertex", imports: [ "fullscreen_triangle" ], outputs: [ { name: "vs_coordinate", type: "f32x2" } ], source: " void main() { f32x4 triangle = fullscreen_triangle(); rx_position = f32x4(triangle.xy, 0.0, 1.0); vs_coordinate = triangle.zw; } " },{ type: "fragment", inputs: [ { name: "vs_coordinate", type: "f32x2" } ], outputs: [ { name: "fs_color", type: "f32x4" } ], imports: [ "position_from_depth", "normal_decode", "bayer" ], source: " f32x3 approximate_specular_ibl(f32x3 specular_color, f32 roughness, f32x3 n, f32x3 v) { f32 n_dot_v = max(0.0, dot(n, v)); f32x3 r = reflect(-v, n); f32x3 prefiltered_color = rx_textureCMLod(u_prefilter, r, roughness * 5.0).rgb; f32x2 brdf = rx_texture2D(u_scale_bias, f32x2(roughness, n_dot_v)).rg; return prefiltered_color * (specular_color * brdf.x + brdf.y); } void main() { f32x4 sample_albedo = rx_texture2D(u_albedo, vs_coordinate); f32x4 sample_normal = rx_texture2D(u_normal, vs_coordinate); f32x4 sample_emission = rx_texture2D(u_emission, vs_coordinate); f32 sample_depth = rx_texture2D(u_depth, vs_coordinate).r; f32x3 albedo = sample_albedo.rgb; f32x3 normal = normal_decode(sample_normal.rg); f32 roughness = sample_normal.b; f32 metalness = sample_normal.a; f32x3 position = position_from_depth( vs_coordinate, u_inverse_projection, sample_depth); f32x3 v = normalize(u_camera_position - position); f32x3 base_color = sample_albedo.rgb; f32x3 diffuse_color = base_color * (1.0 - metalness); f32x3 specular_color = mix(f32x3(0.04), base_color, metalness); f32x3 irradiance = rx_textureCM(u_irradiance, normal).rgb; f32x3 indirect_diffuse = diffuse_color * irradiance + sample_emission.rgb; f32x3 indirect_specular = approximate_specular_ibl( specular_color, roughness, normal, v); // When approximating indirect specular the result is severely // undersampled due to the low-resolution and low-bitdepth prefilter'd // environment map. This results in both ringing and banding artifacts, // apply an ordered dither to the result of specular to spread this // error out across several pixels rather than being concentrated. indirect_specular += bayer_16x16(vs_coordinate * u_resolution) / 255.0; fs_color = f32x4(sample_albedo.a * (indirect_diffuse + indirect_specular), 1.0); } " } ] }