diff options
| author | 2015-11-18 22:36:01 -0500 | |
|---|---|---|
| committer | 2016-02-05 17:17:33 -0500 | |
| commit | 76f303538b8fd5c4bed1f5878058fb4c18fb045f (patch) | |
| tree | 54d6a90fc8286aabb7844e4a028cef2781dc1367 /src | |
| parent | gl_shader_gen: Fix directional lights. (diff) | |
| download | yuzu-76f303538b8fd5c4bed1f5878058fb4c18fb045f.tar.gz yuzu-76f303538b8fd5c4bed1f5878058fb4c18fb045f.tar.xz yuzu-76f303538b8fd5c4bed1f5878058fb4c18fb045f.zip | |
gl_shader_gen: Reorganize and cleanup lighting code.
- No functional difference.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 207 |
1 files changed, 107 insertions, 100 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 8bc8e2b36..10cb2d065 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -318,6 +318,111 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi | |||
| 318 | out += "next_combiner_buffer.a = last_tex_env_out.a;\n"; | 318 | out += "next_combiner_buffer.a = last_tex_env_out.a;\n"; |
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | /// Writes the code to emulate fragment lighting | ||
| 322 | static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | ||
| 323 | // Define lighting globals | ||
| 324 | out += "vec3 diffuse_sum = vec3(0.0);\n"; | ||
| 325 | out += "vec3 specular_sum = vec3(0.0);\n"; | ||
| 326 | out += "vec3 light_vector = vec3(0.0);\n"; | ||
| 327 | |||
| 328 | // Convert interpolated quaternion to a GL fragment normal | ||
| 329 | out += "vec3 normal = normalize(vec3(\n"; | ||
| 330 | out += " 2.f*(normquat.x*normquat.z + normquat.y*normquat.w),\n"; | ||
| 331 | out += " 2.f*(normquat.y*normquat.z + normquat.x*normquat.w),\n"; | ||
| 332 | out += " 1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n"; | ||
| 333 | |||
| 334 | // Gets the index into the specified lookup table for specular lighting | ||
| 335 | auto GetLutIndex = [config](unsigned light_num, Regs::LightingLutInput input, bool abs) { | ||
| 336 | const std::string half_angle = "normalize(normalize(view) + light_vector)"; | ||
| 337 | std::string index; | ||
| 338 | switch (input) { | ||
| 339 | case Regs::LightingLutInput::NH: | ||
| 340 | index = "dot(normal, " + half_angle + ")"; | ||
| 341 | break; | ||
| 342 | |||
| 343 | case Regs::LightingLutInput::VH: | ||
| 344 | index = std::string("dot(view, " + half_angle + ")"); | ||
| 345 | break; | ||
| 346 | |||
| 347 | case Regs::LightingLutInput::NV: | ||
| 348 | index = std::string("dot(normal, view)"); | ||
| 349 | break; | ||
| 350 | |||
| 351 | case Regs::LightingLutInput::LN: | ||
| 352 | index = std::string("dot(light_vector, normal)"); | ||
| 353 | break; | ||
| 354 | |||
| 355 | default: | ||
| 356 | LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input); | ||
| 357 | UNIMPLEMENTED(); | ||
| 358 | break; | ||
| 359 | } | ||
| 360 | |||
| 361 | if (abs) { | ||
| 362 | // LUT index is in the range of (0.0, 1.0) | ||
| 363 | index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; | ||
| 364 | return "clamp(" + index + ", 0.0, FLOAT_255)"; | ||
| 365 | } else { | ||
| 366 | // LUT index is in the range of (-1.0, 1.0) | ||
| 367 | index = "clamp(" + index + ", -1.0, 1.0)"; | ||
| 368 | return "clamp(((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0, 0.0, FLOAT_255)"; | ||
| 369 | } | ||
| 370 | |||
| 371 | return std::string(); | ||
| 372 | }; | ||
| 373 | |||
| 374 | // Gets the lighting lookup table value given the specified sampler and index | ||
| 375 | auto GetLutValue = [](Regs::LightingSampler sampler, std::string lut_index) { | ||
| 376 | return std::string("texture(lut[" + std::to_string((unsigned)sampler / 4) + "], " + | ||
| 377 | lut_index + ")[" + std::to_string((unsigned)sampler & 3) + "]"); | ||
| 378 | }; | ||
| 379 | |||
| 380 | // Write the code to emulate each enabled light | ||
| 381 | for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) { | ||
| 382 | unsigned num = config.light_src[light_index].num; | ||
| 383 | const auto& light_config = config.light_src[light_index]; | ||
| 384 | std::string light_src = "light_src[" + std::to_string(num) + "]"; | ||
| 385 | |||
| 386 | // Compute light vector (directional or positional) | ||
| 387 | if (light_config.directional) | ||
| 388 | out += "light_vector = normalize(" + light_src + ".position);\n"; | ||
| 389 | else | ||
| 390 | out += "light_vector = normalize(" + light_src + ".position + view);\n"; | ||
| 391 | |||
| 392 | // Compute dot product of light_vector and normal, adjust if lighting is one-sided or two-sided | ||
| 393 | std::string dot_product = light_config.two_sided_diffuse ? "abs(dot(light_vector, normal))" : "max(dot(light_vector, normal), 0.0)"; | ||
| 394 | |||
| 395 | // If enabled, compute distance attenuation value | ||
| 396 | std::string dist_atten = "1.0"; | ||
| 397 | if (light_config.dist_atten_enabled) { | ||
| 398 | std::string scale = std::to_string(light_config.dist_atten_scale); | ||
| 399 | std::string bias = std::to_string(light_config.dist_atten_bias); | ||
| 400 | std::string lut_index = "(" + scale + " * length(-view - " + light_src + ".position) + " + bias + ")"; | ||
| 401 | lut_index = "((clamp(" + lut_index + ", 0.0, FLOAT_255)))"; | ||
| 402 | const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); | ||
| 403 | dist_atten = GetLutValue((Regs::LightingSampler)lut_num, lut_index); | ||
| 404 | } | ||
| 405 | |||
| 406 | // Compute primary fragment color (diffuse lighting) function | ||
| 407 | out += "diffuse_sum += ((" + light_src + ".diffuse * " + dot_product + ") + " + light_src + ".ambient) * " + dist_atten + ";\n"; | ||
| 408 | |||
| 409 | // If enabled, clamp specular component if lighting result is negative | ||
| 410 | std::string clamp_highlights = config.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; | ||
| 411 | |||
| 412 | // Lookup specular distribution 0 LUT value | ||
| 413 | std::string d0_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs); | ||
| 414 | std::string d0_lut_value = GetLutValue(Regs::LightingSampler::Distribution0, d0_lut_index); | ||
| 415 | |||
| 416 | // Compute secondary fragment color (specular lighting) function | ||
| 417 | out += "specular_sum += " + clamp_highlights + " * " + d0_lut_value + " * " + light_src + ".specular_0 * " + dist_atten + ";\n"; | ||
| 418 | } | ||
| 419 | |||
| 420 | // Sum final lighting result | ||
| 421 | out += "diffuse_sum += lighting_global_ambient;\n"; | ||
| 422 | out += "primary_fragment_color = vec4(clamp(diffuse_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; | ||
| 423 | out += "secondary_fragment_color = vec4(clamp(specular_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; | ||
| 424 | } | ||
| 425 | |||
| 321 | std::string GenerateFragmentShader(const PicaShaderConfig& config) { | 426 | std::string GenerateFragmentShader(const PicaShaderConfig& config) { |
| 322 | std::string out = R"( | 427 | std::string out = R"( |
| 323 | #version 330 core | 428 | #version 330 core |
| @@ -358,106 +463,8 @@ vec4 primary_fragment_color = vec4(0.0); | |||
| 358 | vec4 secondary_fragment_color = vec4(0.0); | 463 | vec4 secondary_fragment_color = vec4(0.0); |
| 359 | )"; | 464 | )"; |
| 360 | 465 | ||
| 361 | if (config.lighting_enabled) { | 466 | if (config.lighting_enabled) |
| 362 | out += "vec3 normal = normalize(vec3(\n"; | 467 | WriteLighting(out, config); |
| 363 | out += " 2.f*(normquat.x*normquat.z + normquat.y*normquat.w),\n"; | ||
| 364 | out += " 2.f*(normquat.y*normquat.z + normquat.x*normquat.w),\n"; | ||
| 365 | out += " 1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n"; | ||
| 366 | out += "vec4 secondary_color = vec4(0.0);\n"; | ||
| 367 | out += "vec3 diffuse_sum = vec3(0.0);\n"; | ||
| 368 | out += "vec3 specular_sum = vec3(0.0);\n"; | ||
| 369 | out += "vec3 fragment_position = -view;\n"; | ||
| 370 | out += "vec3 light_vector = vec3(0.0);\n"; | ||
| 371 | out += "vec3 half_angle_vector = vec3(0.0);\n"; | ||
| 372 | out += "float clamp_highlights = 1.0;\n"; | ||
| 373 | out += "float dist_atten = 1.0;\n"; | ||
| 374 | |||
| 375 | // Gets the index into the specified lookup table for specular lighting | ||
| 376 | auto GetLutIndex = [&](unsigned light_num, Regs::LightingLutInput input, bool abs) { | ||
| 377 | std::string index; | ||
| 378 | switch (input) { | ||
| 379 | case Regs::LightingLutInput::NH: | ||
| 380 | index = "dot(normal, half_angle_vector)"; | ||
| 381 | break; | ||
| 382 | |||
| 383 | case Regs::LightingLutInput::VH: | ||
| 384 | index = std::string("dot(view, half_angle_vector)"); | ||
| 385 | break; | ||
| 386 | |||
| 387 | case Regs::LightingLutInput::NV: | ||
| 388 | index = std::string("dot(normal, view)"); | ||
| 389 | break; | ||
| 390 | |||
| 391 | case Regs::LightingLutInput::LN: | ||
| 392 | index = std::string("dot(light_vector, normal)"); | ||
| 393 | break; | ||
| 394 | |||
| 395 | default: | ||
| 396 | LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input); | ||
| 397 | UNIMPLEMENTED(); | ||
| 398 | break; | ||
| 399 | } | ||
| 400 | |||
| 401 | if (abs) { | ||
| 402 | // In the range of [ 0.f, 1.f] | ||
| 403 | index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; | ||
| 404 | return "clamp(" + index + ", 0.0, FLOAT_255)"; | ||
| 405 | } else { | ||
| 406 | // In the range of [-1.f, 1.f] | ||
| 407 | index = "clamp(" + index + ", -1.0, 1.0)"; | ||
| 408 | return "clamp(((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0, 0.0, FLOAT_255)"; | ||
| 409 | } | ||
| 410 | |||
| 411 | return std::string(); | ||
| 412 | }; | ||
| 413 | |||
| 414 | for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) { | ||
| 415 | unsigned num = config.light_src[light_index].num; | ||
| 416 | std::string light_src = "light_src[" + std::to_string(num) + "]"; | ||
| 417 | |||
| 418 | if (config.light_src[light_index].directional) | ||
| 419 | out += "light_vector = normalize(" + light_src + ".position);\n"; | ||
| 420 | else | ||
| 421 | out += "light_vector = normalize(" + light_src + ".position - fragment_position);\n"; | ||
| 422 | |||
| 423 | std::string dot_product; | ||
| 424 | if (config.light_src[light_index].two_sided_diffuse) | ||
| 425 | dot_product = "abs(dot(light_vector, normal))"; | ||
| 426 | else | ||
| 427 | dot_product = "max(dot(light_vector, normal), 0.0)"; | ||
| 428 | |||
| 429 | // Compute distance attenuation value | ||
| 430 | out += "dist_atten = 1.0;\n"; | ||
| 431 | if (config.light_src[light_index].dist_atten_enabled) { | ||
| 432 | std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale); | ||
| 433 | std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias); | ||
| 434 | std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")"; | ||
| 435 | std::string clamped_lut_index = "((clamp(" + lut_index + ", 0.0, FLOAT_255)))"; | ||
| 436 | |||
| 437 | const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); | ||
| 438 | out += "dist_atten = texture(lut[" + std::to_string(lut_num / 4) + "], " + clamped_lut_index + ")[" + std::to_string(lut_num & 3) + "];\n"; | ||
| 439 | } | ||
| 440 | |||
| 441 | // Compute primary fragment color (diffuse lighting) function | ||
| 442 | out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * dist_atten;\n"; | ||
| 443 | |||
| 444 | // Compute secondary fragment color (specular lighting) function | ||
| 445 | out += "half_angle_vector = normalize(normalize(view) + light_vector);\n"; | ||
| 446 | std::string clamped_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs); | ||
| 447 | const unsigned lut_num = (unsigned)Regs::LightingSampler::Distribution0; | ||
| 448 | std::string lut_lookup = "texture(lut[" + std::to_string(lut_num / 4) + "], " + clamped_lut_index + ")[" + std::to_string(lut_num & 3) + "]"; | ||
| 449 | |||
| 450 | if (config.clamp_highlights) { | ||
| 451 | out += "clamp_highlights = (dot(light_vector, normal) <= 0.0) ? 0.0 : 1.0;\n"; | ||
| 452 | } | ||
| 453 | |||
| 454 | out += "specular_sum += clamp_highlights * " + lut_lookup + " * light_src[" + std::to_string(num) + "].specular_0 * dist_atten;\n"; | ||
| 455 | } | ||
| 456 | |||
| 457 | out += "diffuse_sum += lighting_global_ambient;\n"; | ||
| 458 | out += "primary_fragment_color = vec4(clamp(diffuse_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; | ||
| 459 | out += "secondary_fragment_color = vec4(clamp(specular_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; | ||
| 460 | } | ||
| 461 | 468 | ||
| 462 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test | 469 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test |
| 463 | if (config.alpha_test_func == Regs::CompareFunc::Never) { | 470 | if (config.alpha_test_func == Regs::CompareFunc::Never) { |