From 56787bbc1778b45d33d305c52761e91a06faf32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Tue, 8 Oct 2024 20:46:27 -0300 Subject: [PATCH] Add LightStrength to UDMF, move SoftShadowRadius from AActor to DynamicLight --- specs/udmf_zdoom.txt | 3 ++ src/doomdata.h | 1 + src/maploader/udmf.cpp | 6 +++- src/namedef_custom.h | 3 ++ src/playsim/a_dynlight.cpp | 32 +++++++++++++++++-- src/playsim/a_dynlight.h | 6 ++++ src/playsim/actor.h | 2 -- src/playsim/p_mobj.cpp | 16 ++++++++-- src/r_data/a_dynlightdata.cpp | 11 +++++++ src/rendering/hwrenderer/hw_dynlightdata.cpp | 9 ++++-- .../shaders/scene/lightmodel_normal.glsl | 2 +- .../static/shaders/scene/lightmodel_pbr.glsl | 4 +-- .../shaders/scene/lightmodel_shared.glsl | 9 ++---- .../shaders/scene/lightmodel_specular.glsl | 2 +- .../static/zscript/actors/shared/dynlights.zs | 2 ++ 15 files changed, 88 insertions(+), 20 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 0b0b50c99..acf3a36da 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -429,6 +429,9 @@ Note: All fields default to false unless mentioned otherwise. lm_suncolor = ; // ZDRay lightmap sun color. Default is white (0xFFFFFF). light_softshadowradius = ; // ZDRay lightmap light and raytraced dynamic light soft shadow amount. Higher values produce softer shadows. Default = 5.0 + + light_strength = ; // Light strenght for Inverse-square falloff lights. Default = 0.0 (auto) + friendlyseeblocks = ; // How far (in block units) a friendly monster can see other monsters. Default 10 diff --git a/src/doomdata.h b/src/doomdata.h index 303e0eca7..8ef88effa 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -384,6 +384,7 @@ struct FMapThing int friendlyseeblocks; FName arg0str; double SoftShadowRadius; + double LightStrength; }; diff --git a/src/maploader/udmf.cpp b/src/maploader/udmf.cpp index 7ff310d28..84ac00981 100644 --- a/src/maploader/udmf.cpp +++ b/src/maploader/udmf.cpp @@ -793,7 +793,11 @@ public: break; case NAME_light_softshadowradius: - th->SoftShadowRadius = (float)CheckFloat(key); + th->SoftShadowRadius = CheckFloat(key); + break; + + case NAME_light_strength: + th->LightStrength = CheckFloat(key); break; case NAME_lm_suncolor: diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 6f2338009..363c62add 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -320,6 +320,8 @@ xx(RedSkull) xx(DynamicLight) xx(SpotInnerAngle) xx(SpotOuterAngle) +xx(SoftShadowRadius) +xx(LightStrength) xx(lightflags) xx(lighttype) xx(InternalDynamicLight) @@ -869,6 +871,7 @@ xx(lm_suncolor) // Light keywords xx(light_softshadowradius) +xx(light_strength) xx(skew_bottom_type) xx(skew_middle_type) diff --git a/src/playsim/a_dynlight.cpp b/src/playsim/a_dynlight.cpp index b274d63c6..78e8b1f1e 100644 --- a/src/playsim/a_dynlight.cpp +++ b/src/playsim/a_dynlight.cpp @@ -99,6 +99,12 @@ static FDynamicLight *GetLight(FLevelLocals *Level) } +static inline constexpr float calcStrength(float radius) +{ + radius *= 2; // radius in shaders is actualy diameter, so multiply it here to match + return std::min(1500.0f, (radius * radius) / 10); +} + //========================================================================== // // Attaches a dynamic light descriptor to a dynamic light actor. @@ -115,7 +121,14 @@ void AttachLight(AActor *self) light->pPitch = &self->Angles.Pitch; light->pLightFlags = (LightFlags*)&self->IntVar(NAME_lightflags); light->pArgs = self->args; - light->pSoftShadowRadius = &self->SoftShadowRadius; + light->pSoftShadowRadius = &self->FloatVar(NAME_SoftShadowRadius); + light->pStrength = &self->FloatVar(NAME_LightStrength); + + if(*light->pStrength <= 0) + { + *light->pStrength = -calcStrength(light->m_currentRadius); + } + light->specialf1 = DAngle::fromDeg(double(self->SpawnAngle)).Normalized360().Degrees(); light->Sector = self->Sector; light->target = self; @@ -213,7 +226,6 @@ void FDynamicLight::ReleaseLight() FreeList.Push(this); } - //========================================================================== // // [TS] @@ -237,6 +249,11 @@ void FDynamicLight::Activate() m_currentRadius = float(m_cycler.GetVal()); } if (m_currentRadius <= 0) m_currentRadius = 1; + + if(pStrength && *pStrength <= 0) + { + *pStrength = -calcStrength(m_currentRadius); + } } @@ -254,6 +271,8 @@ void FDynamicLight::Tick() return; } + int oldradius = m_currentRadius; + if (owned) { if (!target->state || !target->ShouldRenderLocally()) @@ -345,8 +364,9 @@ void FDynamicLight::Tick() intensity = Sector? Sector->lightlevel * scale : 0; intensity = clamp(intensity, 0.f, 255.f); - + m_currentRadius = intensity; + break; } @@ -355,6 +375,12 @@ void FDynamicLight::Tick() break; } if (m_currentRadius <= 0) m_currentRadius = 1; + + + if(pStrength && *pStrength <= 0 && oldradius != m_currentRadius) + { + *pStrength = -calcStrength(m_currentRadius); + } UpdateLocation(); } diff --git a/src/playsim/a_dynlight.h b/src/playsim/a_dynlight.h index ad9a04ec4..4180e8ebb 100644 --- a/src/playsim/a_dynlight.h +++ b/src/playsim/a_dynlight.h @@ -131,6 +131,7 @@ protected: DAngle m_spotOuterAngle = DAngle::fromDeg(25.0); DAngle m_pitch = nullAngle; double SoftShadowRadius = 5.0; + double Strength = 0.0; friend FSerializer &Serialize(FSerializer &arc, const char *key, FLightDefaults &value, FLightDefaults *def); }; @@ -224,6 +225,7 @@ 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); } int GetRed() const { return pArgs[LIGHT_RED]; } int GetGreen() const { return pArgs[LIGHT_GREEN]; } int GetBlue() const { return pArgs[LIGHT_BLUE]; } @@ -272,6 +274,8 @@ public: const LightFlags *pLightFlags; const double* pSoftShadowRadius; // Softshadows. Physical size of the light source + double* pStrength; // Softshadows. Physical size of the light source + double specialf1; FDynamicLight *next, *prev; sector_t *Sector; @@ -292,6 +296,8 @@ public: bool swapped; bool explicitpitch; + double tmpStrength; + // Locations in the level mesh light list. Ends with index = 0 or all entries used enum { max_levelmesh_entries = 4 }; struct diff --git a/src/playsim/actor.h b/src/playsim/actor.h index dcf739977..3b4efd0a8 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -1375,8 +1375,6 @@ public: // (note: this is put into AActor instead of the PlayerPawn because non-players also use the value) double LandingSpeed; - double SoftShadowRadius = 5.0; // Light source's soft shadow radius - // ThingIDs void SetTID (int newTID); diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index d75f88f35..eca50a742 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -6181,8 +6181,6 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) if (mthing->fillcolor) mobj->fillcolor = (mthing->fillcolor & 0xffffff) | (ColorMatcher.Pick((mthing->fillcolor & 0xff0000) >> 16, (mthing->fillcolor & 0xff00) >> 8, (mthing->fillcolor & 0xff)) << 24); - if (mthing->SoftShadowRadius >= 0.0) - mobj->SoftShadowRadius = mthing->SoftShadowRadius; // allow color strings for lights and reshuffle the args for spot lights if (i->IsDescendantOf(NAME_DynamicLight)) @@ -6206,6 +6204,20 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) mobj->AngleVar(NAME_SpotInnerAngle) = DAngle::fromDeg(mthing->args[1]); mobj->AngleVar(NAME_SpotOuterAngle) = DAngle::fromDeg(mthing->args[2]); } + + if (mthing->SoftShadowRadius >= 0.0) + { + mobj->FloatVar(NAME_SoftShadowRadius) = mthing->SoftShadowRadius; + } + else + { + mobj->FloatVar(NAME_SoftShadowRadius) = 5.0; + } + + if (mthing->LightStrength > 0.0) + { + mobj->FloatVar(NAME_LightStrength) = mthing->LightStrength; + } } mobj->CallBeginPlay (); diff --git a/src/r_data/a_dynlightdata.cpp b/src/r_data/a_dynlightdata.cpp index bc692faec..cd043fc49 100644 --- a/src/r_data/a_dynlightdata.cpp +++ b/src/r_data/a_dynlightdata.cpp @@ -127,6 +127,17 @@ void FLightDefaults::ApplyProperties(FDynamicLight * light) const light->specialf1 = m_Param; light->pArgs = m_Args; light->pSoftShadowRadius = &SoftShadowRadius; + + if(Strength > 0.0) + { + light->pStrength = const_cast(&Strength); // casting const to non-const, but positive strength values will not be modified + } + else + { + light->tmpStrength = 0.0; + light->pStrength = &light->tmpStrength; + } + light->pLightFlags = &m_lightFlags; if (m_lightFlags & LF_SPOT) { diff --git a/src/rendering/hwrenderer/hw_dynlightdata.cpp b/src/rendering/hwrenderer/hw_dynlightdata.cpp index 258b6c9b3..adf2c57df 100644 --- a/src/rendering/hwrenderer/hw_dynlightdata.cpp +++ b/src/rendering/hwrenderer/hw_dynlightdata.cpp @@ -31,6 +31,7 @@ #include"hw_cvars.h" #include "v_video.h" #include "hwrenderer/scene/hw_drawstructs.h" +#include "g_levellocals.h" // If we want to share the array to avoid constant allocations it needs to be thread local unless it'd be littered with expensive synchronization. thread_local FDynLightData lightdata; @@ -140,6 +141,8 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f } float softShadowRadius = light->GetSoftShadowRadius(); + float strength = light->GetStrength(); + float *data = &dld.arrays[i][dld.arrays[i].Reserve(16)]; data[0] = float(pos.X); data[1] = float(pos.Z); @@ -156,7 +159,7 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f data[12] = spotInnerAngle; data[13] = spotOuterAngle; data[14] = softShadowRadius; - data[15] = 0.0f; // unused + data[15] = strength; } void AddSunLightToList(FDynLightData& dld, float x, float y, float z, const FVector3& sundir, const FVector3& suncolor) @@ -177,6 +180,8 @@ void AddSunLightToList(FDynLightData& dld, float x, float y, float z, const FVec float spotDirZ = 0.0f; float shadowIndex = -1025.f; // Note: 1025 disables shadowmap and the attenuate flag is in the sign bit of the float + float strength = 1500.0f; + float* data = &dld.arrays[i][dld.arrays[i].Reserve(16)]; data[0] = float(x); data[1] = float(z); @@ -193,5 +198,5 @@ void AddSunLightToList(FDynLightData& dld, float x, float y, float z, const FVec data[12] = spotInnerAngle; data[13] = spotOuterAngle; data[14] = 0.0f; // unused - data[15] = 0.0f; // unused + data[15] = strength; } diff --git a/wadsrc/static/shaders/scene/lightmodel_normal.glsl b/wadsrc/static/shaders/scene/lightmodel_normal.glsl index 4677544bf..03df92b54 100644 --- a/wadsrc/static/shaders/scene/lightmodel_normal.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_normal.glsl @@ -13,7 +13,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 = distanceAttenuation(lightdistance, lightpos.w); + float attenuation = distanceAttenuation(lightdistance, lightpos.w, lightspot2.w); 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 9ca4401df..112cfa4e5 100644 --- a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl @@ -79,7 +79,7 @@ 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); + 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); if (lightcolor.a < 0.0) @@ -119,7 +119,7 @@ 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); + 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); if (lightcolor.a < 0.0) diff --git a/wadsrc/static/shaders/scene/lightmodel_shared.glsl b/wadsrc/static/shaders/scene/lightmodel_shared.glsl index f2ca2947a..296466a7a 100644 --- a/wadsrc/static/shaders/scene/lightmodel_shared.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_shared.glsl @@ -1,8 +1,8 @@ + #ifdef LIGHT_ATTENUATION_INVERSE_SQUARE -float distanceAttenuation(float dist, float radius) +float distanceAttenuation(float dist, float radius, float strength) { - float strength = min(1500.0, (radius * radius) / 10); 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; @@ -10,9 +10,6 @@ float distanceAttenuation(float dist, float radius) #else //elif defined(LIGHT_ATTENUATION_LINEAR) -float distanceAttenuation(float dist, float radius) -{ - return clamp((radius - dist) / radius, 0.0, 1.0); -} +#define distanceAttenuation(dist, radius, strength) clamp((radius - dist) / radius, 0.0, 1.0) #endif diff --git a/wadsrc/static/shaders/scene/lightmodel_specular.glsl b/wadsrc/static/shaders/scene/lightmodel_specular.glsl index 6d684c218..bd1914549 100644 --- a/wadsrc/static/shaders/scene/lightmodel_specular.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_specular.glsl @@ -8,7 +8,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 = distanceAttenuation(lightdistance, lightpos.w); + float attenuation = distanceAttenuation(lightdistance, lightpos.w, lightspot2.w); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); diff --git a/wadsrc/static/zscript/actors/shared/dynlights.zs b/wadsrc/static/zscript/actors/shared/dynlights.zs index 664b6d1d9..f4ca60556 100644 --- a/wadsrc/static/zscript/actors/shared/dynlights.zs +++ b/wadsrc/static/zscript/actors/shared/dynlights.zs @@ -2,6 +2,8 @@ class DynamicLight : Actor { double SpotInnerAngle; double SpotOuterAngle; + double SoftShadowRadius; + double LightStrength; // used for Inverse-square falloff lights private int lighttype; private int lightflags;