From bf512216323f3df55627421bb0187ed364d58340 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Wed, 1 Sep 2021 00:18:04 +0200 Subject: White furnace test on gltf scenes & load normals --- shaders/compute.comp | 103 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 34 deletions(-) (limited to 'shaders/compute.comp') diff --git a/shaders/compute.comp b/shaders/compute.comp index 7454589..0d5c525 100644 --- a/shaders/compute.comp +++ b/shaders/compute.comp @@ -25,8 +25,7 @@ const uint DIFFUSE = 1; const uint SPECULAR = 2; struct material { - vec4 albedo; - vec4 emissive; + vec4 base_color; float metalness; float roughness; uint[2] padding; @@ -35,7 +34,8 @@ struct material { struct hit_info { float t; vec3 point; - vec3 normal; + vec3 geometry_normal; + vec3 shading_normal; material mat; }; @@ -48,6 +48,7 @@ struct sphere { struct vertex { vec4 position; + vec4 normal; }; struct triangle { @@ -93,8 +94,8 @@ layout(buffer_reference) readonly buffer scene_metadata { }; layout(buffer_reference) readonly buffer primitives_array { - sphere[] spheres; - // triangle triangles[]; + // sphere[] spheres; + triangle triangles[]; }; layout(buffer_reference) readonly buffer nodes_array { @@ -232,12 +233,12 @@ bool hit_sphere(sphere s, ray r, out hit_info info) { } info.t = root; - info.point = at(r, info.t); + // info.point = at(r, info.t); - vec3 outward_normal = (info.point - s.position.xyz) / s.radius; - bool front_face = dot(outward_normal, r.direction) < 0.0; - info.normal = front_face ? outward_normal : -outward_normal; - info.mat = s.mat; + // vec3 outward_normal = (info.point - s.position.xyz) / s.radius; + // bool front_face = dot(outward_normal, r.direction) < 0.0; + // info.normal = front_face ? outward_normal : -outward_normal; + // info.mat = s.mat; return true; } @@ -259,7 +260,7 @@ bool hit_triangle(triangle tri, ray r, out hit_info info) { } info.t = t; - info.normal = normal; + info.geometry_normal = normalize(normal); return true; } @@ -272,16 +273,16 @@ bool hit_node(ray r, out hit_info info) { while(id != -1) { // Leafs if (bufs.bvh.nodes[id].primitive_id != -1) { - if (hit_sphere(bufs.geometry.spheres[bufs.bvh.nodes[id].primitive_id], r, temp_info)) { - info = temp_info; - r.max_t = temp_info.t; - hit = true; - } - // if (hit_triangle(bufs.geometry.triangles[bufs.bvh.nodes[id].primitive_id], r, temp_info)) { + // if (hit_sphere(bufs.geometry.spheres[bufs.bvh.nodes[id].primitive_id], r, temp_info)) { // info = temp_info; // r.max_t = temp_info.t; // hit = true; // } + if (hit_triangle(bufs.geometry.triangles[bufs.bvh.nodes[id].primitive_id], r, temp_info)) { + info = temp_info; + r.max_t = temp_info.t; + hit = true; + } id = bufs.bvh.nodes[id].next_id; } else if (hit_aabb(bufs.bvh.nodes[id].min, bufs.bvh.nodes[id].max, r)) { id++; @@ -294,12 +295,12 @@ bool hit_node(ray r, out hit_info info) { return hit; } -vec3 albedo_to_specular_F0(vec3 albedo, float metalness) { - return mix(vec3(MIN_DIELECTRICS_F0), albedo, metalness); +vec3 base_color_to_specular_F0(vec3 base_color, float metalness) { + return mix(vec3(MIN_DIELECTRICS_F0), base_color, metalness); } -vec3 albedo_to_diffuse_reflectance(vec3 albedo, float metalness) { - return albedo * (1.0f - metalness); +vec3 base_color_to_diffuse_reflectance(vec3 base_color, float metalness) { + return base_color * (1.0f - metalness); } // Schlick's approximation to Fresnel term @@ -325,12 +326,12 @@ float shadowed_F90(vec3 F0) { return min(1.f, t * luminance(F0)); } -float get_brdf_probability(material mat, vec3 view, vec3 shadingNormal) { +float get_brdf_probability(material mat, vec3 view, vec3 shading_normal) { // 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 - vec3 specular_F0 = vec3(luminance(albedo_to_specular_F0(mat.albedo.rgb, mat.metalness))); - float diffuse_reflectance = luminance(albedo_to_diffuse_reflectance(mat.albedo.rgb, mat.metalness)); - float fresnel = clamp(luminance(eval_fresnel(specular_F0, shadowed_F90(specular_F0), max(0.0f, dot(view, shadingNormal)))), 0.0, 1.0); + vec3 specular_F0 = vec3(luminance(base_color_to_specular_F0(mat.base_color.rgb, mat.metalness))); + float diffuse_reflectance = luminance(base_color_to_diffuse_reflectance(mat.base_color.rgb, mat.metalness)); + float fresnel = clamp(luminance(eval_fresnel(specular_F0, shadowed_F90(specular_F0), max(0.0f, dot(view, shading_normal)))), 0.0, 1.0); // Approximate relative contribution of BRDFs using the Fresnel term float specular = fresnel; @@ -352,34 +353,68 @@ vec3 ray_color(ray r, uint seed) { if (!hit_node(r, info)) return throughput * vec3(1.0); - // uint brdf_type; + vec3 v = -r.direction; + + if (dot(info.geometry_normal, v) < 0.f) info.geometry_normal = -info.geometry_normal; + + // if (dot(info.geometry_normal, info.shading_normal) < 0.0f) info.shading_normal = -info.shading_normal; + + uint brdf_type; // if (info.mat.metalness == 1.f && info.mat.metalness == 0.f) { // brdf_type = SPECULAR; // } else { - // float brdf_probability = get_brdf_probability(info.mat, -r.direction, ); + // float brdf_probability = get_brdf_probability(info.mat, -r.direction, info.shading_normal); // if (rand(seed) < brdf_probability) { // brdf_type = SPECULAR; + // throughput /= brdf_probability; // } else { // brdf_type = DIFFUSE; + // throughput /= (1.0 - brdf_probability); // } // } + brdf_type = DIFFUSE; + + // Ignore ray coming from below the hemisphere + // if (dot(info.shading_normal, v) <= 0.f) break; + // Move to tangent space - vec4 rotation_to_z = rotation_to_z_axis(info.normal); + vec4 rotation_to_z = rotation_to_z_axis(info.geometry_normal); vec3 view_local = rotate_point(rotation_to_z, -r.direction); vec3 normal_local = vec3(0.0, 0.0, 1.0); - vec3 ray_dir_local = sample_hemisphere(seed); + vec3 ray_dir_local; + vec3 brdf_weight; + + if (brdf_type == DIFFUSE) { + ray_dir_local = sample_hemisphere(seed); + + float NdotL = dot(normal_local, ray_dir_local); + float pdf = NdotL / PI; + // vec3 brdf = base_color_to_diffuse_reflectance(info.mat.base_color.xyz, info.mat.metalness) / PI; + vec3 brdf = (vec3(1.0) * NdotL) / PI; + brdf_weight = brdf / pdf; + } else if (brdf_type == SPECULAR) { + // alpha = info.mat.roughness * info.mat.roughness; + + // vec3 half_local; + // if (alpha == 0.0f) { + // // Fast path for zero roughness (perfect reflection), also prevents NaNs appearing due to divisions by zeroes + // half_local = vec3(0.0f, 0.0f, 1.0f); + // } else { + // // For non-zero roughness, this calls VNDF sampling for GG-X distribution or Walter's sampling for Beckmann distribution + // half_local = sampleSpecularHalfVector(view_local, vec2(alpha)); + // } + } - float NdotL = dot(normal_local, ray_dir_local); - float pdf = NdotL / PI; - vec3 brdf = albedo_to_diffuse_reflectance(info.mat.albedo.xyz, info.mat.metalness) / PI; - throughput *= brdf / pdf; + throughput *= brdf_weight; // Move to global space vec4 rotation_from_z = invert_rotation(rotation_to_z); vec3 ray_dir = rotate_point(rotation_from_z, ray_dir_local); - r = ray(info.point, normalize(info.normal + ray_dir), 0.001f, 1e15); + if (dot(info.geometry_normal, ray_dir) <= 0.0f) break; + + r = ray(info.point, ray_dir, 0.001f, 1e15); // Russian Roulette // As the throughput gets smaller, the ray is more likely to get terminated early. -- cgit v1.3