summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-11-18 22:36:01 -0500
committerGravatar bunnei2016-02-05 17:17:33 -0500
commit76f303538b8fd5c4bed1f5878058fb4c18fb045f (patch)
tree54d6a90fc8286aabb7844e4a028cef2781dc1367 /src
parentgl_shader_gen: Fix directional lights. (diff)
downloadyuzu-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.cpp207
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
322static 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
321std::string GenerateFragmentShader(const PicaShaderConfig& config) { 426std::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);
358vec4 secondary_fragment_color = vec4(0.0); 463vec4 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) {