From 7052d43a67c205d7284ab46e658e2c00aac970fd Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 7 Jun 2017 22:58:36 +0300 Subject: [PATCH 1/2] gl_rasterizer/lighting: implement geometric factor --- src/video_core/regs_lighting.h | 2 ++ .../renderer_opengl/gl_shader_gen.cpp | 17 ++++++++++++++++- src/video_core/renderer_opengl/gl_shader_gen.h | 2 ++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/video_core/regs_lighting.h b/src/video_core/regs_lighting.h index f383b8b4f..7221d1688 100644 --- a/src/video_core/regs_lighting.h +++ b/src/video_core/regs_lighting.h @@ -168,6 +168,8 @@ struct LightingRegs { union { BitField<0, 1, u32> directional; BitField<1, 1, u32> two_sided_diffuse; // When disabled, clamp dot-product to 0 + BitField<2, 1, u32> geometric_factor_0; + BitField<3, 1, u32> geometric_factor_1; } config; BitField<0, 20, u32> dist_atten_bias; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 14be1201f..04e7cb0c4 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -73,6 +73,8 @@ PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) { state.lighting.light[light_index].num = num; state.lighting.light[light_index].directional = light.config.directional != 0; state.lighting.light[light_index].two_sided_diffuse = light.config.two_sided_diffuse != 0; + state.lighting.light[light_index].geometric_factor_0 = light.config.geometric_factor_0 != 0; + state.lighting.light[light_index].geometric_factor_1 = light.config.geometric_factor_1 != 0; state.lighting.light[light_index].dist_atten_enable = !regs.lighting.IsDistAttenDisabled(num); state.lighting.light[light_index].spot_atten_enable = @@ -518,7 +520,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { "vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);\n" "vec3 light_vector = vec3(0.0);\n" "vec3 refl_value = vec3(0.0);\n" - "vec3 spot_dir = vec3(0.0);\n;"; + "vec3 spot_dir = vec3(0.0);\n" + "float geo_factor = 1.0;\n"; // Compute fragment normals and tangents const std::string pertubation = @@ -671,6 +674,12 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { std::string clamp_highlights = lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; + if (light_config.geometric_factor_0 || light_config.geometric_factor_1) { + out += "geo_factor = 1 + dot(light_vector, normalize(view));\n" + "geo_factor = geo_factor == 0.0 ? 0.0 : min(0.5 * " + + dot_product + " / geo_factor, 1.0);\n"; + } + // Specular 0 component std::string d0_lut_value = "1.0"; if (lighting.lut_d0.enable && @@ -683,6 +692,9 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { GetLutValue(LightingRegs::LightingSampler::Distribution0, index) + ")"; } std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; + if (light_config.geometric_factor_0) { + specular_0 = "(" + specular_0 + " * geo_factor)"; + } // If enabled, lookup ReflectRed value, otherwise, 1.0 is used if (lighting.lut_rr.enable && @@ -738,6 +750,9 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { } std::string specular_1 = "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; + if (light_config.geometric_factor_1) { + specular_1 = "(" + specular_1 + " * geo_factor)"; + } // Fresnel if (lighting.lut_fr.enable && diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index 9c90eadf9..2302ae453 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -94,6 +94,8 @@ union PicaShaderConfig { bool two_sided_diffuse; bool dist_atten_enable; bool spot_atten_enable; + bool geometric_factor_0; + bool geometric_factor_1; } light[8]; bool enable; From 5a454173a875c52a00850b2f1f080c183e5e7936 Mon Sep 17 00:00:00 2001 From: wwylele Date: Sun, 18 Jun 2017 10:17:12 +0300 Subject: [PATCH 2/2] gl_rasterizer/lighting: use the formula from the paper for germetic factor --- src/video_core/renderer_opengl/gl_shader_gen.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 04e7cb0c4..540cbb9d0 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -521,6 +521,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { "vec3 light_vector = vec3(0.0);\n" "vec3 refl_value = vec3(0.0);\n" "vec3 spot_dir = vec3(0.0);\n" + "vec3 half_vector = vec3(0.0);\n" "float geo_factor = 1.0;\n"; // Compute fragment normals and tangents @@ -564,15 +565,14 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { // Gets the index into the specified lookup table for specular lighting auto GetLutIndex = [&lighting](unsigned light_num, LightingRegs::LightingLutInput input, bool abs) { - const std::string half_angle = "normalize(normalize(view) + light_vector)"; std::string index; switch (input) { case LightingRegs::LightingLutInput::NH: - index = "dot(normal, " + half_angle + ")"; + index = "dot(normal, normalize(half_vector))"; break; case LightingRegs::LightingLutInput::VH: - index = std::string("dot(normalize(view), " + half_angle + ")"); + index = std::string("dot(normalize(view), normalize(half_vector))"); break; case LightingRegs::LightingLutInput::NV: @@ -593,9 +593,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { // Note: even if the normal vector is modified by normal map, which is not the // normal of the tangent plane anymore, the half angle vector is still projected // using the modified normal vector. - std::string half_angle_proj = half_angle + - " - normal / dot(normal, normal) * dot(normal, " + - half_angle + ")"; + std::string half_angle_proj = "normalize(half_vector) - normal / dot(normal, " + "normal) * dot(normal, normalize(half_vector))"; // Note: the half angle vector projection is confirmed not normalized before the dot // product. The result is in fact not cos(phi) as the name suggested. index = "dot(" + half_angle_proj + ", tangent)"; @@ -641,6 +640,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { out += "light_vector = normalize(" + light_src + ".position + view);\n"; out += "spot_dir = " + light_src + ".spot_direction;\n"; + out += "half_vector = normalize(view) + light_vector;\n"; // Compute dot product of light_vector and normal, adjust if lighting is one-sided or // two-sided @@ -675,8 +675,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; if (light_config.geometric_factor_0 || light_config.geometric_factor_1) { - out += "geo_factor = 1 + dot(light_vector, normalize(view));\n" - "geo_factor = geo_factor == 0.0 ? 0.0 : min(0.5 * " + + out += "geo_factor = dot(half_vector, half_vector);\n" + "geo_factor = geo_factor == 0.0 ? 0.0 : min(" + dot_product + " / geo_factor, 1.0);\n"; }