vk: rt: fix incorrect basecolor brdf multiplication

PBR model used implies the following rules:
- for metals both diffuse and specular components should be tinted by
  material base color.
- for dielectrics, only diffuse should be tinted, specular should remain
  as is.

Partially fixes #666
This commit is contained in:
Ivan Avdeev 2023-12-11 11:48:44 -05:00
parent 20da50ca7b
commit c8123952a2
5 changed files with 31 additions and 29 deletions

View File

@ -158,8 +158,6 @@ void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specula
if (!getHit(pos, bounce_direction, payload))
return;
throughput *= payload.base_color_a.rgb;
// 4. Sample light sources
{
vec3 ldiffuse = vec3(0.);
@ -172,9 +170,11 @@ void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specula
hit_material.emissive = vec3(0.f);
hit_material.metalness = payload.material_rmxx.g;
hit_material.roughness = payload.material_rmxx.r;
computeLighting(hit_pos, hit_shading_normal, throughput, -bounce_direction, hit_material, ldiffuse, lspecular);
computeLighting(hit_pos, hit_shading_normal, -bounce_direction, hit_material, ldiffuse, lspecular);
vec3 background = payload.base_color_a.rgb * ldiffuse;
background += lspecular * mix(vec3(1.), payload.base_color_a.rgb, hit_material.metalness);
vec3 background = ldiffuse + lspecular;
vec3 emissive = vec3(0.);
traceSimpleBlending(pos, bounce_direction, payload.hit_t.w, emissive, background);
const vec3 final_color = emissive + background;

View File

@ -22,6 +22,7 @@ layout(set = 0, binding = 6, rgba16f) uniform readonly image2D emissive;
layout(set = 0, binding = 7, rgba32f) uniform readonly image2D position_t;
layout(set = 0, binding = 8, rgba16f) uniform readonly image2D normals_gs;
layout(set = 0, binding = 9, rgba8) uniform readonly image2D material_rmxx;
layout(set = 0, binding = 10, rgba32f) uniform readonly image2D geometry_prev_position;
layout(set = 0, binding = 11) uniform UBO { UniformBuffer ubo; } ubo;
@ -42,7 +43,6 @@ layout(set = 0, binding = 18) uniform sampler3D blue_noise_texture;
#endif
//layout(set = 0, binding = 19) uniform sampler2D textures[MAX_TEXTURES];
//layout(set = 0, binding = 18, rgba8) uniform readonly image2D material_rmxx;
const int INDIRECT_SCALE = 2;
@ -243,11 +243,9 @@ void main() {
return;
}
vec3 colour = vec3(0.);
vec3 diffuse = c.direct_diffuse + c.indirect_diffuse;
vec3 specular = c.direct_specular + c.indirect_specular;
{
vec3 diffuse = c.direct_diffuse + c.indirect_diffuse;
vec3 specular = c.direct_specular + c.indirect_specular;
//#define DISABLE_TEMPORAL_DENOISER
#ifndef DISABLE_TEMPORAL_DENOISER
// TODO: need to extract reprojecting from this shader because reprojected stuff need svgf denoising pass after it
@ -296,13 +294,18 @@ void main() {
imageStore(out_temporal_diffuse, pix, vec4(diffuse, depth));
imageStore(out_temporal_specular, pix, vec4(specular, 0./*unused*/));
#endif // ifndef DISABLE_TEMPORAL_DENOISER
}
vec3 colour = vec3(0.);
if (ubo.ubo.debug_display_only != DEBUG_DISPLAY_LIGHTING) {
const vec3 base_color = SRGBtoLINEAR(imageLoad(base_color_a, pix).rgb);
colour = diffuse * base_color;
colour += specular * mix(vec3(1.), base_color, imageLoad(material_rmxx, pix).g);
} else {
colour = diffuse + specular;
}
if (ubo.ubo.debug_display_only != DEBUG_DISPLAY_LIGHTING) {
const vec4 base_color_a = SRGBtoLINEAR(imageLoad(base_color_a, pix));
colour *= base_color_a.rgb;
}
colour += imageLoad(emissive, pix).rgb;
colour = LINEARtoSRGB(colour);

View File

@ -11,7 +11,7 @@ const float shadow_offset_fudge = .1;
#endif
#if LIGHT_POINT
void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 throughput, vec3 view_dir, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 view_dir, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
diffuse = specular = vec3(0.);
//diffuse = vec3(1.);//float(lights.m.num_point_lights) / 64.);
@ -24,7 +24,7 @@ void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 throughput, vec
for (uint i = 0; i < lights.m.num_point_lights; ++i) {
#endif
vec3 color = lights.m.point_lights[i].color_stopdot.rgb * throughput;
vec3 color = lights.m.point_lights[i].color_stopdot.rgb;
if (dot(color,color) < color_culling_threshold)
continue;
@ -114,7 +114,7 @@ void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 throughput, vec
}
#endif
void computeLighting(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
void computeLighting(vec3 P, vec3 N, vec3 view_dir, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
diffuse = specular = vec3(0.);
const ivec3 light_cell = ivec3(floor(P / LIGHT_GRID_CELL_SIZE)) - lights.m.grid_min_cell;
@ -122,7 +122,7 @@ void computeLighting(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, MaterialPro
#ifdef USE_CLUSTERS
if (any(greaterThanEqual(light_cell, lights.m.grid_size)) || cluster_index >= MAX_LIGHT_CLUSTERS)
return; // throughput * vec3(1., 0., 0.);
return; // vec3(1., 0., 0.);
#endif
//diffuse = specular = vec3(1.);
@ -138,7 +138,7 @@ void computeLighting(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, MaterialPro
//C += .3 * fract(vec3(light_cell) / 4.);
#if LIGHT_POLYGON
sampleEmissiveSurfaces(P, N, throughput, view_dir, material, cluster_index, diffuse, specular);
sampleEmissiveSurfaces(P, N, view_dir, material, cluster_index, diffuse, specular);
// These constants are empirical. There's no known math reason behind them
diffuse /= 25.0;
specular /= 25.0;
@ -146,7 +146,7 @@ void computeLighting(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, MaterialPro
#if LIGHT_POINT
vec3 ldiffuse = vec3(0.), lspecular = vec3(0.);
computePointLights(P, N, cluster_index, throughput, view_dir, material, ldiffuse, lspecular);
computePointLights(P, N, cluster_index, view_dir, material, ldiffuse, lspecular);
// These constants are empirical. There's no known math reason behind them
ldiffuse /= 4.;
lspecular /= 4.;

View File

@ -197,7 +197,7 @@ void sampleSinglePolygonLight(in vec3 P, in vec3 N, in vec3 view_dir, in SampleC
#if 0
// Sample random one
void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, MaterialProperties material, uint cluster_index, inout vec3 diffuse, inout vec3 specular) {
void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 view_dir, MaterialProperties material, uint cluster_index, inout vec3 diffuse, inout vec3 specular) {
const uint num_polygons = uint(light_grid.clusters_[cluster_index].num_polygons);
if (num_polygons == 0)
@ -215,7 +215,7 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, Mate
}
#elif 1
void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, MaterialProperties material, uint cluster_index, inout vec3 diffuse, inout vec3 specular) {
void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 view_dir, MaterialProperties material, uint cluster_index, inout vec3 diffuse, inout vec3 specular) {
#if DO_ALL_IN_CLUSTER
const SampleContext ctx = buildSampleContext(P, N, view_dir);
@ -256,8 +256,8 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, Mate
const float estimate = light_sample_dir.w;
vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.);
evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular);
diffuse += throughput * emissive * estimate * poly_diffuse;
specular += throughput * emissive * estimate * poly_specular;
diffuse += emissive * estimate * poly_diffuse;
specular += emissive * estimate * poly_specular;
}
}
#else // DO_ALL_IN_CLUSTERS
@ -310,8 +310,8 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, Mate
const vec3 emissive = poly.emissive;
vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.);
evalSplitBRDF(N, normalize(poly.center-P), view_dir, material, poly_diffuse, poly_specular);
diffuse += throughput * emissive * total_contrib;
specular += throughput * emissive * total_contrib;
diffuse += emissive * total_contrib;
specular += emissive * total_contrib;
#else
const SampleContext ctx = buildSampleContext(P, N, view_dir);
const PolygonLight poly = lights.m.polygons[selected - 1];
@ -332,8 +332,8 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, Mate
const float estimate = light_sample_dir.w;
vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.);
evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular);
diffuse += throughput * emissive * estimate;
specular += throughput * emissive * estimate;
diffuse += emissive * estimate;
specular += emissive * estimate;
}
#endif
#endif

View File

@ -45,9 +45,8 @@ void main() {
vec3 geometry_normal, shading_normal;
readNormals(pix, geometry_normal, shading_normal);
const vec3 throughput = vec3(1.);
vec3 diffuse = vec3(0.), specular = vec3(0.);
computeLighting(pos + geometry_normal * .001, shading_normal, throughput, -direction, material, diffuse, specular);
computeLighting(pos + geometry_normal * .001, shading_normal, -direction, material, diffuse, specular);
#if LIGHT_POINT
imageStore(out_light_point_diffuse, pix, vec4(diffuse, 0.f));