From 92e04068fd17f62d02aab5bc9c4594c7339351f5 Mon Sep 17 00:00:00 2001 From: redstrate <54911369+redstrate@users.noreply.github.com> Date: Sun, 16 Aug 2020 23:31:00 -0400 Subject: [PATCH] Remove kD term, improve fresnel reflections and fix scene capture --- engine/renderer/src/materialcompiler.cpp | 50 ++++++++++++------------ engine/renderer/src/renderer.cpp | 2 + engine/renderer/src/scenecapture.cpp | 8 ++-- shaders/brdf.frag.glsl | 2 +- shaders/common.nocompile.glsl | 12 ++++-- shaders/rendering.nocompile.glsl | 41 +++++++++---------- 6 files changed, 58 insertions(+), 57 deletions(-) diff --git a/engine/renderer/src/materialcompiler.cpp b/engine/renderer/src/materialcompiler.cpp index 3d2c367..840f318 100755 --- a/engine/renderer/src/materialcompiler.cpp +++ b/engine/renderer/src/materialcompiler.cpp @@ -292,6 +292,18 @@ ShaderSource MaterialCompiler::compile_material_fragment(Material& material, boo }\n"; } + if(use_ibl) { + src += "vec3 ibl(const int probe, const ComputedSurfaceInfo surface_info, const float intensity) {\n \ + const vec3 R = get_reflect(probe, surface_info.N);\n \ + const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg; \n \ + const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, probe)).xyz;\n \ + const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, probe), surface_info.roughness * 4).xyz;\n \ + const vec3 diffuse = sampledIrradiance * surface_info.diffuse_color;\n \ + const vec3 specular = prefilteredColor * (surface_info.F0 * brdf.x + 1.0 * brdf.y);\n \ + return (diffuse + specular) * intensity;\n \ + }\n"; + } + src += "void main() {\n"; bool has_output = false; @@ -335,47 +347,33 @@ ShaderSource MaterialCompiler::compile_material_fragment(Material& material, boo light_info = calculate_sun(scene.lights[i]);\n \ break;\n \ }\n \ - ComputedLightSurfaceInfo light_surface_info = compute_light_surface(light_info.direction, surface_info);\n"; + SurfaceBRDF surface_brdf = brdf(light_info.direction, surface_info);\n"; if(render_options.enable_normal_mapping && has_normal_mapping && render_options.enable_normal_shadowing) { src += std::string("light_info.radiance *= calculate_normal_lighting(") + normal_map_property_name + ", final_normal, light_info.direction);\n"; } - - src += "Lo += (light_surface_info.kD * final_diffuse_color.rgb / PI + light_surface_info.specular) * light_surface_info.NdotL * scene.lights[i].colorSize.xyz * light_info.radiance;\n \ + + src += "Lo += ((surface_brdf.specular + surface_brdf.diffuse) * light_info.radiance * surface_brdf.NdotL) * scene.lights[i].colorSize.rgb;\n \ }\n"; - + if(use_ibl) { src += - "const vec3 F = fresnel_schlick_roughness(surface_info.NdotV, surface_info.F0, surface_info.roughness); \n \ - const vec3 kD = (1.0 - F) * (1.0 - surface_info.metallic); \n \ - vec3 ambient = vec3(0.0); \ + "vec3 ambient = vec3(0.0); \ float sum = 0.0;\n \ for(int i = 0; i < max_probes; i++) { \ if(scene.probes[i].position.w == 1) {\n \ - vec3 position = scene.probes[i].position.xyz; \ - vec3 probe_min = position - (scene.probes[i].size.xyz / 2.0); \ - vec3 probe_max = position + (scene.probes[i].size.xyz / 2.0); \ - if(all(greaterThan(in_frag_pos, probe_min)) && all(lessThan(in_frag_pos, probe_max)) && scene.probes[i].position.w == 1) { \ + const vec3 position = scene.probes[i].position.xyz; \ + const vec3 probe_min = position - (scene.probes[i].size.xyz / 2.0); \ + const vec3 probe_max = position + (scene.probes[i].size.xyz / 2.0); \ + if(all(greaterThan(in_frag_pos, probe_min)) && all(lessThan(in_frag_pos, probe_max))) { \ float intensity = 1.0 - length(abs(in_frag_pos - position) / (scene.probes[i].size.xyz / 2.0));\n \ intensity = clamp(intensity, 0.0, 1.0) * scene.probes[i].size.w;\n \ - const vec3 R = get_reflect(i, surface_info.N);\n \ - const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg; \n \ - const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, i)).xyz;\n \ - const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, i), surface_info.roughness * 4).xyz;\n \ - const vec3 diffuse = sampledIrradiance * final_diffuse_color.rgb;\n \ - const vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);\n \ - ambient += (kD * diffuse + specular) * intensity;\n \ + ambient += ibl(i, surface_info, intensity);\n \ sum += intensity; \n \ } \ } else if(scene.probes[i].position.w == 2) {\n \ - const vec3 R = reflect(-surface_info.V, surface_info.N);\n \ - const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg; \n \ - const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, i)).xyz;\n \ - const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, i), surface_info.roughness * 4).xyz;\n \ - const vec3 diffuse = sampledIrradiance * final_diffuse_color.rgb;\n \ - const vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);\n \ - ambient += (kD * diffuse + specular) * scene.probes[i].size.w;\n \ - sum += 1.0; \n \ + ambient += ibl(i, surface_info, scene.probes[i].size.w);\n \ + sum += scene.probes[i].size.w; \n \ }\n \ }\n \ ambient /= sum;\n"; diff --git a/engine/renderer/src/renderer.cpp b/engine/renderer/src/renderer.cpp index cd30165..d2215fc 100755 --- a/engine/renderer/src/renderer.cpp +++ b/engine/renderer/src/renderer.cpp @@ -705,6 +705,8 @@ void Renderer::create_mesh_pipeline(Material& material) { pipelineInfo.render_pass = scene_capture->renderPass; pipelineInfo.shaders.fragment_src = material_compiler.compile_material_fragment(material, false); // scene capture does not use IBL + + pipelineInfo.rasterization.culling_mode = GFXCullingMode::Frontface; material.capture_pipeline = material_compiler.create_static_pipeline(pipelineInfo, false, true); } diff --git a/engine/renderer/src/scenecapture.cpp b/engine/renderer/src/scenecapture.cpp index b5ce59e..8a13815 100755 --- a/engine/renderer/src/scenecapture.cpp +++ b/engine/renderer/src/scenecapture.cpp @@ -47,8 +47,8 @@ const int mipLevels = 5; const std::array sceneTransforms = { transform::look_at(Vector3(0), Vector3(1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)), transform::look_at(Vector3(0), Vector3(-1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)), - transform::look_at(Vector3(0), Vector3( 0.0, -1.0, 0.0), Vector3(0.0, 0.0,1.0)), - transform::look_at(Vector3(0), Vector3( 0.0, 1.0, 0.0), Vector3(0.0, 0.0,-1.0)), + transform::look_at(Vector3(0), Vector3( 0.0, -1.0, 0.0), Vector3(0.0, 0.0,-1.0)), + transform::look_at(Vector3(0), Vector3( 0.0, 1.0, 0.0), Vector3(0.0, 0.0,1.0)), transform::look_at(Vector3(0), Vector3( 0.0, 0.0, 1.0), Vector3(0.0, -1.0, 0.0)), transform::look_at(Vector3(0), Vector3( 0.0, 0.0, -1.0), Vector3(0.0, -1.0, 0.0)) }; @@ -165,8 +165,8 @@ void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) { Vector3 front = Vector3(0.0f, 0.0f, 1.0f) * scene->get(obj).rotation; sl.directionPower = Vector4(-front, light.power); - sl.colorSize = Vector4(light.color, radians(light.size)); - sl.shadowsEnable = Vector4(light.enable_shadows, 0, 0, 0); + sl.colorSize = Vector4(light.color, radians(light.spot_size)); + sl.shadowsEnable = Vector4(light.enable_shadows, radians(light.size), 0, 0); sceneInfo.lights[sceneInfo.numLights++] = sl; } diff --git a/shaders/brdf.frag.glsl b/shaders/brdf.frag.glsl index 8c52338..370ae90 100755 --- a/shaders/brdf.frag.glsl +++ b/shaders/brdf.frag.glsl @@ -21,7 +21,7 @@ vec2 IntegrateBRDF(float NdotV, float roughness) { // preferred alignment direction (importance sampling). const vec2 Xi = hammersley(i, SAMPLE_COUNT); const vec3 H = importance_sample_ggx(Xi, N, roughness); - const vec3 L = normalize(2.0 * dot(V, H) * H - V); + const vec3 L = 2.0 * dot(V, H) * H - V; const float NdotL = max(L.z, 0.0); const float NdotH = max(H.z, 0.0); diff --git a/shaders/common.nocompile.glsl b/shaders/common.nocompile.glsl index 618e165..a3fefec 100755 --- a/shaders/common.nocompile.glsl +++ b/shaders/common.nocompile.glsl @@ -88,10 +88,14 @@ float geometry_slick_direct(const vec3 N, const vec3 V, const float roughness) { // GGX Smith Geometry, using GGX slick but combining both the view direction and the light direction float geometry_smith(const vec3 N, const vec3 V, const vec3 L, float roughness) { - float ggx2 = geometry_slick_direct(N, V, roughness); - float ggx1 = geometry_slick_direct(N, L, roughness); - - return ggx1 * ggx2; + const float dotNV = max(dot(N, V), 0.0); + const float dotNL = max(dot(N, L), 0.0); + + const float k = (roughness * roughness) / 2.0; + const float GL = dotNL / (dotNL * (1.0 - k) + k); + const float GV = dotNV / (dotNV * (1.0 - k) + k); + + return GL * GV; } // Fresnel Shlick diff --git a/shaders/rendering.nocompile.glsl b/shaders/rendering.nocompile.glsl index 095f6b6..34c4054 100755 --- a/shaders/rendering.nocompile.glsl +++ b/shaders/rendering.nocompile.glsl @@ -1,7 +1,7 @@ struct ComputedSurfaceInfo { vec3 N; vec3 V; - vec3 F0; + vec3 F0, diffuse_color; float NdotV; @@ -16,46 +16,43 @@ ComputedSurfaceInfo compute_surface(const vec3 diffuse, const vec3 normal, const info.NdotV = max(dot(info.N, info.V), 0.0); info.metallic = metallic; - info.roughness = max(0.0001, roughness * roughness); + info.roughness = max(0.0001, roughness); - info.F0 = mix(vec3(0.04), diffuse, info.metallic); + info.F0 = 0.16 * (1.0 - info.metallic) + diffuse * info.metallic; + info.diffuse_color = (1.0 - info.metallic) * diffuse; return info; } -struct ComputedLightSurfaceInfo { - vec3 kD; - vec3 specular; +struct SurfaceBRDF { + vec3 diffuse, specular; float NdotL; }; -ComputedLightSurfaceInfo compute_light_surface(const vec3 L, const ComputedSurfaceInfo surface_info) { - ComputedLightSurfaceInfo info; +SurfaceBRDF brdf(const vec3 L, const ComputedSurfaceInfo surface_info) { + SurfaceBRDF info; // half-vector const vec3 H = normalize(surface_info.V + L); const float HdotV = clamp(dot(H, surface_info.V), 0.0, 1.0); - const vec3 F = fresnel_schlick(HdotV, surface_info.F0); - - info.kD = (vec3(1.0) - F) * (1.0 - surface_info.metallic); - + // fresnel reflectance function + const vec3 F = fresnel_schlick(surface_info.NdotV, surface_info.F0); + + // geometry function const float D = ggx_distribution(surface_info.N, H, surface_info.roughness); + + // normal distribution function const float G = geometry_smith(surface_info.N, surface_info.V, L, surface_info.roughness); - - /* - F = fresnel reflectance function - G = geometry function - D = NDF (normal distribution function) - */ + const vec3 numerator = F * G * D; - - /* - Correction factor - */ const float denominator = 4.0 * surface_info.NdotV * clamp(dot(surface_info.N, L), 0.0, 1.0); + // cook-torrance specular brdf info.specular = numerator / (denominator + 0.001); + + // lambertian diffuse + info.diffuse = surface_info.diffuse_color * (1.0 / PI); info.NdotL = clamp(dot(surface_info.N, L), 0.0, 1.0);