diff options
| author | 2015-11-14 23:23:08 -0500 | |
|---|---|---|
| committer | 2016-02-05 17:17:30 -0500 | |
| commit | bf89870437ebb0d983cfc20c3ac0490169f59f44 (patch) | |
| tree | 8bf0f8121c02e66fd5aeeff8cacb7e288c84ae90 /src | |
| parent | renderer_opengl: Implement HW fragment lighting distance attenuation. (diff) | |
| download | yuzu-bf89870437ebb0d983cfc20c3ac0490169f59f44.tar.gz yuzu-bf89870437ebb0d983cfc20c3ac0490169f59f44.tar.xz yuzu-bf89870437ebb0d983cfc20c3ac0490169f59f44.zip | |
renderer_opengl: Initial implementation of basic specular lighting.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/pica.h | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 68 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 20 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 82 |
4 files changed, 165 insertions, 13 deletions
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index aad9effdc..c63d87a36 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -659,6 +659,8 @@ struct Regs { | |||
| 659 | 659 | ||
| 660 | enum class LightingLutInput { | 660 | enum class LightingLutInput { |
| 661 | NH = 0, // Cosine of the angle between the normal and half-angle vectors | 661 | NH = 0, // Cosine of the angle between the normal and half-angle vectors |
| 662 | VH = 1, // Cosine of the angle between the view and half-angle vectors | ||
| 663 | NV = 2, // Cosine of the angle between the normal and the view vector | ||
| 662 | LN = 3, // Cosine of the angle between the light and the normal vectors | 664 | LN = 3, // Cosine of the angle between the light and the normal vectors |
| 663 | }; | 665 | }; |
| 664 | 666 | ||
| @@ -709,7 +711,11 @@ struct Regs { | |||
| 709 | LightColor global_ambient; // emission + (material.ambient * lighting.ambient) | 711 | LightColor global_ambient; // emission + (material.ambient * lighting.ambient) |
| 710 | INSERT_PADDING_WORDS(0x1); | 712 | INSERT_PADDING_WORDS(0x1); |
| 711 | BitField<0, 3, u32> src_num; // number of enabled lights - 1 | 713 | BitField<0, 3, u32> src_num; // number of enabled lights - 1 |
| 712 | INSERT_PADDING_WORDS(0x1); | 714 | |
| 715 | union { | ||
| 716 | BitField< 4, 4, u32> config; | ||
| 717 | BitField<27, 1, u32> clamp_highlights; | ||
| 718 | } light_env; | ||
| 713 | 719 | ||
| 714 | union { | 720 | union { |
| 715 | // Each bit specifies whether distance attenuation should be applied for the | 721 | // Each bit specifies whether distance attenuation should be applied for the |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 80693fa29..c6fb37c53 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -297,6 +297,58 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 297 | SyncCombinerColor(); | 297 | SyncCombinerColor(); |
| 298 | break; | 298 | break; |
| 299 | 299 | ||
| 300 | // Fragment lighting specular 0 color | ||
| 301 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_0, 0x140 + 0 * 0x10): | ||
| 302 | SyncLightSpecular0(0); | ||
| 303 | break; | ||
| 304 | case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_0, 0x140 + 1 * 0x10): | ||
| 305 | SyncLightSpecular0(1); | ||
| 306 | break; | ||
| 307 | case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_0, 0x140 + 2 * 0x10): | ||
| 308 | SyncLightSpecular0(2); | ||
| 309 | break; | ||
| 310 | case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_0, 0x140 + 3 * 0x10): | ||
| 311 | SyncLightSpecular0(3); | ||
| 312 | break; | ||
| 313 | case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_0, 0x140 + 4 * 0x10): | ||
| 314 | SyncLightSpecular0(4); | ||
| 315 | break; | ||
| 316 | case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_0, 0x140 + 5 * 0x10): | ||
| 317 | SyncLightSpecular0(5); | ||
| 318 | break; | ||
| 319 | case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_0, 0x140 + 6 * 0x10): | ||
| 320 | SyncLightSpecular0(6); | ||
| 321 | break; | ||
| 322 | case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_0, 0x140 + 7 * 0x10): | ||
| 323 | SyncLightSpecular0(7); | ||
| 324 | break; | ||
| 325 | |||
| 326 | // Fragment lighting specular 1 color | ||
| 327 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_1, 0x141 + 0 * 0x10): | ||
| 328 | SyncLightSpecular1(0); | ||
| 329 | break; | ||
| 330 | case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_1, 0x141 + 1 * 0x10): | ||
| 331 | SyncLightSpecular1(1); | ||
| 332 | break; | ||
| 333 | case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_1, 0x141 + 2 * 0x10): | ||
| 334 | SyncLightSpecular1(2); | ||
| 335 | break; | ||
| 336 | case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_1, 0x141 + 3 * 0x10): | ||
| 337 | SyncLightSpecular1(3); | ||
| 338 | break; | ||
| 339 | case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_1, 0x141 + 4 * 0x10): | ||
| 340 | SyncLightSpecular1(4); | ||
| 341 | break; | ||
| 342 | case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_1, 0x141 + 5 * 0x10): | ||
| 343 | SyncLightSpecular1(5); | ||
| 344 | break; | ||
| 345 | case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_1, 0x141 + 6 * 0x10): | ||
| 346 | SyncLightSpecular1(6); | ||
| 347 | break; | ||
| 348 | case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_1, 0x141 + 7 * 0x10): | ||
| 349 | SyncLightSpecular1(7); | ||
| 350 | break; | ||
| 351 | |||
| 300 | // Fragment lighting diffuse color | 352 | // Fragment lighting diffuse color |
| 301 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].diffuse, 0x142 + 0 * 0x10): | 353 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].diffuse, 0x142 + 0 * 0x10): |
| 302 | SyncLightDiffuse(0); | 354 | SyncLightDiffuse(0); |
| @@ -835,6 +887,22 @@ void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { | |||
| 835 | } | 887 | } |
| 836 | } | 888 | } |
| 837 | 889 | ||
| 890 | void RasterizerOpenGL::SyncLightSpecular0(int light_index) { | ||
| 891 | auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_0); | ||
| 892 | if (color != uniform_block_data.data.light_src[light_index].specular_0) { | ||
| 893 | uniform_block_data.data.light_src[light_index].specular_0 = color; | ||
| 894 | uniform_block_data.dirty = true; | ||
| 895 | } | ||
| 896 | } | ||
| 897 | |||
| 898 | void RasterizerOpenGL::SyncLightSpecular1(int light_index) { | ||
| 899 | auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_1); | ||
| 900 | if (color != uniform_block_data.data.light_src[light_index].specular_1) { | ||
| 901 | uniform_block_data.data.light_src[light_index].specular_1 = color; | ||
| 902 | uniform_block_data.dirty = true; | ||
| 903 | } | ||
| 904 | } | ||
| 905 | |||
| 838 | void RasterizerOpenGL::SyncLightDiffuse(int light_index) { | 906 | void RasterizerOpenGL::SyncLightDiffuse(int light_index) { |
| 839 | auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].diffuse); | 907 | auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].diffuse); |
| 840 | if (color != uniform_block_data.data.light_src[light_index].diffuse) { | 908 | if (color != uniform_block_data.data.light_src[light_index].diffuse) { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index ba0b05802..9e93b8b2f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -87,6 +87,10 @@ struct PicaShaderConfig { | |||
| 87 | res.light_src[light_index].dist_atten_scale = Pica::float20::FromRawFloat20(light.dist_atten_scale).ToFloat32(); | 87 | res.light_src[light_index].dist_atten_scale = Pica::float20::FromRawFloat20(light.dist_atten_scale).ToFloat32(); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | res.lighting_lut.d0_abs = (regs.lighting.abs_lut_input.d0 == 0); | ||
| 91 | res.lighting_lut.d0_type = (Pica::Regs::LightingLutInput)regs.lighting.lut_input.d0.Value(); | ||
| 92 | res.clamp_highlights = regs.lighting.light_env.clamp_highlights; | ||
| 93 | |||
| 90 | return res; | 94 | return res; |
| 91 | } | 95 | } |
| 92 | 96 | ||
| @@ -118,6 +122,12 @@ struct PicaShaderConfig { | |||
| 118 | 122 | ||
| 119 | bool lighting_enabled = false; | 123 | bool lighting_enabled = false; |
| 120 | unsigned num_lights = 0; | 124 | unsigned num_lights = 0; |
| 125 | bool clamp_highlights = false; | ||
| 126 | |||
| 127 | struct { | ||
| 128 | bool d0_abs = false; | ||
| 129 | Pica::Regs::LightingLutInput d0_type = Pica::Regs::LightingLutInput::NH; | ||
| 130 | } lighting_lut; | ||
| 121 | }; | 131 | }; |
| 122 | }; | 132 | }; |
| 123 | 133 | ||
| @@ -231,6 +241,10 @@ private: | |||
| 231 | }; | 241 | }; |
| 232 | 242 | ||
| 233 | struct LightSrc { | 243 | struct LightSrc { |
| 244 | std::array<GLfloat, 3> specular_0; | ||
| 245 | INSERT_PADDING_WORDS(1); | ||
| 246 | std::array<GLfloat, 3> specular_1; | ||
| 247 | INSERT_PADDING_WORDS(1); | ||
| 234 | std::array<GLfloat, 3> diffuse; | 248 | std::array<GLfloat, 3> diffuse; |
| 235 | INSERT_PADDING_WORDS(1); | 249 | INSERT_PADDING_WORDS(1); |
| 236 | std::array<GLfloat, 3> ambient; | 250 | std::array<GLfloat, 3> ambient; |
| @@ -316,6 +330,12 @@ private: | |||
| 316 | /// Syncs the specified light's position to match the PICA register | 330 | /// Syncs the specified light's position to match the PICA register |
| 317 | void SyncLightPosition(int light_index); | 331 | void SyncLightPosition(int light_index); |
| 318 | 332 | ||
| 333 | /// Syncs the specified light's specular 0 color to match the PICA register | ||
| 334 | void SyncLightSpecular0(int light_index); | ||
| 335 | |||
| 336 | /// Syncs the specified light's specular 1 color to match the PICA register | ||
| 337 | void SyncLightSpecular1(int light_index); | ||
| 338 | |||
| 319 | /// Syncs the remaining OpenGL drawing state to match the current PICA state | 339 | /// Syncs the remaining OpenGL drawing state to match the current PICA state |
| 320 | void SyncDrawState(); | 340 | void SyncDrawState(); |
| 321 | 341 | ||
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, | |||
| 35 | out += "primary_fragment_color"; | 35 | out += "primary_fragment_color"; |
| 36 | break; | 36 | break; |
| 37 | case Source::SecondaryFragmentColor: | 37 | case Source::SecondaryFragmentColor: |
| 38 | // HACK: Until we implement fragment lighting, use zero | 38 | out += "secondary_fragment_color"; |
| 39 | out += "vec4(0.0)"; | ||
| 40 | break; | 39 | break; |
| 41 | case Source::Texture0: | 40 | case Source::Texture0: |
| 42 | out += "texture(tex[0], texcoord[0])"; | 41 | out += "texture(tex[0], texcoord[0])"; |
| @@ -334,6 +333,8 @@ in vec3 view; | |||
| 334 | out vec4 color; | 333 | out vec4 color; |
| 335 | 334 | ||
| 336 | struct LightSrc { | 335 | struct LightSrc { |
| 336 | vec3 specular_0; | ||
| 337 | vec3 specular_1; | ||
| 337 | vec3 diffuse; | 338 | vec3 diffuse; |
| 338 | vec3 ambient; | 339 | vec3 ambient; |
| 339 | vec3 position; | 340 | vec3 position; |
| @@ -358,6 +359,7 @@ uniform sampler2D tex[3]; | |||
| 358 | 359 | ||
| 359 | void main() { | 360 | void main() { |
| 360 | vec4 primary_fragment_color = vec4(0.0); | 361 | vec4 primary_fragment_color = vec4(0.0); |
| 362 | vec4 secondary_fragment_color = vec4(0.0); | ||
| 361 | )"; | 363 | )"; |
| 362 | 364 | ||
| 363 | if (config.lighting_enabled) { | 365 | if (config.lighting_enabled) { |
| @@ -367,41 +369,97 @@ vec4 primary_fragment_color = vec4(0.0); | |||
| 367 | out += " 1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n"; | 369 | out += " 1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n"; |
| 368 | out += "vec4 secondary_color = vec4(0.0);\n"; | 370 | out += "vec4 secondary_color = vec4(0.0);\n"; |
| 369 | out += "vec3 diffuse_sum = vec3(0.0);\n"; | 371 | out += "vec3 diffuse_sum = vec3(0.0);\n"; |
| 372 | out += "vec3 specular_sum = vec3(0.0);\n"; | ||
| 370 | out += "vec3 fragment_position = -view;\n"; | 373 | out += "vec3 fragment_position = -view;\n"; |
| 374 | out += "vec3 light_vector = vec3(0.0);\n"; | ||
| 375 | out += "float dist_atten = 1.0;\n"; | ||
| 376 | |||
| 377 | // Gets the index into the specified lookup table for specular lighting | ||
| 378 | auto GetLutIndex = [&](unsigned light_num, Regs::LightingLutInput input, bool abs) { | ||
| 379 | const std::string half_angle = "normalize(view + light_vector)"; | ||
| 380 | std::string index; | ||
| 381 | switch (input) { | ||
| 382 | case Regs::LightingLutInput::NH: | ||
| 383 | index = "dot(normal, " + half_angle + ")"; | ||
| 384 | break; | ||
| 385 | |||
| 386 | case Regs::LightingLutInput::VH: | ||
| 387 | index = std::string("dot(view, " + half_angle + ")"); | ||
| 388 | break; | ||
| 389 | |||
| 390 | case Regs::LightingLutInput::NV: | ||
| 391 | index = std::string("dot(normal, view)"); | ||
| 392 | break; | ||
| 393 | |||
| 394 | case Regs::LightingLutInput::LN: | ||
| 395 | index = std::string("dot(light_vector, normal)"); | ||
| 396 | break; | ||
| 397 | |||
| 398 | default: | ||
| 399 | LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input); | ||
| 400 | UNIMPLEMENTED(); | ||
| 401 | break; | ||
| 402 | } | ||
| 403 | |||
| 404 | if (abs) { | ||
| 405 | // In the range of [ 0.f, 1.f] | ||
| 406 | index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; | ||
| 407 | return "clamp(int(" + index + " * 256.0), 0, 255)"; | ||
| 408 | } else { | ||
| 409 | // In the range of [-1.f, 1.f] | ||
| 410 | index = "clamp(" + index + ", -1.0, 1.0)"; | ||
| 411 | return std::string("uint(int(" + index + " * 127.f) & 0xff)"); | ||
| 412 | } | ||
| 413 | |||
| 414 | return std::string(); | ||
| 415 | }; | ||
| 371 | 416 | ||
| 372 | for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) { | 417 | for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) { |
| 373 | unsigned num = config.light_src[light_index].num; | 418 | unsigned num = config.light_src[light_index].num; |
| 374 | std::string light_src = "light_src[" + std::to_string(num) + "]"; | 419 | std::string light_src = "light_src[" + std::to_string(num) + "]"; |
| 375 | 420 | ||
| 376 | std::string light_vector; | ||
| 377 | if (config.light_src[light_index].directional) | 421 | if (config.light_src[light_index].directional) |
| 378 | light_vector = "normalize(-" + light_src + ".position)"; | 422 | out += "light_vector = normalize(-" + light_src + ".position);\n"; |
| 379 | else | 423 | else |
| 380 | light_vector = "normalize(" + light_src + ".position - fragment_position)"; | 424 | out += "light_vector = normalize(" + light_src + ".position - fragment_position);\n"; |
| 381 | 425 | ||
| 382 | std::string dot_product; | 426 | std::string dot_product; |
| 383 | if (config.light_src[light_index].two_sided_diffuse) | 427 | if (config.light_src[light_index].two_sided_diffuse) |
| 384 | dot_product = "abs(dot(" + light_vector + ", normal))"; | 428 | dot_product = "abs(dot(light_vector, normal))"; |
| 385 | else | 429 | else |
| 386 | dot_product = "max(dot(" + light_vector + ", normal), 0.0)"; | 430 | dot_product = "max(dot(light_vector, normal), 0.0)"; |
| 387 | 431 | ||
| 388 | std::string dist_atten = "1.0"; | 432 | // Compute distance attenuation value |
| 433 | out += "dist_atten = 1.0;\n"; | ||
| 389 | if (config.light_src[light_index].dist_atten_enabled) { | 434 | if (config.light_src[light_index].dist_atten_enabled) { |
| 390 | std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale); | 435 | std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale); |
| 391 | std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias); | 436 | std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias); |
| 392 | std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")"; | 437 | std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")"; |
| 393 | std::string clamped_lut_index = "((clamp(int(" + lut_index + " * 256.0), 0, 255)))"; | 438 | std::string clamped_lut_index = "((clamp(int(" + lut_index + " * 256.0), 0, 255)))"; |
| 394 | 439 | ||
| 395 | unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); | 440 | const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); |
| 396 | 441 | out += "dist_atten = lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "];\n"; | |
| 397 | dist_atten = "lighting_lut_" + std::to_string(lut_num /4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "]"; | ||
| 398 | } | 442 | } |
| 399 | 443 | ||
| 400 | out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * " + dist_atten + ";\n"; | 444 | // Compute primary fragment color (diffuse lighting) function |
| 445 | out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * dist_atten;\n"; | ||
| 446 | |||
| 447 | // Compute secondary fragment color (specular lighting) function | ||
| 448 | std::string clamped_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs); | ||
| 449 | const unsigned lut_num = (unsigned)Regs::LightingSampler::Distribution0; | ||
| 450 | std::string lut_lookup = "lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "]"; | ||
| 451 | |||
| 452 | out += "specular_sum += (" + lut_lookup + " * light_src[" + std::to_string(num) + "].specular_0 * dist_atten);\n"; | ||
| 453 | } | ||
| 454 | |||
| 455 | out += "float clamp_highlights = 1.0;\n"; | ||
| 456 | if (config.clamp_highlights) { | ||
| 457 | out += "if (dot(light_vector, normal) <= 0.0) clamp_highlights = 0.0;\n"; | ||
| 401 | } | 458 | } |
| 402 | 459 | ||
| 403 | out += "diffuse_sum += lighting_global_ambient;\n"; | 460 | out += "diffuse_sum += lighting_global_ambient;\n"; |
| 404 | out += "primary_fragment_color = vec4(clamp(diffuse_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; | 461 | out += "primary_fragment_color = vec4(clamp(diffuse_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; |
| 462 | out += "secondary_fragment_color = vec4(clamp(clamp_highlights * specular_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; | ||
| 405 | } | 463 | } |
| 406 | 464 | ||
| 407 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test | 465 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test |