change light strength to light linearity 0.0 = inverse square, 1.0 = linear

This commit is contained in:
Ricardo Luís Vaz Silva 2024-10-10 16:51:09 -03:00 committed by Magnus Norddahl
commit 74a49ca919
13 changed files with 54 additions and 56 deletions

View file

@ -384,7 +384,7 @@ struct FMapThing
int friendlyseeblocks;
FName arg0str;
double SoftShadowRadius;
double LightStrength;
double LightLinearity;
bool LightNoShadowMap;
bool LightDontLightActors;
bool LightDontLightMap;

View file

@ -796,8 +796,8 @@ public:
th->SoftShadowRadius = CheckFloat(key);
break;
case NAME_light_strength:
th->LightStrength = CheckFloat(key);
case NAME_light_linearity:
th->LightLinearity = CheckFloat(key);
break;
case NAME_light_noshadowmap:

View file

@ -321,7 +321,7 @@ xx(DynamicLight)
xx(SpotInnerAngle)
xx(SpotOuterAngle)
xx(SoftShadowRadius)
xx(LightStrength)
xx(LightLinearity)
xx(lightflags)
xx(lighttype)
xx(InternalDynamicLight)
@ -871,7 +871,7 @@ xx(lm_suncolor)
// Light keywords
xx(light_softshadowradius)
xx(light_strength)
xx(light_linearity)
xx(light_noshadowmap)
xx(light_dontlightactors)
xx(light_dontlightmap)

View file

@ -99,7 +99,7 @@ static FDynamicLight *GetLight(FLevelLocals *Level)
}
static inline constexpr float calcStrength(float radius)
float LightCalcStrength(float radius)
{
radius *= 2; // radius in shaders is actualy diameter, so multiply it here to match
return std::min(1500.0f, (radius * radius) / 10);
@ -122,12 +122,10 @@ void AttachLight(AActor *self)
light->pLightFlags = (LightFlags*)&self->IntVar(NAME_lightflags);
light->pArgs = self->args;
light->pSoftShadowRadius = &self->FloatVar(NAME_SoftShadowRadius);
light->pStrength = &self->FloatVar(NAME_LightStrength);
light->pLinearity = &self->FloatVar(NAME_LightLinearity);
if(*light->pStrength <= 0)
{
*light->pStrength = -calcStrength(light->m_currentRadius);
}
light->lightStrength = LightCalcStrength(light->pArgs[LIGHT_INTENSITY]);
light->specialf1 = DAngle::fromDeg(double(self->SpawnAngle)).Normalized360().Degrees();
light->Sector = self->Sector;
@ -250,10 +248,7 @@ void FDynamicLight::Activate()
}
if (m_currentRadius <= 0) m_currentRadius = 1;
if(pStrength && *pStrength <= 0)
{
*pStrength = -calcStrength(m_currentRadius);
}
lightStrength = LightCalcStrength(m_currentRadius);
}
@ -377,9 +372,9 @@ void FDynamicLight::Tick()
if (m_currentRadius <= 0) m_currentRadius = 1;
if(pStrength && *pStrength <= 0 && oldradius != m_currentRadius)
if(oldradius != m_currentRadius)
{
*pStrength = -calcStrength(m_currentRadius);
lightStrength = LightCalcStrength(m_currentRadius);
}
UpdateLocation();
}

View file

@ -131,7 +131,7 @@ protected:
DAngle m_spotOuterAngle = DAngle::fromDeg(25.0);
DAngle m_pitch = nullAngle;
double SoftShadowRadius = 5.0;
double Strength = 0.0;
double Linearity = 0.0;
friend FSerializer &Serialize(FSerializer &arc, const char *key, FLightDefaults &value, FLightDefaults *def);
};
@ -225,7 +225,8 @@ struct FDynamicLight
bool IsActive() const { return m_active; }
float GetRadius() const { return (IsActive() ? m_currentRadius * 2.f : 0.f); }
float GetSoftShadowRadius() const { return (float)(*pSoftShadowRadius); }
float GetStrength() const { return std::abs((float)*pStrength); }
float GetLinearity() const { return (float)(*pLinearity); }
float GetStrength() const { return lightStrength; }
int GetRed() const { return pArgs[LIGHT_RED]; }
int GetGreen() const { return pArgs[LIGHT_GREEN]; }
int GetBlue() const { return pArgs[LIGHT_BLUE]; }
@ -274,7 +275,7 @@ public:
const LightFlags *pLightFlags;
const double* pSoftShadowRadius; // Softshadows. Physical size of the light source
double* pStrength; // Softshadows. Physical size of the light source
const double* pLinearity;
double specialf1;
FDynamicLight *next, *prev;
@ -296,7 +297,7 @@ public:
bool swapped;
bool explicitpitch;
double tmpStrength;
float lightStrength;
// Locations in the level mesh light list. Ends with index = 0 or all entries used
enum { max_levelmesh_entries = 4 };

View file

@ -6214,9 +6214,9 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position)
mobj->FloatVar(NAME_SoftShadowRadius) = 5.0;
}
if (mthing->LightStrength > 0.0)
if (mthing->LightLinearity > 0.0)
{
mobj->FloatVar(NAME_LightStrength) = mthing->LightStrength;
mobj->FloatVar(NAME_LightLinearity) = mthing->LightLinearity;
}
if (mthing->LightNoShadowMap)

View file

@ -118,6 +118,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, TDeletingArray<FLightD
//
//-----------------------------------------------------------------------------
extern float LightCalcStrength(float radius);
void FLightDefaults::ApplyProperties(FDynamicLight * light) const
{
auto oldtype = light->lighttype;
@ -128,15 +130,8 @@ void FLightDefaults::ApplyProperties(FDynamicLight * light) const
light->pArgs = m_Args;
light->pSoftShadowRadius = &SoftShadowRadius;
if(Strength > 0.0)
{
light->pStrength = const_cast<double*>(&Strength); // casting const to non-const, but positive strength values will not be modified
}
else
{
light->tmpStrength = 0.0;
light->pStrength = &light->tmpStrength;
}
light->pLinearity = &Linearity;
light->lightStrength = LightCalcStrength(light->pArgs[LIGHT_INTENSITY]);
light->pLightFlags = &m_lightFlags;
if (m_lightFlags & LF_SPOT)

View file

@ -120,7 +120,7 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f
// Store attenuate flag in the sign bit of the float.
if (light->IsAttenuated() || forceAttenuate) shadowIndex = -shadowIndex;
float lightType = 0.0f;
bool lightType = false;
float spotInnerAngle = 0.0f;
float spotOuterAngle = 0.0f;
float spotDirX = 0.0f;
@ -128,7 +128,7 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f
float spotDirZ = 0.0f;
if (light->IsSpot())
{
lightType = 1.0f;
lightType = true;
spotInnerAngle = (float)light->pSpotInnerAngle->Cos();
spotOuterAngle = (float)light->pSpotOuterAngle->Cos();
@ -139,15 +139,19 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f
spotDirY = float(-negPitch.Sin());
spotDirZ = float(-Angle.Sin() * xzLen);
}
float softShadowRadius = light->GetSoftShadowRadius();
float linearity = light->GetLinearity();
float strength = light->GetStrength();
float *data = &dld.arrays[i][dld.arrays[i].Reserve(16)];
data[0] = float(pos.X);
data[1] = float(pos.Z);
data[2] = float(pos.Y);
data[3] = radius;
data[3] = lightType ? -radius : radius;
data[4] = r;
data[5] = g;
data[6] = b;
@ -155,7 +159,7 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f
data[8] = spotDirX;
data[9] = spotDirY;
data[10] = spotDirZ;
data[11] = lightType;
data[11] = std::clamp(linearity, 0.0f, 1.0f);
data[12] = spotInnerAngle;
data[13] = spotOuterAngle;
data[14] = softShadowRadius;
@ -172,7 +176,6 @@ void AddSunLightToList(FDynLightData& dld, float x, float y, float z, const FVec
z += sundir.Z * dist;
int i = 0;
float lightType = 0.0f;
float spotInnerAngle = 0.0f;
float spotOuterAngle = 0.0f;
float spotDirX = 0.0f;
@ -194,7 +197,7 @@ void AddSunLightToList(FDynLightData& dld, float x, float y, float z, const FVec
data[8] = spotDirX;
data[9] = spotDirY;
data[10] = spotDirZ;
data[11] = lightType;
data[11] = 0.0f; // unused
data[12] = spotInnerAngle;
data[13] = spotOuterAngle;
data[14] = 0.0f; // unused

View file

@ -4,19 +4,21 @@ vec3 lightContribution(int i, vec3 normal)
vec4 lightcolor = lights[i+1];
vec4 lightspot1 = lights[i+2];
vec4 lightspot2 = lights[i+3];
float radius = abs(lightpos.w);
float lightdistance = distance(lightpos.xyz, pixelpos.xyz);
if (lightpos.w < lightdistance)
if (radius < lightdistance)
return vec3(0.0); // Early out lights touching surface but not this fragment
vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz);
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 = distanceAttenuation(lightdistance, lightpos.w, lightspot2.w);
float attenuation = distanceAttenuation(lightdistance, radius, lightspot2.w, lightspot1.w);
if (lightspot1.w == 1.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
if (lightpos.w < 0.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); // Sign bit is the spotlight flag
if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag
{

View file

@ -79,9 +79,9 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight)
vec3 L = normalize(lightpos.xyz - worldpos);
vec3 H = normalize(V + L);
float attenuation = distanceAttenuation(distance(lightpos.xyz, pixelpos.xyz), lightpos.w, lightspot2.w);
if (lightspot1.w == 1.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
float attenuation = distanceAttenuation(distance(lightpos.xyz, pixelpos.xyz), abs(lightpos.w), lightspot2.w, lightspot1.w);
if (lightpos.w < 0.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); // Sign bit is the spotlight flag
if (lightcolor.a < 0.0)
attenuation *= clamp(dot(N, L), 0.0, 1.0); // Sign bit is the attenuated light flag
@ -119,9 +119,9 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight)
vec3 L = normalize(lightpos.xyz - worldpos);
vec3 H = normalize(V + L);
float attenuation = distanceAttenuation(distance(lightpos.xyz, pixelpos.xyz), lightpos.w, lightspot2.w);
if (lightspot1.w == 1.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
float attenuation = distanceAttenuation(distance(lightpos.xyz, pixelpos.xyz), abs(lightpos.w), lightspot2.w, lightspot1.w);
if (lightpos.w < 0.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); // Sign bit is the spotlight flag
if (lightcolor.a < 0.0)
attenuation *= clamp(dot(N, L), 0.0, 1.0); // Sign bit is the attenuated light flag

View file

@ -1,15 +1,15 @@
#ifdef LIGHT_ATTENUATION_INVERSE_SQUARE
float distanceAttenuation(float dist, float radius, float strength)
float distanceAttenuation(float dist, float radius, float strength, float linearity)
{
float a = dist / radius;
float b = clamp(1.0 - a * a * a * a, 0.0, 1.0);
return (b * b) / (dist * dist + 1.0) * strength;
return mix((b * b) / (dist * dist + 1.0) * strength, clamp((radius - dist) / radius, 0.0, 1.0), linearity);
}
#else //elif defined(LIGHT_ATTENUATION_LINEAR)
#define distanceAttenuation(dist, radius, strength) clamp((radius - dist) / radius, 0.0, 1.0)
#define distanceAttenuation(dist, radius, strength, linearity) clamp((radius - dist) / radius, 0.0, 1.0)
#endif

View file

@ -3,15 +3,17 @@ vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA, float
vec4 lightpos = lights[i];
vec4 lightspot1 = lights[i+2];
vec4 lightspot2 = lights[i+3];
float radius = abs(lightpos.w);
float lightdistance = distance(lightpos.xyz, pixelpos.xyz);
if (lightpos.w < lightdistance)
if (radius < lightdistance)
return vec2(0.0); // Early out lights touching surface but not this fragment
float attenuation = distanceAttenuation(lightdistance, lightpos.w, lightspot2.w);
float attenuation = distanceAttenuation(lightdistance, radius, lightspot2.w, lightspot1.w);
if (lightspot1.w == 1.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y);
if (lightpos.w < 0.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); // Sign bit is the spotlight flag
vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz);

View file

@ -3,7 +3,7 @@ class DynamicLight : Actor
double SpotInnerAngle;
double SpotOuterAngle;
double SoftShadowRadius;
double LightStrength; // used for Inverse-square falloff lights
double LightLinearity; // used for Inverse-square falloff lights
private int lighttype;
private int lightflags;