Commit fff8906b authored by Johannes Braun's avatar Johannes Braun
Browse files

Still bsdf bugfixing. Now with weird sampling and dark seams.

parent 8c46bf3f
......@@ -95,7 +95,7 @@ BSDFResult computeBSDF(const in Material material, const in vec2 random, const i
// Schlick's fresnel approximation with the material's normal response
float normal_response = normalResponse(sampled_material.ior, sampled_material.metallic);
float fresnel = fresnelSchlick(clamp(dot(incoming, micro_normal), 0, 1), normal_response);
float fresnel = fresnelSchlick(dot(incoming, micro_normal), normal_response);
float k_s = fresnel;
float k_rest = 1-k_s;
......@@ -124,7 +124,7 @@ BSDFResult computeBSDF(const in Material material, const in vec2 random, const i
vec3 outgoing_refracted = normalize((eta * c - sign(dot(incoming, normal)) * sqrt(1 + eta*(c * c - 1))) * micro_normal - eta * incoming);
// Now we can generate a direction of the ray being reflected at the microsurface normal
vec3 outgoing_reflected = normalize(2 * clamp(dot(incoming, micro_normal), 0, 1) * micro_normal - incoming);
vec3 outgoing_reflected = normalize(2 * abs(dot(incoming, micro_normal)) * micro_normal - incoming);
// Compute geometric attenuation via GGX
float geometry = ggxGeometry(incoming, outgoing_reflected, normal, micro_normal, sampled_material.roughness);
......@@ -133,20 +133,16 @@ BSDFResult computeBSDF(const in Material material, const in vec2 random, const i
// Reflections of metallic materials are tinted with the material base color.
vec3 fresnel_tint = fresnelTint(fresnel, sampled_material.metallic, sampled_material.base);
float n_dot_in = clamp(dot(normal, incoming), 0, 1);
float n_dot_out = clamp(dot(normal, outgoing_reflected), 0, 1);
float m_dot_in = clamp(dot(micro_normal, outgoing_reflected), 0, 1);
float m_dot_out = clamp(dot(micro_normal, outgoing_reflected), 0, 1);
float m_dot_out_refract = clamp(dot(micro_normal, outgoing_refracted), -1, 1);
float n_dot_out_refract = clamp(dot(normal, outgoing_refracted), -1, 1);
float m_dot_n = clamp(dot(micro_normal, normal), 0, 1);
float m_dot_in = abs(dot(micro_normal, outgoing_reflected));
float m_dot_out = abs(dot(micro_normal, outgoing_reflected));
float m_dot_out_refract = abs(dot(micro_normal, outgoing_refracted));
// In this implementation, it is defined that the importance sample generated is cos(theta) instead of the usual approach of only theta.
float cos_theta = cos(hemisphere_sample.importance.y);
float cos_theta = abs(dot(micro_normal, normal));
// Compute the microsurface normal probability and with that the final probability density function
// Clamp up denominator to not divide by zero.
float jacobian_reflect = 1 / clamp(4 * m_dot_out, 0.0001f, 1);
float jacobian_reflect = 1 / (4 * m_dot_out);
float probability_m = hemisphere_sample.distribution * cos_theta;
float pdf = probability_m * jacobian_reflect;
......@@ -154,24 +150,24 @@ BSDFResult computeBSDF(const in Material material, const in vec2 random, const i
float ior_out_2 = ior_out * ior_out;
float jacobian_refract_denominator = ior_in * m_dot_in + ior_out * m_dot_out_refract;
jacobian_refract_denominator *= jacobian_refract_denominator;
jacobian_refract_denominator = clamp(jacobian_refract_denominator, 0.0001f, 1.f);
jacobian_refract_denominator = clamp(jacobian_refract_denominator, 0.0000000001f, 1.f);
//Take the absolute value as m_dot_out_refract is negative
float jacobian_refract = abs(ior_out_2 * m_dot_out_refract / jacobian_refract_denominator);
float pdf_refract = probability_m * jacobian_refract;
// Same here... clamp up denominator to not divide by zero
float brdf_denominator = clamp((4 * n_dot_in * n_dot_out), 0.0001f, 1.f);
float brdf_denominator = 4 * m_dot_in * m_dot_out;
float btdf_denominator = jacobian_refract_denominator;
// Finally, build the brdf. As we do russian roulette, we can just tint the brdf instead of multiplying with the fresnel value.
vec3 brdf = mix(vec3(1), sampled_material.base, sampled_material.metallic) * geometry * hemisphere_sample.distribution / brdf_denominator;
// Same as above, we don't need the fresnel factor here either.
vec3 btdf = (m_dot_in * m_dot_out_refract / (n_dot_in * n_dot_out_refract)) * ior_out_2 * sampled_material.base * geometry_refracted * hemisphere_sample.distribution / btdf_denominator;
vec3 btdf = abs(m_dot_in * m_dot_out_refract / (m_dot_in * m_dot_out_refract)) * ior_out_2 * sampled_material.base * geometry_refracted * hemisphere_sample.distribution / btdf_denominator;
// russian roulette Part 2
// Also check whether the refracted ray is valid, as we don't want to sample with NaN rays, just for safety.
if(roulette_border_specular > random.x || isnan(outgoing_refracted.x))
if(roulette_border_specular >= random.x)
{
// Use as brdf sample
result.generated_ray.direction = outgoing_reflected;
......@@ -180,7 +176,7 @@ BSDFResult computeBSDF(const in Material material, const in vec2 random, const i
result.evaluation = vec3(0); // No diffuse if reflecting
result.bsdf_id = eReflect;
}
else if(roulette_border_transmit > random.x)
else
{
// Use as btdf sample
result.generated_ray.direction = outgoing_refracted;
......
......@@ -20,7 +20,7 @@ uniform struct
bool u_random_subpixel; //defaults to false.
} settings;
void generate(int id);
void generate(int id, int pixels);
void trace(int id);
void resetImportance(int id);
......@@ -30,15 +30,15 @@ void main()
if (!(int(gl_GlobalInvocationID.x) < target_size.x && int(gl_GlobalInvocationID.y) < target_size.y))
return;
int id = u_render_target.imageSize().x * int(gl_GlobalInvocationID.y) + int(gl_GlobalInvocationID.x);
generate(id);
int id = target_size.x * int(gl_GlobalInvocationID.y) + int(gl_GlobalInvocationID.x);
generate(id, target_size.x * target_size.y);
trace(id);
resetImportance(id);
}
void generate(int id)
void generate(int id, int pixels)
{
traces_data[id].ray = u_camera.getRayFromPixel(vec2(gl_GlobalInvocationID.xy), settings.u_random_subpixel ? vec2(0, 0) : rand2D(random_seed + id));
traces_data[id].ray = u_camera.getRayFromPixel(vec2(gl_GlobalInvocationID.xy), settings.u_random_subpixel ? vec2(0, 0) : rand2D(random_seed + id, pixels));
}
void trace(int id)
......
......@@ -36,7 +36,7 @@ void main()
vec4 texel_01 = u_gbuffer_texture_01.imageLoad(ivec2(pixel), random_sample);
traces_data[id].ray = u_camera.getRayFromPixel(pixel, rand2D(random_seed + int(id)));
traces_data[id].ray = u_camera.getRayFromPixel(pixel, rand2D(random_seed + int(id), target_size.x * target_size.y));
traces_data[id].hit.invalidate();
if (length(texel_01) != 0) {
......
......@@ -134,8 +134,6 @@ bool shade(int id, inout vec3 radiance, uint bounce, out uint bsdf_id)
if(bsdf_result.bsdf_id == eEmit)
{
writeColorStore(ray, radiance * bsdf_result.radiance, clamp_color_max);
// if(!isnan(bsdf_result.generated_ray.direction.x))
//writeColorStore(ray, bsdf_result.generated_ray.direction.xyz, clamp_color_max);
traces_data[id].hit.invalidate();
return false;
}
......@@ -154,7 +152,7 @@ bool shade(int id, inout vec3 radiance, uint bounce, out uint bsdf_id)
vec3 non_normal_direction = point_on_light - vertex.position.xyz;
Ray shadow_test;
shadow_test.direction = normalize(non_normal_direction);
shadow_test.origin = vertex.position.xyz + 1e-5 * shadow_test.direction;
shadow_test.origin = vertex.position.xyz + 1e-2f * vertex.normal.xyz;
if (success && !shadow_test.intersectsAny(length(non_normal_direction), use_bvh))
{
......
......@@ -66,17 +66,10 @@ void expand(inout Bounds bounds, const in vec3 include)
bounds.max = max(bounds.max, vec4(include, 0));
}
vec3 localToWorld(const in vec3 vector, const in vec3 view, const in vec3 normal) {
vec3 localToWorld(const in vec3 vector, const in vec3 view, const in vec3 n) {
// Find an axis that is not parallel to normal
vec3 majorAxis;
if(vector == vec3(0, 0, 1))
{
return normal;
}
else
{
majorAxis = cross(view, normal);
}
vec3 normal = faceforward(n, -view, n);
vec3 majorAxis = mix(vec3(0, 0, 1), vec3(1, 0, 0), dot(normal, vec3(0, 0, 1)));
// Use majorAxis to create a coordinate system relative to world space
vec3 u = normalize(cross(normal, majorAxis));
......
......@@ -67,7 +67,7 @@ float ggxChi(float v)
float ggxDistribution(float cosT, float roughness)
{
float normal_dot_half = cosT;
float roughness2 = roughness * roughness;
float roughness2 = max(roughness * roughness, 0.0001f);
float normal_dot_half2 = normal_dot_half * normal_dot_half;
float denominator = normal_dot_half2 * roughness2 + (1-normal_dot_half2);
......
......@@ -114,8 +114,8 @@ float rand(int seed)
return float(rand_xorshift()) * (1.0 / UINT_MAX);
}
vec2 rand2D(int seed){
return hammersley2d(uint(rand(seed) * RANDOM_SAMPLING_FACTOR), INV_RANDOM_SAMPLING_FACTOR);
vec2 rand2D(int seed, int samples){
return hammersley2d(uint(rand(seed) * samples), 1/float(samples));
}
#endif //!INCLUDE_UTIL_RANDOM_GLSL
......@@ -78,7 +78,7 @@ float getEmission(const in Material material, const in vec2 texcoord)
float getRoughness(const in Material material, const in vec2 texcoord)
{
return max(material.roughness.parameter1f(texcoord), 0.00001f);
return material.roughness.parameter1f(texcoord);
}
float getMetallic(const in Material material, const in vec2 texcoord)
......
......@@ -28,7 +28,7 @@ const fs::path engine_settings_path = files::asset("/preferences/default.xml");
const fs::path pathtracer_settings_path = files::asset("/preferences/pathtracer_default.xml");
const fs::path skybox_files_path = files::asset("/textures/ryfjallet/");
const fs::path env_audio_path = files::asset("/audio/env.wav");
const fs::path startup_scene_path = files::asset("/meshes/scenery/figure.dae");
const fs::path startup_scene_path = files::asset("/meshes/scenery/sphere.dae");
// My little all-enclosing pathtracer pointer
std::unique_ptr<raytrace::Pathtracer> pathtracer = nullptr;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment