vk: rt: rewrite direct-eval brdfs from scratch
Deprecate `brdf.h` usage, start writing our own BRDF functions. Use glTF 2.0 BRDF mixing model as a simple starting point. Mix-in base_color into specular early, as it is light-direction dependent and cannot be easily separated. Disable bounces for now, as we don't have yet good sampling story, need to write "backwards" BRDFs that give us ray directions to sample, and accommodate for that sampling bias in BRDF attenuation itself. Also introduces some other weird artifacts on `test_material` map, investigation pending. Related to black metals in #666
This commit is contained in:
parent
6ffaad02f2
commit
88b24ad3bd
|
@ -94,33 +94,13 @@ bool getHit(vec3 origin, vec3 direction, inout RayPayloadPrimary payload) {
|
|||
}
|
||||
const int INDIRECT_SCALE = 2;
|
||||
|
||||
void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specular) {
|
||||
diffuse = vec3(0.);
|
||||
specular = vec3(0.);
|
||||
|
||||
const vec4 pos_t = imageLoad(position_t, pix);
|
||||
if (pos_t.w <= 0.)
|
||||
return;
|
||||
|
||||
const vec4 material_data = imageLoad(material_rmxx, pix);
|
||||
const vec4 base_a = SRGBtoLINEAR(imageLoad(base_color_a, pix));
|
||||
|
||||
MaterialProperties material;
|
||||
material.baseColor = vec3(1.f);
|
||||
material.emissive = vec3(0.f);
|
||||
material.metalness = material_data.g;
|
||||
material.roughness = material_data.r;
|
||||
|
||||
vec3 geometry_normal, shading_normal;
|
||||
readNormals(pix, geometry_normal, shading_normal);
|
||||
|
||||
const float ray_normal_fudge = .01;
|
||||
vec3 throughput = vec3(1.);
|
||||
|
||||
// 1. Make a "random" material-based ray for diffuse lighting
|
||||
vec3 bounce_direction = vec3(0.);
|
||||
bool pickBounceDirection(MaterialProperties material, float alpha, out vec3 direction, inout vec3 throughput) {
|
||||
#if 1
|
||||
// TODO implement
|
||||
return false;
|
||||
#else
|
||||
int brdf_type = DIFFUSE_TYPE;
|
||||
|
||||
// FIXME address translucency properly
|
||||
const float alpha = (base_a.a);
|
||||
if (1. > alpha && rand01() > alpha) {
|
||||
brdf_type = SPECULAR_TYPE;
|
||||
|
@ -144,12 +124,43 @@ void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specula
|
|||
const vec2 u = vec2(rand01(), rand01());
|
||||
vec3 brdf_weight = vec3(0.);
|
||||
if (!evalIndirectCombinedBRDF(u, shading_normal, geometry_normal, -direction, material, brdf_type, bounce_direction, brdf_weight))
|
||||
return;
|
||||
return false;
|
||||
throughput *= brdf_weight;
|
||||
}
|
||||
|
||||
const float throughput_threshold = 1e-3;
|
||||
if (dot(throughput, throughput) < throughput_threshold)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specular) {
|
||||
diffuse = vec3(0.);
|
||||
specular = vec3(0.);
|
||||
|
||||
#if 0
|
||||
const vec4 pos_t = imageLoad(position_t, pix);
|
||||
if (pos_t.w <= 0.)
|
||||
return;
|
||||
|
||||
const vec4 material_data = imageLoad(material_rmxx, pix);
|
||||
const vec4 base_a = SRGBtoLINEAR(imageLoad(base_color_a, pix));
|
||||
|
||||
vec3 geometry_normal, shading_normal;
|
||||
readNormals(pix, geometry_normal, shading_normal);
|
||||
|
||||
const float ray_normal_fudge = .01;
|
||||
vec3 throughput = vec3(1.);
|
||||
vec3 bounce_direction = vec3(0.);
|
||||
|
||||
MaterialProperties material;
|
||||
material.base_color = base_a.rgb;
|
||||
material.metalness = material_data.g;
|
||||
material.roughness = material_data.r;
|
||||
|
||||
if (!pickBounceDirection(material, base_a.a, bounce_direction, throughput))
|
||||
return;
|
||||
|
||||
// 2. Rake yuri it, get hit
|
||||
|
@ -169,8 +180,7 @@ void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specula
|
|||
vec3 ldiffuse = vec3(0.);
|
||||
vec3 lspecular = vec3(0.);
|
||||
MaterialProperties hit_material;
|
||||
hit_material.baseColor = vec3(1.);
|
||||
hit_material.emissive = vec3(0.f);
|
||||
hit_material.base_color = payload.base_color_a.rgb;
|
||||
hit_material.metalness = payload.material_rmxx.g;
|
||||
hit_material.roughness = payload.material_rmxx.r;
|
||||
computeLighting(hit_pos, hit_shading_normal, -bounce_direction, hit_material, ldiffuse, lspecular);
|
||||
|
@ -189,6 +199,7 @@ void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specula
|
|||
diffuse += lighting;
|
||||
else
|
||||
specular += lighting + payload.emissive.rgb;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ This work is published from: Germany. */
|
|||
// - remove c++ compat
|
||||
// - port to glsl
|
||||
|
||||
#ifndef BRDF_H_INCLUDED
|
||||
#define BRDF_H_INCLUDED
|
||||
|
||||
float rsqrt(float x) { return inversesqrt(x); }
|
||||
float saturate(float x) { return clamp(x, 0.0f, 1.0f); }
|
||||
vec3 saturate(vec3 x) { return clamp(x, vec3(0.0f), vec3(1.0f)); }
|
||||
|
@ -179,7 +182,7 @@ vec3 saturate(vec3 x) { return clamp(x, vec3(0.0f), vec3(1.0f)); }
|
|||
|
||||
struct MaterialProperties
|
||||
{
|
||||
vec3 baseColor;
|
||||
vec3 base_color;
|
||||
float metalness;
|
||||
|
||||
vec3 emissive;
|
||||
|
@ -249,13 +252,13 @@ float luminance(vec3 rgb)
|
|||
return dot(rgb, vec3(0.2126f, 0.7152f, 0.0722f));
|
||||
}
|
||||
|
||||
vec3 baseColorToSpecularF0(vec3 baseColor, float metalness) {
|
||||
return mix(vec3(MIN_DIELECTRICS_F0, MIN_DIELECTRICS_F0, MIN_DIELECTRICS_F0), baseColor, metalness);
|
||||
vec3 baseColorToSpecularF0(vec3 base_color, float metalness) {
|
||||
return mix(vec3(MIN_DIELECTRICS_F0, MIN_DIELECTRICS_F0, MIN_DIELECTRICS_F0), base_color, metalness);
|
||||
}
|
||||
|
||||
vec3 baseColorToDiffuseReflectance(vec3 baseColor, float metalness)
|
||||
vec3 baseColorToDiffuseReflectance(vec3 base_color, float metalness)
|
||||
{
|
||||
return baseColor * (1.0f - metalness);
|
||||
return base_color * (1.0f - metalness);
|
||||
}
|
||||
|
||||
float none(const BrdfData data) {
|
||||
|
@ -867,8 +870,8 @@ BrdfData prepareBRDFData(vec3 N, vec3 L, vec3 V, MaterialProperties material) {
|
|||
data.VdotH = saturate(dot(V, data.H));
|
||||
|
||||
// Unpack material properties
|
||||
data.specularF0 = baseColorToSpecularF0(material.baseColor, material.metalness);
|
||||
data.diffuseReflectance = baseColorToDiffuseReflectance(material.baseColor, material.metalness);
|
||||
data.specularF0 = baseColorToSpecularF0(material.base_color, material.metalness);
|
||||
data.diffuseReflectance = baseColorToDiffuseReflectance(material.base_color, material.metalness);
|
||||
|
||||
// Unpack 'perceptively linear' -> 'linear' -> 'squared' roughness
|
||||
data.roughness = material.roughness;
|
||||
|
@ -957,8 +960,8 @@ float getBrdfProbability(MaterialProperties material, vec3 V, vec3 shadingNormal
|
|||
|
||||
// Evaluate Fresnel term using the shading normal
|
||||
// Note: we use the shading normal instead of the microfacet normal (half-vector) for Fresnel term here. That's suboptimal for rough surfaces at grazing angles, but half-vector is yet unknown at this point
|
||||
float specularF0 = luminance(baseColorToSpecularF0(material.baseColor, material.metalness));
|
||||
float diffuseReflectance = luminance(baseColorToDiffuseReflectance(material.baseColor, material.metalness));
|
||||
float specularF0 = luminance(baseColorToSpecularF0(material.base_color, material.metalness));
|
||||
float diffuseReflectance = luminance(baseColorToDiffuseReflectance(material.base_color, material.metalness));
|
||||
float Fresnel = saturate(luminance(evalFresnel(vec3(specularF0), shadowedF90(vec3(specularF0)), max(0.0f, dot(V, shadingNormal)))));
|
||||
|
||||
// Approximate relative contribution of BRDFs using the Fresnel term
|
||||
|
@ -971,3 +974,4 @@ float getBrdfProbability(MaterialProperties material, vec3 V, vec3 shadingNormal
|
|||
// Clamp probability to avoid undersampling of less prominent BRDF
|
||||
return clamp(p, 0.1f, 0.9f);
|
||||
}
|
||||
#endif // ifndef BRDF_H_INCLUDED
|
||||
|
|
|
@ -302,8 +302,16 @@ void main() {
|
|||
|
||||
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);
|
||||
|
||||
const float metalness = imageLoad(material_rmxx, pix).g;
|
||||
|
||||
// Late base_color compositing with diffuse lighting
|
||||
// see brdf.glsl
|
||||
const vec3 diffuse_color = mix(base_color, vec3(0.), metalness);
|
||||
colour = diffuse * diffuse_color;
|
||||
|
||||
// Specular color is already computed-in as it is both view and light-source-direction dependent
|
||||
colour += specular;
|
||||
} else {
|
||||
colour = diffuse + specular;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
const float color_culling_threshold = 0;//600./color_factor;
|
||||
const float shadow_offset_fudge = .1;
|
||||
|
||||
#include "brdf.h"
|
||||
#include "brdf.glsl"
|
||||
#include "light_common.glsl"
|
||||
|
||||
#if LIGHT_POLYGON
|
||||
|
|
|
@ -149,23 +149,4 @@ bool shadowedSky(vec3 pos, vec3 dir) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// This is an entry point for evaluation of all other BRDFs based on selected configuration (for direct light)
|
||||
void evalSplitBRDF(vec3 N, vec3 L, vec3 V, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
|
||||
// Prepare data needed for BRDF evaluation - unpack material properties and evaluate commonly used terms (e.g. Fresnel, NdotL, ...)
|
||||
const BrdfData data = prepareBRDFData(N, L, V, material);
|
||||
|
||||
// Ignore V and L rays "below" the hemisphere
|
||||
//if (data.Vbackfacing || data.Lbackfacing) return vec3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Eval specular and diffuse BRDFs
|
||||
specular = evalSpecular(data);
|
||||
diffuse = evalDiffuse(data);
|
||||
|
||||
// Combine specular and diffuse layers
|
||||
#if COMBINE_BRDFS_WITH_FRESNEL
|
||||
// Specular is already multiplied by F, just attenuate diffuse
|
||||
diffuse *= vec3(1.) - data.F;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif //ifndef LIGHT_COMMON_GLSL_INCLUDED
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "noise.glsl"
|
||||
|
||||
#include "ray_kusochki.glsl"
|
||||
#include "color_spaces.glsl"
|
||||
|
||||
#include "light.glsl"
|
||||
|
||||
|
@ -35,11 +36,12 @@ void main() {
|
|||
const vec4 material_data = imageLoad(material_rmxx, pix);
|
||||
|
||||
MaterialProperties material;
|
||||
material.baseColor = vec3(1.);
|
||||
material.emissive = vec3(0.f);
|
||||
material.base_color = SRGBtoLINEAR(imageLoad(base_color_a, pix).rgb);
|
||||
material.metalness = material_data.g;
|
||||
material.roughness = material_data.r;
|
||||
|
||||
//g_mat_gltf2 = pix.y > ubo.ubo.res.y / 2.;
|
||||
|
||||
const vec4 pos_t = imageLoad(position_t, pix);
|
||||
|
||||
vec3 diffuse = vec3(0.), specular = vec3(0.);
|
||||
|
|
|
@ -22,6 +22,7 @@ layout (set = 0, binding = 8, align = 1) readonly buffer UBOLightClusters {
|
|||
layout(set = 0, binding = 10, rgba32f) uniform readonly image2D position_t;
|
||||
layout(set = 0, binding = 11, rgba16f) uniform readonly image2D normals_gs;
|
||||
layout(set = 0, binding = 12, rgba8) uniform readonly image2D material_rmxx;
|
||||
layout(set = 0, binding = 13, rgba8) uniform readonly image2D base_color_a;
|
||||
|
||||
layout(set = 0, binding = 20, rgba16f) uniform writeonly image2D out_light_point_diffuse;
|
||||
layout(set = 0, binding = 21, rgba16f) uniform writeonly image2D out_light_point_specular;
|
||||
|
|
|
@ -22,6 +22,7 @@ layout (set = 0, binding = 8, align = 1) readonly buffer UBOLightClusters {
|
|||
layout(set = 0, binding = 10, rgba32f) uniform readonly image2D position_t;
|
||||
layout(set = 0, binding = 11, rgba16f) uniform readonly image2D normals_gs;
|
||||
layout(set = 0, binding = 12, rgba8) uniform readonly image2D material_rmxx;
|
||||
layout(set = 0, binding = 13, rgba8) uniform readonly image2D base_color_a;
|
||||
|
||||
layout(set = 0, binding = 20, rgba16f) uniform writeonly image2D out_light_poly_diffuse;
|
||||
layout(set = 0, binding = 21, rgba16f) uniform writeonly image2D out_light_poly_specular;
|
||||
|
|
|
@ -125,7 +125,6 @@ void main() {
|
|||
imageStore(out_position_t, pix, payload.hit_t);
|
||||
imageStore(out_base_color_a, pix, LINEARtoSRGB(payload.base_color_a));
|
||||
imageStore(out_normals_gs, pix, payload.normals_gs);
|
||||
//imageStore(out_material_rmxx, pix, vec4(payload.material_rmxx.rg, 0, uintToFloat01(xxhash32(debug_geometry_index))));
|
||||
imageStore(out_material_rmxx, pix, payload.material_rmxx);
|
||||
imageStore(out_emissive, pix, payload.emissive);
|
||||
imageStore(out_geometry_prev_position, pix, payload.prev_pos_t);
|
||||
|
|
Loading…
Reference in New Issue