From 37a7907221e402601d0d8312f397f068a1d807e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Sun, 6 Oct 2024 14:28:21 -0300 Subject: [PATCH] Allow setting light attenuation mode from mapinfo --- .../hwrenderer/data/hw_renderstate.h | 1 + .../hwrenderer/data/hw_viewpointuniforms.h | 10 +++++++ src/gamedata/g_mapinfo.cpp | 30 ++++++++++++++++++- src/gamedata/g_mapinfo.h | 1 + .../hwrenderer/scene/hw_drawinfo.cpp | 3 +- .../shaders/scene/binding_rsbuffers.glsl | 2 ++ .../shaders/scene/lightmodel_normal.glsl | 27 ++++++++++++++++- .../static/shaders/scene/lightmodel_pbr.glsl | 16 ++++++++-- .../shaders/scene/lightmodel_specular.glsl | 27 ++++++++++++++++- 9 files changed, 111 insertions(+), 6 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_renderstate.h b/src/common/rendering/hwrenderer/data/hw_renderstate.h index 788947768..80be8c69f 100644 --- a/src/common/rendering/hwrenderer/data/hw_renderstate.h +++ b/src/common/rendering/hwrenderer/data/hw_renderstate.h @@ -647,6 +647,7 @@ public: matrices.mClipLine.X = -10000000.0f; matrices.mShadowFilter = gl_light_shadow_filter; matrices.mLightBlendMode = 0; + matrices.mLightAttenuationMode = 0; matrices.mProjectionMatrix.ortho(0, (float)width, (float)height, 0, -1.0f, 1.0f); matrices.CalcDependencies(); return SetViewpoint(matrices); diff --git a/src/common/rendering/hwrenderer/data/hw_viewpointuniforms.h b/src/common/rendering/hwrenderer/data/hw_viewpointuniforms.h index 89cb6aac0..64d580b4a 100644 --- a/src/common/rendering/hwrenderer/data/hw_viewpointuniforms.h +++ b/src/common/rendering/hwrenderer/data/hw_viewpointuniforms.h @@ -13,6 +13,14 @@ enum class ELightBlendMode : uint8_t DEFAULT = CLAMP, }; +enum class ELightAttenuationMode : uint8_t +{ + LINEAR = 0, + INVERSE_SQUARE = 1, + + DEFAULT = LINEAR, +}; + struct HWViewpointUniforms { VSMatrix mProjectionMatrix; @@ -35,6 +43,8 @@ struct HWViewpointUniforms int mLightTilesWidth = 0; + int mLightAttenuationMode = 0; + void CalcDependencies() { mNormalViewMatrix.computeNormalMatrix(mViewMatrix); diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index 27609e6da..e4aead7e6 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -325,6 +325,7 @@ void level_info_t::Reset() skyrotatevector = FVector3(0, 0, 1); skyrotatevector2 = FVector3(0, 0, 1); lightblendmode = ELightBlendMode::DEFAULT; + lightattenuationmode = ELightAttenuationMode::DEFAULT; tonemap = ETonemapMode::None; } @@ -1596,10 +1597,14 @@ DEFINE_MAP_OPTION(lightblendmode, false) parse.ParseAssign(); parse.sc.MustGetString(); - if (parse.sc.Compare("Default") || parse.sc.Compare("Clamp")) + if (parse.sc.Compare("Default")) { info->lightblendmode = ELightBlendMode::DEFAULT; } + else if (parse.sc.Compare("Clamp")) + { + info->lightblendmode = ELightBlendMode::CLAMP; + } else if (parse.sc.Compare("ColoredClamp")) { info->lightblendmode = ELightBlendMode::CLAMP_COLOR; @@ -1642,6 +1647,29 @@ DEFINE_MAP_OPTION(lightblendmode, false) } } +DEFINE_MAP_OPTION(lightattenuationmode, false) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + + if (parse.sc.Compare("Default")) + { + info->lightattenuationmode = ELightAttenuationMode::DEFAULT; + } + else if (parse.sc.Compare("Linear")) + { + info->lightattenuationmode = ELightAttenuationMode::LINEAR; + } + else if (parse.sc.Compare("InverseSquare")) + { + info->lightattenuationmode = ELightAttenuationMode::INVERSE_SQUARE; + } + else + { + parse.sc.ScriptMessage("Invalid light attenuation mode %s", parse.sc.String); + } +} + DEFINE_MAP_OPTION(notexturefill, false) { if (parse.CheckAssign()) diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index 3bdaaa0a3..6dfcc7dfa 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -431,6 +431,7 @@ struct level_info_t FString acsName; bool fs_nocheckposition; ELightBlendMode lightblendmode; + ELightAttenuationMode lightattenuationmode; ETonemapMode tonemap; CutsceneDef intro, outro; diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index fdd6b9507..b36cccaa2 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -127,7 +127,8 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni } VPUniforms.mClipLine.X = -10000000.0f; VPUniforms.mShadowFilter = static_cast(gl_light_shadow_filter); - VPUniforms.mLightBlendMode = (level.info ? (int)level.info->lightblendmode : 0); + VPUniforms.mLightBlendMode = (level.info ? static_cast(level.info->lightblendmode) : 0); + VPUniforms.mLightAttenuationMode = (level.info ? static_cast(level.info->lightattenuationmode) : 0); } mClipper->SetViewpoint(Viewpoint); vClipper->SetViewpoint(Viewpoint); diff --git a/wadsrc/static/shaders/scene/binding_rsbuffers.glsl b/wadsrc/static/shaders/scene/binding_rsbuffers.glsl index 3abe60a43..e4ca07fe2 100644 --- a/wadsrc/static/shaders/scene/binding_rsbuffers.glsl +++ b/wadsrc/static/shaders/scene/binding_rsbuffers.glsl @@ -21,6 +21,8 @@ layout(set = 1, binding = 0, std140) uniform ViewpointUBO int uLightBlendMode; int uLightTilesWidth; // Levelmesh light tiles + + int uLightAttenuationMode; }; layout(set = 1, binding = 1, std140) uniform MatricesUBO diff --git a/wadsrc/static/shaders/scene/lightmodel_normal.glsl b/wadsrc/static/shaders/scene/lightmodel_normal.glsl index 894a3d972..ac510e027 100644 --- a/wadsrc/static/shaders/scene/lightmodel_normal.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_normal.glsl @@ -1,3 +1,28 @@ +float linearDistanceAttenuation(vec4 lightpos, float d) +{ + return clamp((lightpos.w - d) / lightpos.w, 0.0, 1.0); +} + +float inverseSquareDistanceAttenuation(vec4 lightpos, float d) +{ + float strength = 1500.0; + float r = lightpos.w; + float a = d / r; + float b = clamp(1.0 - a * a * a * a, 0.0, 1.0); + return (b * b) / (d * d + 1.0) * strength; +} + +float distanceAttenuation(vec4 lightpos, float d) +{ + if ( uLightAttenuationMode == 1 ) + { + return inverseSquareDistanceAttenuation(lightpos, d); + } + else + { + return linearDistanceAttenuation(lightpos, d); + } +} vec3 lightContribution(int i, vec3 normal) { @@ -14,7 +39,7 @@ vec3 lightContribution(int i, vec3 normal) float dotprod = dot(normal, lightdir); if (dotprod < -0.0001) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. Note that this can cause precision issues. - float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + float attenuation = distanceAttenuation(lightpos, lightdistance); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); diff --git a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl index 7c7f252a8..d1e0f2f52 100644 --- a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl @@ -61,6 +61,18 @@ float inverseSquareDistanceAttenuation(vec4 lightpos) return (b * b) / (d * d + 1.0) * strength; } +float distanceAttenuation(vec4 lightpos) +{ + if ( uLightAttenuationMode == 1 ) + { + return inverseSquareDistanceAttenuation(lightpos); + } + else + { + return linearDistanceAttenuation(lightpos); + } +} + vec3 ProcessMaterialLight(Material material, vec3 ambientLight) { vec3 worldpos = pixelpos.xyz; @@ -96,7 +108,7 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - float attenuation = inverseSquareDistanceAttenuation(lightpos); + float attenuation = distanceAttenuation(lightpos); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); if (lightcolor.a < 0.0) @@ -136,7 +148,7 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - float attenuation = linearDistanceAttenuation(lightpos); + float attenuation = distanceAttenuation(lightpos); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); if (lightcolor.a < 0.0) diff --git a/wadsrc/static/shaders/scene/lightmodel_specular.glsl b/wadsrc/static/shaders/scene/lightmodel_specular.glsl index a9d99c779..534bdec64 100644 --- a/wadsrc/static/shaders/scene/lightmodel_specular.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_specular.glsl @@ -1,3 +1,28 @@ +float linearDistanceAttenuation(vec4 lightpos, float d) +{ + return clamp((lightpos.w - d) / lightpos.w, 0.0, 1.0); +} + +float inverseSquareDistanceAttenuation(vec4 lightpos, float d) +{ + float strength = 1500.0; + float r = lightpos.w; + float a = d / r; + float b = clamp(1.0 - a * a * a * a, 0.0, 1.0); + return (b * b) / (d * d + 1.0) * strength; +} + +float distanceAttenuation(vec4 lightpos, float d) +{ + if ( uLightAttenuationMode == 1 ) + { + return inverseSquareDistanceAttenuation(lightpos, d); + } + else + { + return linearDistanceAttenuation(lightpos, d); + } +} vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA, float glossiness, float specularLevel) { @@ -9,7 +34,7 @@ vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA, float if (lightpos.w < lightdistance) return vec2(0.0); // Early out lights touching surface but not this fragment - float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + float attenuation = distanceAttenuation(lightpos, lightdistance); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);