From ce2ad7436ee061ef60b152cf2798dd9305616210 Mon Sep 17 00:00:00 2001 From: wwylele Date: Mon, 12 Mar 2018 19:40:17 +0200 Subject: [PATCH] swrasterizer/lighting: implement shadow attenuation --- src/video_core/regs_lighting.h | 13 +++++++ src/video_core/swrasterizer/lighting.cpp | 45 +++++++++++++++++++++--- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/video_core/regs_lighting.h b/src/video_core/regs_lighting.h index 69d1b2b05..8ef1d2136 100644 --- a/src/video_core/regs_lighting.h +++ b/src/video_core/regs_lighting.h @@ -187,9 +187,15 @@ struct LightingRegs { BitField<0, 3, u32> max_light_index; // Number of enabled lights - 1 union { + BitField<0, 1, u32> enable_shadow; BitField<2, 2, LightingFresnelSelector> fresnel_selector; BitField<4, 4, LightingConfig> config; + BitField<16, 1, u32> shadow_primary; + BitField<17, 1, u32> shadow_secondary; + BitField<18, 1, u32> shadow_invert; + BitField<19, 1, u32> shadow_alpha; BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2 + BitField<24, 2, u32> shadow_selector; BitField<27, 1, u32> clamp_highlights; BitField<28, 2, LightingBumpMode> bump_mode; BitField<30, 1, u32> disable_bump_renorm; @@ -198,6 +204,9 @@ struct LightingRegs { union { u32 raw; + // Each bit specifies whether shadow should be applied for the corresponding light. + BitField<0, 8, u32> disable_shadow; + // Each bit specifies whether spot light attenuation should be applied for the corresponding // light. BitField<8, 8, u32> disable_spot_atten; @@ -224,6 +233,10 @@ struct LightingRegs { return (config1.disable_spot_atten & (1 << index)) != 0; } + bool IsShadowDisabled(unsigned index) const { + return (config1.disable_shadow & (1 << index)) != 0; + } + union { BitField<0, 8, u32> index; ///< Index at which to set data in the LUT BitField<8, 5, u32> type; ///< Type of LUT for which to set data diff --git a/src/video_core/swrasterizer/lighting.cpp b/src/video_core/swrasterizer/lighting.cpp index 04f81ef40..0d814dab1 100644 --- a/src/video_core/swrasterizer/lighting.cpp +++ b/src/video_core/swrasterizer/lighting.cpp @@ -25,6 +25,16 @@ std::tuple, Math::Vec4> ComputeFragmentsColors( const Math::Quaternion& normquat, const Math::Vec3& view, const Math::Vec4 (&texture_color)[4]) { + Math::Vec4 shadow; + if (lighting.config0.enable_shadow) { + shadow = texture_color[lighting.config0.shadow_selector].Cast() / 255.0f; + if (lighting.config0.shadow_invert) { + shadow = Math::MakeVec(1.0f, 1.0f, 1.0f, 1.0f) - shadow; + } + } else { + shadow = Math::MakeVec(1.0f, 1.0f, 1.0f, 1.0f); + } + Math::Vec3 surface_normal; Math::Vec3 surface_tangent; @@ -284,11 +294,38 @@ std::tuple, Math::Vec4> ComputeFragmentsColors( } auto diffuse = - light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f(); - diffuse_sum += Math::MakeVec(diffuse * dist_atten * spot_atten, 0.0f); + (light_config.diffuse.ToVec3f() * dot_product + light_config.ambient.ToVec3f()) * + dist_atten * spot_atten; + auto specular = (specular_0 + specular_1) * clamp_highlights * dist_atten * spot_atten; - specular_sum += Math::MakeVec( - (specular_0 + specular_1) * clamp_highlights * dist_atten * spot_atten, 0.0f); + if (!lighting.IsShadowDisabled(num)) { + if (lighting.config0.shadow_primary) { + diffuse = diffuse * shadow.xyz(); + } + if (lighting.config0.shadow_secondary) { + specular = specular * shadow.xyz(); + } + } + + diffuse_sum += Math::MakeVec(diffuse, 0.0f); + specular_sum += Math::MakeVec(specular, 0.0f); + } + + if (lighting.config0.shadow_alpha) { + // Alpha shadow also uses the Fresnel selecotr to determine which alpha to apply + // Enabled for diffuse lighting alpha component + if (lighting.config0.fresnel_selector == + LightingRegs::LightingFresnelSelector::PrimaryAlpha || + lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) { + diffuse_sum.a() *= shadow.w; + } + + // Enabled for the specular lighting alpha component + if (lighting.config0.fresnel_selector == + LightingRegs::LightingFresnelSelector::SecondaryAlpha || + lighting.config0.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) { + specular_sum.a() *= shadow.w; + } } diffuse_sum += Math::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f);