diff options
| author | 2017-06-11 18:23:47 +0000 | |
|---|---|---|
| committer | 2017-06-11 18:23:47 +0000 | |
| commit | 39c7c1f580a1c40a12e65b6c9c65215826e73efb (patch) | |
| tree | 75a2895b108e5460fee8695ebe5b91dbf59e9af2 /src | |
| parent | Remove unused import in break_points.cpp (#2763) (diff) | |
| parent | gl_rasterizer: implement spot light (diff) | |
| download | yuzu-39c7c1f580a1c40a12e65b6c9c65215826e73efb.tar.gz yuzu-39c7c1f580a1c40a12e65b6c9c65215826e73efb.tar.xz yuzu-39c7c1f580a1c40a12e65b6c9c65215826e73efb.zip | |
Merge pull request #2727 from wwylele/spot-light
Fragment lighting: implement spot light
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/regs_lighting.h | 63 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 45 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 39 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 3 |
5 files changed, 128 insertions, 28 deletions
diff --git a/src/video_core/regs_lighting.h b/src/video_core/regs_lighting.h index 6793405d9..fbfebc0a7 100644 --- a/src/video_core/regs_lighting.h +++ b/src/video_core/regs_lighting.h | |||
| @@ -26,6 +26,16 @@ struct LightingRegs { | |||
| 26 | DistanceAttenuation = 16, | 26 | DistanceAttenuation = 16, |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | static LightingSampler SpotlightAttenuationSampler(unsigned index) { | ||
| 30 | return static_cast<LightingSampler>( | ||
| 31 | static_cast<unsigned>(LightingSampler::SpotlightAttenuation) + index); | ||
| 32 | } | ||
| 33 | |||
| 34 | static LightingSampler DistanceAttenuationSampler(unsigned index) { | ||
| 35 | return static_cast<LightingSampler>( | ||
| 36 | static_cast<unsigned>(LightingSampler::DistanceAttenuation) + index); | ||
| 37 | } | ||
| 38 | |||
| 29 | /** | 39 | /** |
| 30 | * Pica fragment lighting supports using different LUTs for each lighting component: Reflectance | 40 | * Pica fragment lighting supports using different LUTs for each lighting component: Reflectance |
| 31 | * R, G, and B channels, distribution function for specular components 0 and 1, fresnel factor, | 41 | * R, G, and B channels, distribution function for specular components 0 and 1, fresnel factor, |
| @@ -73,6 +83,8 @@ struct LightingRegs { | |||
| 73 | VH = 1, // Cosine of the angle between the view and half-angle vectors | 83 | VH = 1, // Cosine of the angle between the view and half-angle vectors |
| 74 | NV = 2, // Cosine of the angle between the normal and the view vector | 84 | NV = 2, // Cosine of the angle between the normal and the view vector |
| 75 | LN = 3, // Cosine of the angle between the light and the normal vectors | 85 | LN = 3, // Cosine of the angle between the light and the normal vectors |
| 86 | SP = 4, // Cosine of the angle between the light and the inverse spotlight vectors | ||
| 87 | CP = 5, // TODO: document and implement | ||
| 76 | }; | 88 | }; |
| 77 | 89 | ||
| 78 | enum class LightingBumpMode : u32 { | 90 | enum class LightingBumpMode : u32 { |
| @@ -104,6 +116,9 @@ struct LightingRegs { | |||
| 104 | return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) && | 116 | return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) && |
| 105 | (config != LightingConfig::Config5); | 117 | (config != LightingConfig::Config5); |
| 106 | 118 | ||
| 119 | case LightingSampler::SpotlightAttenuation: | ||
| 120 | return (config != LightingConfig::Config2) && (config != LightingConfig::Config3); | ||
| 121 | |||
| 107 | case LightingSampler::Fresnel: | 122 | case LightingSampler::Fresnel: |
| 108 | return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) && | 123 | return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) && |
| 109 | (config != LightingConfig::Config4); | 124 | (config != LightingConfig::Config4); |
| @@ -116,11 +131,10 @@ struct LightingRegs { | |||
| 116 | return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) || | 131 | return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) || |
| 117 | (config == LightingConfig::Config7); | 132 | (config == LightingConfig::Config7); |
| 118 | default: | 133 | default: |
| 119 | UNREACHABLE_MSG("Regs::IsLightingSamplerSupported: Reached " | 134 | UNREACHABLE_MSG("Regs::IsLightingSamplerSupported: Reached unreachable section, " |
| 120 | "unreachable section, sampler should be one " | 135 | "sampler should be one of Distribution0, Distribution1, " |
| 121 | "of Distribution0, Distribution1, Fresnel, " | 136 | "SpotlightAttenuation, Fresnel, ReflectRed, ReflectGreen or " |
| 122 | "ReflectRed, ReflectGreen or ReflectBlue, instead " | 137 | "ReflectBlue, instead got %i", |
| 123 | "got %i", | ||
| 124 | static_cast<int>(config)); | 138 | static_cast<int>(config)); |
| 125 | } | 139 | } |
| 126 | } | 140 | } |
| @@ -140,7 +154,16 @@ struct LightingRegs { | |||
| 140 | BitField<0, 16, u32> z; | 154 | BitField<0, 16, u32> z; |
| 141 | }; | 155 | }; |
| 142 | 156 | ||
| 143 | INSERT_PADDING_WORDS(0x3); | 157 | // inverse spotlight direction vector, encoded as fixed1.1.11 |
| 158 | union { | ||
| 159 | BitField<0, 13, s32> spot_x; | ||
| 160 | BitField<16, 13, s32> spot_y; | ||
| 161 | }; | ||
| 162 | union { | ||
| 163 | BitField<0, 13, s32> spot_z; | ||
| 164 | }; | ||
| 165 | |||
| 166 | INSERT_PADDING_WORDS(0x1); | ||
| 144 | 167 | ||
| 145 | union { | 168 | union { |
| 146 | BitField<0, 1, u32> directional; | 169 | BitField<0, 1, u32> directional; |
| @@ -169,8 +192,16 @@ struct LightingRegs { | |||
| 169 | } config0; | 192 | } config0; |
| 170 | 193 | ||
| 171 | union { | 194 | union { |
| 195 | u32 raw; | ||
| 196 | |||
| 197 | // Each bit specifies whether spot light attenuation should be applied for the corresponding | ||
| 198 | // light. | ||
| 199 | BitField<8, 8, u32> disable_spot_atten; | ||
| 200 | |||
| 172 | BitField<16, 1, u32> disable_lut_d0; | 201 | BitField<16, 1, u32> disable_lut_d0; |
| 173 | BitField<17, 1, u32> disable_lut_d1; | 202 | BitField<17, 1, u32> disable_lut_d1; |
| 203 | // Note: by intuition, BitField<18, 1, u32> should be disable_lut_sp, but it is actually a | ||
| 204 | // dummy bit which is always set as 1. | ||
| 174 | BitField<19, 1, u32> disable_lut_fr; | 205 | BitField<19, 1, u32> disable_lut_fr; |
| 175 | BitField<20, 1, u32> disable_lut_rr; | 206 | BitField<20, 1, u32> disable_lut_rr; |
| 176 | BitField<21, 1, u32> disable_lut_rg; | 207 | BitField<21, 1, u32> disable_lut_rg; |
| @@ -178,23 +209,15 @@ struct LightingRegs { | |||
| 178 | 209 | ||
| 179 | // Each bit specifies whether distance attenuation should be applied for the corresponding | 210 | // Each bit specifies whether distance attenuation should be applied for the corresponding |
| 180 | // light. | 211 | // light. |
| 181 | BitField<24, 1, u32> disable_dist_atten_light_0; | 212 | BitField<24, 8, u32> disable_dist_atten; |
| 182 | BitField<25, 1, u32> disable_dist_atten_light_1; | ||
| 183 | BitField<26, 1, u32> disable_dist_atten_light_2; | ||
| 184 | BitField<27, 1, u32> disable_dist_atten_light_3; | ||
| 185 | BitField<28, 1, u32> disable_dist_atten_light_4; | ||
| 186 | BitField<29, 1, u32> disable_dist_atten_light_5; | ||
| 187 | BitField<30, 1, u32> disable_dist_atten_light_6; | ||
| 188 | BitField<31, 1, u32> disable_dist_atten_light_7; | ||
| 189 | } config1; | 213 | } config1; |
| 190 | 214 | ||
| 191 | bool IsDistAttenDisabled(unsigned index) const { | 215 | bool IsDistAttenDisabled(unsigned index) const { |
| 192 | const unsigned disable[] = { | 216 | return (config1.disable_dist_atten & (1 << index)) != 0; |
| 193 | config1.disable_dist_atten_light_0, config1.disable_dist_atten_light_1, | 217 | } |
| 194 | config1.disable_dist_atten_light_2, config1.disable_dist_atten_light_3, | 218 | |
| 195 | config1.disable_dist_atten_light_4, config1.disable_dist_atten_light_5, | 219 | bool IsSpotAttenDisabled(unsigned index) const { |
| 196 | config1.disable_dist_atten_light_6, config1.disable_dist_atten_light_7}; | 220 | return (config1.disable_spot_atten & (1 << index)) != 0; |
| 197 | return disable[index] != 0; | ||
| 198 | } | 221 | } |
| 199 | 222 | ||
| 200 | union { | 223 | union { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index aa9b831dd..57d5e8253 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -735,6 +735,40 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 735 | SyncLightPosition(7); | 735 | SyncLightPosition(7); |
| 736 | break; | 736 | break; |
| 737 | 737 | ||
| 738 | // Fragment spot lighting direction | ||
| 739 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].spot_x, 0x146 + 0 * 0x10): | ||
| 740 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].spot_z, 0x147 + 0 * 0x10): | ||
| 741 | SyncLightSpotDirection(0); | ||
| 742 | break; | ||
| 743 | case PICA_REG_INDEX_WORKAROUND(lighting.light[1].spot_x, 0x146 + 1 * 0x10): | ||
| 744 | case PICA_REG_INDEX_WORKAROUND(lighting.light[1].spot_z, 0x147 + 1 * 0x10): | ||
| 745 | SyncLightSpotDirection(1); | ||
| 746 | break; | ||
| 747 | case PICA_REG_INDEX_WORKAROUND(lighting.light[2].spot_x, 0x146 + 2 * 0x10): | ||
| 748 | case PICA_REG_INDEX_WORKAROUND(lighting.light[2].spot_z, 0x147 + 2 * 0x10): | ||
| 749 | SyncLightSpotDirection(2); | ||
| 750 | break; | ||
| 751 | case PICA_REG_INDEX_WORKAROUND(lighting.light[3].spot_x, 0x146 + 3 * 0x10): | ||
| 752 | case PICA_REG_INDEX_WORKAROUND(lighting.light[3].spot_z, 0x147 + 3 * 0x10): | ||
| 753 | SyncLightSpotDirection(3); | ||
| 754 | break; | ||
| 755 | case PICA_REG_INDEX_WORKAROUND(lighting.light[4].spot_x, 0x146 + 4 * 0x10): | ||
| 756 | case PICA_REG_INDEX_WORKAROUND(lighting.light[4].spot_z, 0x147 + 4 * 0x10): | ||
| 757 | SyncLightSpotDirection(4); | ||
| 758 | break; | ||
| 759 | case PICA_REG_INDEX_WORKAROUND(lighting.light[5].spot_x, 0x146 + 5 * 0x10): | ||
| 760 | case PICA_REG_INDEX_WORKAROUND(lighting.light[5].spot_z, 0x147 + 5 * 0x10): | ||
| 761 | SyncLightSpotDirection(5); | ||
| 762 | break; | ||
| 763 | case PICA_REG_INDEX_WORKAROUND(lighting.light[6].spot_x, 0x146 + 6 * 0x10): | ||
| 764 | case PICA_REG_INDEX_WORKAROUND(lighting.light[6].spot_z, 0x147 + 6 * 0x10): | ||
| 765 | SyncLightSpotDirection(6); | ||
| 766 | break; | ||
| 767 | case PICA_REG_INDEX_WORKAROUND(lighting.light[7].spot_x, 0x146 + 7 * 0x10): | ||
| 768 | case PICA_REG_INDEX_WORKAROUND(lighting.light[7].spot_z, 0x147 + 7 * 0x10): | ||
| 769 | SyncLightSpotDirection(7); | ||
| 770 | break; | ||
| 771 | |||
| 738 | // Fragment lighting light source config | 772 | // Fragment lighting light source config |
| 739 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].config, 0x149 + 0 * 0x10): | 773 | case PICA_REG_INDEX_WORKAROUND(lighting.light[0].config, 0x149 + 0 * 0x10): |
| 740 | case PICA_REG_INDEX_WORKAROUND(lighting.light[1].config, 0x149 + 1 * 0x10): | 774 | case PICA_REG_INDEX_WORKAROUND(lighting.light[1].config, 0x149 + 1 * 0x10): |
| @@ -1595,6 +1629,17 @@ void RasterizerOpenGL::SyncLightPosition(int light_index) { | |||
| 1595 | } | 1629 | } |
| 1596 | } | 1630 | } |
| 1597 | 1631 | ||
| 1632 | void RasterizerOpenGL::SyncLightSpotDirection(int light_index) { | ||
| 1633 | const auto& light = Pica::g_state.regs.lighting.light[light_index]; | ||
| 1634 | GLvec3 spot_direction = {light.spot_x / 2047.0f, light.spot_y / 2047.0f, | ||
| 1635 | light.spot_z / 2047.0f}; | ||
| 1636 | |||
| 1637 | if (spot_direction != uniform_block_data.data.light_src[light_index].spot_direction) { | ||
| 1638 | uniform_block_data.data.light_src[light_index].spot_direction = spot_direction; | ||
| 1639 | uniform_block_data.dirty = true; | ||
| 1640 | } | ||
| 1641 | } | ||
| 1642 | |||
| 1598 | void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) { | 1643 | void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) { |
| 1599 | GLfloat dist_atten_bias = | 1644 | GLfloat dist_atten_bias = |
| 1600 | Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias) | 1645 | Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias) |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index a9ad7d660..d9a3e9d1c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -125,6 +125,7 @@ private: | |||
| 125 | alignas(16) GLvec3 diffuse; | 125 | alignas(16) GLvec3 diffuse; |
| 126 | alignas(16) GLvec3 ambient; | 126 | alignas(16) GLvec3 ambient; |
| 127 | alignas(16) GLvec3 position; | 127 | alignas(16) GLvec3 position; |
| 128 | alignas(16) GLvec3 spot_direction; // negated | ||
| 128 | GLfloat dist_atten_bias; | 129 | GLfloat dist_atten_bias; |
| 129 | GLfloat dist_atten_scale; | 130 | GLfloat dist_atten_scale; |
| 130 | }; | 131 | }; |
| @@ -153,7 +154,7 @@ private: | |||
| 153 | }; | 154 | }; |
| 154 | 155 | ||
| 155 | static_assert( | 156 | static_assert( |
| 156 | sizeof(UniformData) == 0x3E0, | 157 | sizeof(UniformData) == 0x460, |
| 157 | "The size of the UniformData structure has changed, update the structure in the shader"); | 158 | "The size of the UniformData structure has changed, update the structure in the shader"); |
| 158 | static_assert(sizeof(UniformData) < 16384, | 159 | static_assert(sizeof(UniformData) < 16384, |
| 159 | "UniformData structure must be less than 16kb as per the OpenGL spec"); | 160 | "UniformData structure must be less than 16kb as per the OpenGL spec"); |
| @@ -241,6 +242,9 @@ private: | |||
| 241 | /// Syncs the specified light's position to match the PICA register | 242 | /// Syncs the specified light's position to match the PICA register |
| 242 | void SyncLightPosition(int light_index); | 243 | void SyncLightPosition(int light_index); |
| 243 | 244 | ||
| 245 | /// Syncs the specified spot light direcition to match the PICA register | ||
| 246 | void SyncLightSpotDirection(int light_index); | ||
| 247 | |||
| 244 | /// Syncs the specified light's distance attenuation bias to match the PICA register | 248 | /// Syncs the specified light's distance attenuation bias to match the PICA register |
| 245 | void SyncLightDistanceAttenuationBias(int light_index); | 249 | void SyncLightDistanceAttenuationBias(int light_index); |
| 246 | 250 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index ffe419863..db53710aa 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -75,6 +75,8 @@ PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) { | |||
| 75 | state.lighting.light[light_index].two_sided_diffuse = light.config.two_sided_diffuse != 0; | 75 | state.lighting.light[light_index].two_sided_diffuse = light.config.two_sided_diffuse != 0; |
| 76 | state.lighting.light[light_index].dist_atten_enable = | 76 | state.lighting.light[light_index].dist_atten_enable = |
| 77 | !regs.lighting.IsDistAttenDisabled(num); | 77 | !regs.lighting.IsDistAttenDisabled(num); |
| 78 | state.lighting.light[light_index].spot_atten_enable = | ||
| 79 | !regs.lighting.IsSpotAttenDisabled(num); | ||
| 78 | } | 80 | } |
| 79 | 81 | ||
| 80 | state.lighting.lut_d0.enable = regs.lighting.config1.disable_lut_d0 == 0; | 82 | state.lighting.lut_d0.enable = regs.lighting.config1.disable_lut_d0 == 0; |
| @@ -87,6 +89,12 @@ PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) { | |||
| 87 | state.lighting.lut_d1.type = regs.lighting.lut_input.d1.Value(); | 89 | state.lighting.lut_d1.type = regs.lighting.lut_input.d1.Value(); |
| 88 | state.lighting.lut_d1.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.d1); | 90 | state.lighting.lut_d1.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.d1); |
| 89 | 91 | ||
| 92 | // this is a dummy field due to lack of the corresponding register | ||
| 93 | state.lighting.lut_sp.enable = true; | ||
| 94 | state.lighting.lut_sp.abs_input = regs.lighting.abs_lut_input.disable_sp == 0; | ||
| 95 | state.lighting.lut_sp.type = regs.lighting.lut_input.sp.Value(); | ||
| 96 | state.lighting.lut_sp.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.sp); | ||
| 97 | |||
| 90 | state.lighting.lut_fr.enable = regs.lighting.config1.disable_lut_fr == 0; | 98 | state.lighting.lut_fr.enable = regs.lighting.config1.disable_lut_fr == 0; |
| 91 | state.lighting.lut_fr.abs_input = regs.lighting.abs_lut_input.disable_fr == 0; | 99 | state.lighting.lut_fr.abs_input = regs.lighting.abs_lut_input.disable_fr == 0; |
| 92 | state.lighting.lut_fr.type = regs.lighting.lut_input.fr.Value(); | 100 | state.lighting.lut_fr.type = regs.lighting.lut_input.fr.Value(); |
| @@ -509,7 +517,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 509 | out += "vec4 diffuse_sum = vec4(0.0, 0.0, 0.0, 1.0);\n" | 517 | out += "vec4 diffuse_sum = vec4(0.0, 0.0, 0.0, 1.0);\n" |
| 510 | "vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);\n" | 518 | "vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);\n" |
| 511 | "vec3 light_vector = vec3(0.0);\n" | 519 | "vec3 light_vector = vec3(0.0);\n" |
| 512 | "vec3 refl_value = vec3(0.0);\n"; | 520 | "vec3 refl_value = vec3(0.0);\n" |
| 521 | "vec3 spot_dir = vec3(0.0);\n;"; | ||
| 513 | 522 | ||
| 514 | // Compute fragment normals | 523 | // Compute fragment normals |
| 515 | if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) { | 524 | if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) { |
| @@ -560,6 +569,10 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 560 | index = std::string("dot(light_vector, normal)"); | 569 | index = std::string("dot(light_vector, normal)"); |
| 561 | break; | 570 | break; |
| 562 | 571 | ||
| 572 | case LightingRegs::LightingLutInput::SP: | ||
| 573 | index = std::string("dot(light_vector, spot_dir)"); | ||
| 574 | break; | ||
| 575 | |||
| 563 | default: | 576 | default: |
| 564 | LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input); | 577 | LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input); |
| 565 | UNIMPLEMENTED(); | 578 | UNIMPLEMENTED(); |
| @@ -596,21 +609,34 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 596 | else | 609 | else |
| 597 | out += "light_vector = normalize(" + light_src + ".position + view);\n"; | 610 | out += "light_vector = normalize(" + light_src + ".position + view);\n"; |
| 598 | 611 | ||
| 612 | out += "spot_dir = " + light_src + ".spot_direction;\n"; | ||
| 613 | |||
| 599 | // Compute dot product of light_vector and normal, adjust if lighting is one-sided or | 614 | // Compute dot product of light_vector and normal, adjust if lighting is one-sided or |
| 600 | // two-sided | 615 | // two-sided |
| 601 | std::string dot_product = light_config.two_sided_diffuse | 616 | std::string dot_product = light_config.two_sided_diffuse |
| 602 | ? "abs(dot(light_vector, normal))" | 617 | ? "abs(dot(light_vector, normal))" |
| 603 | : "max(dot(light_vector, normal), 0.0)"; | 618 | : "max(dot(light_vector, normal), 0.0)"; |
| 604 | 619 | ||
| 620 | // If enabled, compute spot light attenuation value | ||
| 621 | std::string spot_atten = "1.0"; | ||
| 622 | if (light_config.spot_atten_enable && | ||
| 623 | LightingRegs::IsLightingSamplerSupported( | ||
| 624 | lighting.config, LightingRegs::LightingSampler::SpotlightAttenuation)) { | ||
| 625 | std::string index = | ||
| 626 | GetLutIndex(light_config.num, lighting.lut_sp.type, lighting.lut_sp.abs_input); | ||
| 627 | auto sampler = LightingRegs::SpotlightAttenuationSampler(light_config.num); | ||
| 628 | spot_atten = "(" + std::to_string(lighting.lut_sp.scale) + " * " + | ||
| 629 | GetLutValue(sampler, index) + ")"; | ||
| 630 | } | ||
| 631 | |||
| 605 | // If enabled, compute distance attenuation value | 632 | // If enabled, compute distance attenuation value |
| 606 | std::string dist_atten = "1.0"; | 633 | std::string dist_atten = "1.0"; |
| 607 | if (light_config.dist_atten_enable) { | 634 | if (light_config.dist_atten_enable) { |
| 608 | std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " + | 635 | std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " + |
| 609 | light_src + ".position) + " + light_src + ".dist_atten_bias)"; | 636 | light_src + ".position) + " + light_src + ".dist_atten_bias)"; |
| 610 | index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))"; | 637 | index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))"; |
| 611 | const unsigned lut_num = | 638 | auto sampler = LightingRegs::DistanceAttenuationSampler(light_config.num); |
| 612 | ((unsigned)LightingRegs::LightingSampler::DistanceAttenuation + light_config.num); | 639 | dist_atten = GetLutValue(sampler, index); |
| 613 | dist_atten = GetLutValue((LightingRegs::LightingSampler)lut_num, index); | ||
| 614 | } | 640 | } |
| 615 | 641 | ||
| 616 | // If enabled, clamp specular component if lighting result is negative | 642 | // If enabled, clamp specular component if lighting result is negative |
| @@ -711,11 +737,11 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 711 | 737 | ||
| 712 | // Compute primary fragment color (diffuse lighting) function | 738 | // Compute primary fragment color (diffuse lighting) function |
| 713 | out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " + | 739 | out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " + |
| 714 | light_src + ".ambient) * " + dist_atten + ";\n"; | 740 | light_src + ".ambient) * " + dist_atten + " * " + spot_atten + ";\n"; |
| 715 | 741 | ||
| 716 | // Compute secondary fragment color (specular lighting) function | 742 | // Compute secondary fragment color (specular lighting) function |
| 717 | out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " + | 743 | out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " + |
| 718 | clamp_highlights + " * " + dist_atten + ";\n"; | 744 | clamp_highlights + " * " + dist_atten + " * " + spot_atten + ";\n"; |
| 719 | } | 745 | } |
| 720 | 746 | ||
| 721 | // Sum final lighting result | 747 | // Sum final lighting result |
| @@ -967,6 +993,7 @@ struct LightSrc { | |||
| 967 | vec3 diffuse; | 993 | vec3 diffuse; |
| 968 | vec3 ambient; | 994 | vec3 ambient; |
| 969 | vec3 position; | 995 | vec3 position; |
| 996 | vec3 spot_direction; | ||
| 970 | float dist_atten_bias; | 997 | float dist_atten_bias; |
| 971 | float dist_atten_scale; | 998 | float dist_atten_scale; |
| 972 | }; | 999 | }; |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index ea6d216d1..9c90eadf9 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -93,6 +93,7 @@ union PicaShaderConfig { | |||
| 93 | bool directional; | 93 | bool directional; |
| 94 | bool two_sided_diffuse; | 94 | bool two_sided_diffuse; |
| 95 | bool dist_atten_enable; | 95 | bool dist_atten_enable; |
| 96 | bool spot_atten_enable; | ||
| 96 | } light[8]; | 97 | } light[8]; |
| 97 | 98 | ||
| 98 | bool enable; | 99 | bool enable; |
| @@ -110,7 +111,7 @@ union PicaShaderConfig { | |||
| 110 | bool abs_input; | 111 | bool abs_input; |
| 111 | Pica::LightingRegs::LightingLutInput type; | 112 | Pica::LightingRegs::LightingLutInput type; |
| 112 | float scale; | 113 | float scale; |
| 113 | } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb; | 114 | } lut_d0, lut_d1, lut_sp, lut_fr, lut_rr, lut_rg, lut_rb; |
| 114 | } lighting; | 115 | } lighting; |
| 115 | 116 | ||
| 116 | struct { | 117 | struct { |