diff options
Diffstat (limited to 'src/video_core/renderer_opengl/gl_shader_gen.cpp')
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 82 |
1 files changed, 70 insertions, 12 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index cf99cff76..abcc89f1d 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -35,8 +35,7 @@ static void AppendSource(std::string& out, TevStageConfig::Source source, out += "primary_fragment_color"; break; case Source::SecondaryFragmentColor: - // HACK: Until we implement fragment lighting, use zero - out += "vec4(0.0)"; + out += "secondary_fragment_color"; break; case Source::Texture0: out += "texture(tex[0], texcoord[0])"; @@ -334,6 +333,8 @@ in vec3 view; out vec4 color; struct LightSrc { + vec3 specular_0; + vec3 specular_1; vec3 diffuse; vec3 ambient; vec3 position; @@ -358,6 +359,7 @@ uniform sampler2D tex[3]; void main() { vec4 primary_fragment_color = vec4(0.0); +vec4 secondary_fragment_color = vec4(0.0); )"; if (config.lighting_enabled) { @@ -367,41 +369,97 @@ vec4 primary_fragment_color = vec4(0.0); out += " 1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n"; out += "vec4 secondary_color = vec4(0.0);\n"; out += "vec3 diffuse_sum = vec3(0.0);\n"; + out += "vec3 specular_sum = vec3(0.0);\n"; out += "vec3 fragment_position = -view;\n"; + out += "vec3 light_vector = vec3(0.0);\n"; + out += "float dist_atten = 1.0;\n"; + + // Gets the index into the specified lookup table for specular lighting + auto GetLutIndex = [&](unsigned light_num, Regs::LightingLutInput input, bool abs) { + const std::string half_angle = "normalize(view + light_vector)"; + std::string index; + switch (input) { + case Regs::LightingLutInput::NH: + index = "dot(normal, " + half_angle + ")"; + break; + + case Regs::LightingLutInput::VH: + index = std::string("dot(view, " + half_angle + ")"); + break; + + case Regs::LightingLutInput::NV: + index = std::string("dot(normal, view)"); + break; + + case Regs::LightingLutInput::LN: + index = std::string("dot(light_vector, normal)"); + break; + + default: + LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input); + UNIMPLEMENTED(); + break; + } + + if (abs) { + // In the range of [ 0.f, 1.f] + index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; + return "clamp(int(" + index + " * 256.0), 0, 255)"; + } else { + // In the range of [-1.f, 1.f] + index = "clamp(" + index + ", -1.0, 1.0)"; + return std::string("uint(int(" + index + " * 127.f) & 0xff)"); + } + + return std::string(); + }; for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) { unsigned num = config.light_src[light_index].num; std::string light_src = "light_src[" + std::to_string(num) + "]"; - std::string light_vector; if (config.light_src[light_index].directional) - light_vector = "normalize(-" + light_src + ".position)"; + out += "light_vector = normalize(-" + light_src + ".position);\n"; else - light_vector = "normalize(" + light_src + ".position - fragment_position)"; + out += "light_vector = normalize(" + light_src + ".position - fragment_position);\n"; std::string dot_product; if (config.light_src[light_index].two_sided_diffuse) - dot_product = "abs(dot(" + light_vector + ", normal))"; + dot_product = "abs(dot(light_vector, normal))"; else - dot_product = "max(dot(" + light_vector + ", normal), 0.0)"; + dot_product = "max(dot(light_vector, normal), 0.0)"; - std::string dist_atten = "1.0"; + // Compute distance attenuation value + out += "dist_atten = 1.0;\n"; if (config.light_src[light_index].dist_atten_enabled) { std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale); std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias); std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")"; std::string clamped_lut_index = "((clamp(int(" + lut_index + " * 256.0), 0, 255)))"; - unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); - - dist_atten = "lighting_lut_" + std::to_string(lut_num /4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "]"; + const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); + out += "dist_atten = lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "];\n"; } - out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * " + dist_atten + ";\n"; + // Compute primary fragment color (diffuse lighting) function + out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * dist_atten;\n"; + + // Compute secondary fragment color (specular lighting) function + std::string clamped_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs); + const unsigned lut_num = (unsigned)Regs::LightingSampler::Distribution0; + std::string lut_lookup = "lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "]"; + + out += "specular_sum += (" + lut_lookup + " * light_src[" + std::to_string(num) + "].specular_0 * dist_atten);\n"; + } + + out += "float clamp_highlights = 1.0;\n"; + if (config.clamp_highlights) { + out += "if (dot(light_vector, normal) <= 0.0) clamp_highlights = 0.0;\n"; } out += "diffuse_sum += lighting_global_ambient;\n"; out += "primary_fragment_color = vec4(clamp(diffuse_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; + out += "secondary_fragment_color = vec4(clamp(clamp_highlights * specular_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; } // Do not do any sort of processing if it's obvious we're not going to pass the alpha test |