diff --git a/src/common/rendering/hwrenderer/data/hw_levelmeshlight.h b/src/common/rendering/hwrenderer/data/hw_levelmeshlight.h index 24aff7e23..b18ca38eb 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmeshlight.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmeshlight.h @@ -15,4 +15,5 @@ public: FVector3 SpotDir; FVector3 Color; int SectorGroup; + float SourceRadius; }; diff --git a/src/common/rendering/vulkan/vk_levelmesh.cpp b/src/common/rendering/vulkan/vk_levelmesh.cpp index afe76f5ad..171d3c3a5 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.cpp +++ b/src/common/rendering/vulkan/vk_levelmesh.cpp @@ -674,6 +674,7 @@ void VkLevelMeshUploader::UploadLights() info.OuterAngleCos = light.OuterAngleCos; info.SpotDir = SwapYZ(light.SpotDir); info.Color = light.Color; + info.SourceRadius = light.SourceRadius; *(lights++) = info; } diff --git a/src/common/rendering/vulkan/vk_levelmesh.h b/src/common/rendering/vulkan/vk_levelmesh.h index 745637419..6b6eec003 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.h +++ b/src/common/rendering/vulkan/vk_levelmesh.h @@ -57,7 +57,7 @@ struct LightInfo float InnerAngleCos; float OuterAngleCos; FVector3 SpotDir; - float Padding2; + float SourceRadius; FVector3 Color; float Padding3; }; diff --git a/src/common/rendering/vulkan/vk_lightmapper.cpp b/src/common/rendering/vulkan/vk_lightmapper.cpp index 83b514a6b..83bac594d 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.cpp +++ b/src/common/rendering/vulkan/vk_lightmapper.cpp @@ -27,15 +27,13 @@ CVAR(Float, lm_scale, 1.0, CVAR_NOSAVE); CVAR(Bool, lm_sunlight, true, CVAR_ARCHIVE); CVAR(Bool, lm_blur, true, CVAR_ARCHIVE); CVAR(Bool, lm_ao, false, CVAR_ARCHIVE); -CVAR(Bool, lm_softshadows, false, CVAR_ARCHIVE); +CVAR(Bool, lm_softshadows, true, CVAR_ARCHIVE); CVAR(Bool, lm_bounce, false, CVAR_ARCHIVE); VkLightmapper::VkLightmapper(VulkanRenderDevice* fb) : fb(fb) { useRayQuery = fb->IsRayQueryEnabled(); - templightlist.Resize(128); - try { CreateUniformBuffer(); diff --git a/src/common/rendering/vulkan/vk_lightmapper.h b/src/common/rendering/vulkan/vk_lightmapper.h index c0812dfcd..ac2944cf8 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.h +++ b/src/common/rendering/vulkan/vk_lightmapper.h @@ -148,7 +148,6 @@ private: TArray selectedTiles; TArray> copylists; - TArray templightlist; struct { diff --git a/src/doomdata.h b/src/doomdata.h index 12a286921..40d3b6862 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -382,6 +382,7 @@ struct FMapThing int FloatbobPhase; int friendlyseeblocks; FName arg0str; + double SourceRadius; }; diff --git a/src/maploader/udmf.cpp b/src/maploader/udmf.cpp index 0750aad6f..fbde1f1f3 100644 --- a/src/maploader/udmf.cpp +++ b/src/maploader/udmf.cpp @@ -518,6 +518,7 @@ public: th->Alpha = -1; th->Health = 1; th->FloatbobPhase = -1; + th->SourceRadius = -1.0; sc.MustGetToken('{'); while (!sc.CheckToken('}')) { @@ -791,6 +792,10 @@ public: th->friendlyseeblocks = CheckInt(key); break; + case NAME_SourceRadius: + th->SourceRadius = (float)CheckFloat(key); + break; + case NAME_lm_suncolor: CHECK_N(Zd | Zdt) if (CheckInt(key) < 0 || CheckInt(key) > 0xFFFFFF) diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 189d3edc0..732076bb3 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -858,6 +858,9 @@ xx(lm_sampledist_ceiling) xx(lm_suncolor) xx(lm_dynamic) +// Light keywords +xx(SourceRadius) + xx(skew_bottom_type) xx(skew_middle_type) xx(skew_top_type) diff --git a/src/playsim/a_dynlight.cpp b/src/playsim/a_dynlight.cpp index dddb9f54e..42ccb8fef 100644 --- a/src/playsim/a_dynlight.cpp +++ b/src/playsim/a_dynlight.cpp @@ -115,6 +115,7 @@ void AttachLight(AActor *self) light->pPitch = &self->Angles.Pitch; light->pLightFlags = (LightFlags*)&self->IntVar(NAME_lightflags); light->pArgs = self->args; + light->pSourceRadius = &self->SourceRadius; light->specialf1 = DAngle::fromDeg(double(self->SpawnAngle)).Normalized360().Degrees(); light->Sector = self->Sector; light->target = self; diff --git a/src/playsim/a_dynlight.h b/src/playsim/a_dynlight.h index fdc80e09a..a73074b4f 100644 --- a/src/playsim/a_dynlight.h +++ b/src/playsim/a_dynlight.h @@ -130,6 +130,7 @@ protected: DAngle m_spotInnerAngle = DAngle::fromDeg(10.0); DAngle m_spotOuterAngle = DAngle::fromDeg(25.0); DAngle m_pitch = nullAngle; + double SourceRadius = 5.0; friend FSerializer &Serialize(FSerializer &arc, const char *key, FLightDefaults &value, FLightDefaults *def); }; @@ -222,6 +223,7 @@ struct FDynamicLight bool IsActive() const { return m_active; } float GetRadius() const { return (IsActive() ? m_currentRadius * 2.f : 0.f); } + float GetSourceRadius() const { return (float)(*pSourceRadius); } int GetRed() const { return pArgs[LIGHT_RED]; } int GetGreen() const { return pArgs[LIGHT_GREEN]; } int GetBlue() const { return pArgs[LIGHT_BLUE]; } @@ -268,6 +270,7 @@ public: const DAngle *pPitch; // This is to handle pitch overrides through GLDEFS, it can either point to the target's pitch or the light definition. const int *pArgs; const LightFlags *pLightFlags; + const double* pSourceRadius; // Softshadows. Physical size of the light source double specialf1; FDynamicLight *next, *prev; diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 5781f387e..fec32882c 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -1351,6 +1351,7 @@ public: int SpawnTime; uint32_t SpawnOrder; + double SourceRadius = 5.0; // Light source radius // ThingIDs void SetTID (int newTID); diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index bb449cdac..5474fdb3e 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -5829,6 +5829,8 @@ 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->SourceRadius >= 0.0) + mobj->SourceRadius = mthing->SourceRadius; // allow color strings for lights and reshuffle the args for spot lights if (i->IsDescendantOf(NAME_DynamicLight)) diff --git a/src/r_data/a_dynlightdata.cpp b/src/r_data/a_dynlightdata.cpp index c20c8d2e9..da451282e 100644 --- a/src/r_data/a_dynlightdata.cpp +++ b/src/r_data/a_dynlightdata.cpp @@ -126,6 +126,7 @@ void FLightDefaults::ApplyProperties(FDynamicLight * light) const light->lighttype = m_type; light->specialf1 = m_Param; light->pArgs = m_Args; + light->pSourceRadius = &SourceRadius; light->pLightFlags = &m_lightFlags; if (m_lightFlags & LF_SPOT) { diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 1da031938..e5eec3dc2 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -255,6 +255,8 @@ int DoomLevelMesh::GetLightIndex(FDynamicLight* light, int portalgroup) meshlight.Color.Y = light->GetGreen() * (1.0f / 255.0f); meshlight.Color.Z = light->GetBlue() * (1.0f / 255.0f); + meshlight.SourceRadius = light->GetSourceRadius(); + if (light->Sector) meshlight.SectorGroup = sectorGroup[light->Sector->Index()]; else diff --git a/src/rendering/hwrenderer/hw_dynlightdata.cpp b/src/rendering/hwrenderer/hw_dynlightdata.cpp index 4f2d53824..2414f2901 100644 --- a/src/rendering/hwrenderer/hw_dynlightdata.cpp +++ b/src/rendering/hwrenderer/hw_dynlightdata.cpp @@ -135,6 +135,7 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f spotDirY = float(-negPitch.Sin()); spotDirZ = float(-Angle.Sin() * xzLen); } + float sourceRadius = light->GetSourceRadius(); float *data = &dld.arrays[i][dld.arrays[i].Reserve(16)]; data[0] = float(pos.X); @@ -151,7 +152,7 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f data[11] = lightType; data[12] = spotInnerAngle; data[13] = spotOuterAngle; - data[14] = 0.0f; // unused + data[14] = sourceRadius; data[15] = 0.0f; // unused } diff --git a/wadsrc/static/shaders/lightmap/binding_lightmapper.glsl b/wadsrc/static/shaders/lightmap/binding_lightmapper.glsl index bd57caa4f..e23406f12 100644 --- a/wadsrc/static/shaders/lightmap/binding_lightmapper.glsl +++ b/wadsrc/static/shaders/lightmap/binding_lightmapper.glsl @@ -37,7 +37,7 @@ struct LightInfo float InnerAngleCos; float OuterAngleCos; vec3 SpotDir; - float Padding2; + float SourceRadius; vec3 Color; float Padding3; }; diff --git a/wadsrc/static/shaders/lightmap/trace_light.glsl b/wadsrc/static/shaders/lightmap/trace_light.glsl index 5a7cf1723..742e961e2 100644 --- a/wadsrc/static/shaders/lightmap/trace_light.glsl +++ b/wadsrc/static/shaders/lightmap/trace_light.glsl @@ -29,18 +29,25 @@ vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light, float extraDistance) #if defined(USE_SOFTSHADOWS) - vec3 v = (abs(dir.x) > abs(dir.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0); - vec3 xdir = normalize(cross(dir, v)); - vec3 ydir = cross(dir, xdir); - - float lightsize = 10; - int step_count = 10; - for (int i = 0; i < step_count; i++) + if (light.SourceRadius != 0.0) { - vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * lightsize; - vec3 pos = light.Origin + xdir * gridoffset.x + ydir * gridoffset.y; + vec3 v = (abs(dir.x) > abs(dir.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0); + vec3 xdir = normalize(cross(dir, v)); + vec3 ydir = cross(dir, xdir); - incoming += TracePointLightRay(origin, pos, minDistance, rayColor) / float(step_count); + float lightsize = light.SourceRadius; + int step_count = 10; + for (int i = 0; i < step_count; i++) + { + vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * lightsize; + vec3 pos = light.Origin + xdir * gridoffset.x + ydir * gridoffset.y; + + incoming += TracePointLightRay(origin, pos, minDistance, rayColor) / float(step_count); + } + } + else + { + incoming += TracePointLightRay(origin, light.Origin, minDistance, rayColor); } #else diff --git a/wadsrc/static/shaders/scene/light_shadow.glsl b/wadsrc/static/shaders/scene/light_shadow.glsl index 95fa46202..e46421345 100644 --- a/wadsrc/static/shaders/scene/light_shadow.glsl +++ b/wadsrc/static/shaders/scene/light_shadow.glsl @@ -182,7 +182,7 @@ vec2 getVogelDiskSample(int sampleIndex, int sampleCount, float phi) return vec2(cosine, sine) * r; } -float traceShadow(vec4 lightpos, int quality) +float traceShadow(vec4 lightpos, int quality, float sourceRadius) { vec3 origin = pixelpos.xyz; vec3 target = lightpos.xyz + 0.01; // nudge light position slightly as Doom maps tend to have their lights perfectly aligned with planes @@ -190,7 +190,7 @@ float traceShadow(vec4 lightpos, int quality) vec3 direction = normalize(target - origin); float dist = distance(origin, target); - if (quality == 0) + if (quality == 0 || sourceRadius == 0) { return traceHit(origin, direction, dist) ? 0.0 : 1.0; } @@ -204,7 +204,7 @@ float traceShadow(vec4 lightpos, int quality) int step_count = quality * 4; for (int i = 0; i < step_count; i++) { - vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * 3; + vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * sourceRadius; vec3 pos = target + xdir * gridoffset.x + ydir * gridoffset.y; sum += traceHit(origin, normalize(pos - origin), dist) ? 0.0 : 1.0; } @@ -212,11 +212,11 @@ float traceShadow(vec4 lightpos, int quality) } } -float shadowAttenuation(vec4 lightpos, float lightcolorA) +float shadowAttenuation(vec4 lightpos, float lightcolorA, float sourceRadius) { if (lightpos.w > 1000000.0) return 1.0; // Sunlight - return traceShadow(lightpos, uShadowmapFilter); + return traceShadow(lightpos, uShadowmapFilter, sourceRadius); } #elif defined(USE_SHADOWMAP) @@ -346,7 +346,7 @@ float shadowmapAttenuation(vec4 lightpos, float shadowIndex) } } -float shadowAttenuation(vec4 lightpos, float lightcolorA) +float shadowAttenuation(vec4 lightpos, float lightcolorA, float sourceRadius) { if (lightpos.w > 1000000.0) return 1.0; // Sunlight @@ -360,7 +360,7 @@ float shadowAttenuation(vec4 lightpos, float lightcolorA) #else -float shadowAttenuation(vec4 lightpos, float lightcolorA) +float shadowAttenuation(vec4 lightpos, float lightcolorA, float sourceRadius) { return 1.0; } diff --git a/wadsrc/static/shaders/scene/lightmodel_normal.glsl b/wadsrc/static/shaders/scene/lightmodel_normal.glsl index b9d25852c..894a3d972 100644 --- a/wadsrc/static/shaders/scene/lightmodel_normal.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_normal.glsl @@ -26,7 +26,7 @@ vec3 lightContribution(int i, vec3 normal) if (attenuation > 0.0) // Skip shadow map test if possible { - attenuation *= shadowAttenuation(lightpos, lightcolor.a); + attenuation *= shadowAttenuation(lightpos, lightcolor.a, lightspot2.z); return lightcolor.rgb * attenuation; } else diff --git a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl index 35c50bfc3..c87cbf52f 100644 --- a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl @@ -106,7 +106,7 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight) if (attenuation > 0.0) { - attenuation *= shadowAttenuation(lightpos, lightcolor.a); + attenuation *= shadowAttenuation(lightpos, lightcolor.a, lightspot2.z); vec3 radiance = lightcolor.rgb * attenuation; @@ -146,7 +146,7 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight) if (attenuation > 0.0) { - attenuation *= shadowAttenuation(lightpos, lightcolor.a); + attenuation *= shadowAttenuation(lightpos, lightcolor.a, lightspot2.z); vec3 radiance = lightcolor.rgb * attenuation; diff --git a/wadsrc/static/shaders/scene/lightmodel_specular.glsl b/wadsrc/static/shaders/scene/lightmodel_specular.glsl index 12eabd33e..b889034ab 100644 --- a/wadsrc/static/shaders/scene/lightmodel_specular.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_specular.glsl @@ -20,7 +20,7 @@ vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA) attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); if (attenuation > 0.0) // Skip shadow map test if possible - attenuation *= shadowAttenuation(lightpos, lightcolorA); + attenuation *= shadowAttenuation(lightpos, lightcolorA, lightspot2.z); if (attenuation <= 0.0) return vec2(0.0);