Allow setting light attenuation mode from mapinfo

This commit is contained in:
Ricardo Luís Vaz Silva 2024-10-06 14:28:21 -03:00 committed by Magnus Norddahl
commit 37a7907221
9 changed files with 111 additions and 6 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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())

View file

@ -431,6 +431,7 @@ struct level_info_t
FString acsName;
bool fs_nocheckposition;
ELightBlendMode lightblendmode;
ELightAttenuationMode lightattenuationmode;
ETonemapMode tonemap;
CutsceneDef intro, outro;

View file

@ -127,7 +127,8 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni
}
VPUniforms.mClipLine.X = -10000000.0f;
VPUniforms.mShadowFilter = static_cast<int>(gl_light_shadow_filter);
VPUniforms.mLightBlendMode = (level.info ? (int)level.info->lightblendmode : 0);
VPUniforms.mLightBlendMode = (level.info ? static_cast<int>(level.info->lightblendmode) : 0);
VPUniforms.mLightAttenuationMode = (level.info ? static_cast<int>(level.info->lightattenuationmode) : 0);
}
mClipper->SetViewpoint(Viewpoint);
vClipper->SetViewpoint(Viewpoint);

View file

@ -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

View file

@ -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);

View file

@ -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)

View file

@ -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);