- added some checks to exclude dynamic lights from being subjected to shadowmapping if they do not touch any one-sided lines from the back side. This condition is a requirement for a 1D shadowmap to even have an effect.

This commit is contained in:
Christoph Oelckers 2017-03-20 00:34:19 +01:00
parent 0721aef218
commit 1031481167
4 changed files with 50 additions and 21 deletions

View file

@ -568,6 +568,7 @@ void ADynamicLight::CollectWithinRadius(const DVector3 &opos, subsector_t *subSe
collected_ss.Push({ subSec, opos }); collected_ss.Push({ subSec, opos });
subSec->validcount = ::validcount; subSec->validcount = ::validcount;
bool hitonesidedback = false;
for (unsigned i = 0; i < collected_ss.Size(); i++) for (unsigned i = 0; i < collected_ss.Size(); i++)
{ {
subSec = collected_ss[i].sub; subSec = collected_ss[i].sub;
@ -596,6 +597,10 @@ void ADynamicLight::CollectWithinRadius(const DVector3 &opos, subsector_t *subSe
seg->linedef->validcount = validcount; seg->linedef->validcount = validcount;
touching_sides = AddLightNode(&seg->sidedef->lighthead, seg->sidedef, this, touching_sides); touching_sides = AddLightNode(&seg->sidedef->lighthead, seg->sidedef, this, touching_sides);
} }
else if (seg->linedef->sidedef[0] == seg->sidedef && seg->linedef->sidedef[1] == nullptr)
{
hitonesidedback = true;
}
} }
if (seg->linedef) if (seg->linedef)
{ {
@ -657,6 +662,7 @@ void ADynamicLight::CollectWithinRadius(const DVector3 &opos, subsector_t *subSe
} }
} }
} }
shadowmapped = hitonesidedback && !(flags4 & MF4_NOSHADOWMAP);
} }
//========================================================================== //==========================================================================
@ -758,6 +764,7 @@ void ADynamicLight::UnlinkLight ()
while (touching_sides) touching_sides = DeleteLightNode(touching_sides); while (touching_sides) touching_sides = DeleteLightNode(touching_sides);
while (touching_subsectors) touching_subsectors = DeleteLightNode(touching_subsectors); while (touching_subsectors) touching_subsectors = DeleteLightNode(touching_subsectors);
while (touching_sector) touching_sector = DeleteLightNode(touching_sector); while (touching_sector) touching_sector = DeleteLightNode(touching_sector);
shadowmapped = false;
} }
void ADynamicLight::OnDestroy() void ADynamicLight::OnDestroy()
@ -771,7 +778,7 @@ CCMD(listlights)
{ {
int walls, sectors, subsecs; int walls, sectors, subsecs;
int allwalls=0, allsectors=0, allsubsecs = 0; int allwalls=0, allsectors=0, allsubsecs = 0;
int i=0; int i=0, shadowcount = 0;
ADynamicLight * dl; ADynamicLight * dl;
TThinkerIterator<ADynamicLight> it; TThinkerIterator<ADynamicLight> it;
@ -780,11 +787,12 @@ CCMD(listlights)
walls=0; walls=0;
sectors=0; sectors=0;
subsecs = 0; subsecs = 0;
Printf("%s at (%f, %f, %f), color = 0x%02x%02x%02x, radius = %f %s", Printf("%s at (%f, %f, %f), color = 0x%02x%02x%02x, radius = %f %s %s",
dl->target? dl->target->GetClass()->TypeName.GetChars() : dl->GetClass()->TypeName.GetChars(), dl->target? dl->target->GetClass()->TypeName.GetChars() : dl->GetClass()->TypeName.GetChars(),
dl->X(), dl->Y(), dl->Z(), dl->args[LIGHT_RED], dl->X(), dl->Y(), dl->Z(), dl->args[LIGHT_RED],
dl->args[LIGHT_GREEN], dl->args[LIGHT_BLUE], dl->radius, (dl->flags4 & MF4_ATTENUATE)? "attenuated" : ""); dl->args[LIGHT_GREEN], dl->args[LIGHT_BLUE], dl->radius, (dl->flags4 & MF4_ATTENUATE)? "attenuated" : "", dl->shadowmapped? "shadowmapped" : "");
i++; i++;
shadowcount += dl->shadowmapped;
if (dl->target) if (dl->target)
{ {
@ -824,7 +832,7 @@ CCMD(listlights)
Printf("- %d walls, %d subsectors, %d sectors\n", walls, subsecs, sectors); Printf("- %d walls, %d subsectors, %d sectors\n", walls, subsecs, sectors);
} }
Printf("%i dynamic lights, %d walls, %d subsectors, %d sectors\n\n\n", i, allwalls, allsubsecs, allsectors); Printf("%i dynamic lights, %d shadowmapped, %d walls, %d subsectors, %d sectors\n\n\n", i, shadowcount, allwalls, allsubsecs, allsectors);
} }
CCMD(listsublights) CCMD(listsublights)

View file

@ -21,11 +21,12 @@ enum
LIGHT_SCALE = 3, LIGHT_SCALE = 3,
}; };
// This is as good as something new - and it can be set directly in the ActorInfo! // This is as good as something new
#define MF4_SUBTRACTIVE MF4_MISSILEEVENMORE #define MF4_SUBTRACTIVE MF4_MISSILEEVENMORE
#define MF4_ADDITIVE MF4_MISSILEMORE #define MF4_ADDITIVE MF4_MISSILEMORE
#define MF4_DONTLIGHTSELF MF4_SEESDAGGERS #define MF4_DONTLIGHTSELF MF4_SEESDAGGERS
#define MF4_ATTENUATE MF4_INCOMBAT #define MF4_ATTENUATE MF4_INCOMBAT
#define MF4_NOSHADOWMAP MF4_STANDSTILL
enum ELightType enum ELightType
{ {
@ -117,6 +118,7 @@ public:
uint8_t color2[3]; uint8_t color2[3];
bool visibletoplayer; bool visibletoplayer;
bool swapped; bool swapped;
bool shadowmapped;
int bufferindex; int bufferindex;

View file

@ -116,35 +116,43 @@ bool FShadowMap::IsEnabled() const
int FShadowMap::ShadowMapIndex(ADynamicLight *light) int FShadowMap::ShadowMapIndex(ADynamicLight *light)
{ {
if (IsEnabled()) if (IsEnabled())
return mLightToShadowmap[light]; {
else auto val = mLightToShadowmap.CheckKey(light);
return 1024; if (val != nullptr) return *val;
}
return 1024;
} }
void FShadowMap::UploadLights() void FShadowMap::UploadLights()
{ {
mLights.Clear(); if (mLights.Size() != 1024 * 4) mLights.Resize(1024 * 4);
int lightindex = 0;
mLightToShadowmap.Clear(mLightToShadowmap.CountUsed() * 2); // To do: allow clearing a TMap while building up a reserve mLightToShadowmap.Clear(mLightToShadowmap.CountUsed() * 2); // To do: allow clearing a TMap while building up a reserve
// Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred.
TThinkerIterator<ADynamicLight> it(STAT_DLIGHT); TThinkerIterator<ADynamicLight> it(STAT_DLIGHT);
while (true) while (auto light = it.Next())
{ {
ADynamicLight *light = it.Next(); if (light->shadowmapped)
if (!light) break; {
mLightToShadowmap[light] = lightindex >> 2;
mLightToShadowmap[light] = mLights.Size() / 4; mLights[lightindex] = light->X();
mLights[lightindex+1] = light->Y();
mLights[lightindex+2] = light->Z();
mLights[lightindex+3] = light->GetRadius();
lightindex += 4;
mLights.Push(light->X()); if (lightindex == 1024*4) // Only 1024 lights for now
mLights.Push(light->Y()); break;
mLights.Push(light->Z()); }
mLights.Push(light->GetRadius());
if (mLights.Size() == 1024) // Only 1024 lights for now
break;
} }
while (mLights.Size() < 1024 * 4) for (; lightindex < 1024 * 4; lightindex++)
mLights.Push(0.0f); {
mLights[lightindex] = 0;
}
if (mLightList == 0) if (mLightList == 0)
glGenBuffers(1, (GLuint*)&mLightList); glGenBuffers(1, (GLuint*)&mLightList);

View file

@ -60,6 +60,7 @@
#include "r_data/sprites.h" #include "r_data/sprites.h"
#include "serializer.h" #include "serializer.h"
#include "wi_stuff.h" #include "wi_stuff.h"
#include "a_dynlight.h"
static TArray<FPropertyInfo*> properties; static TArray<FPropertyInfo*> properties;
static TArray<AFuncDesc> AFTable; static TArray<AFuncDesc> AFTable;
@ -479,6 +480,16 @@ static FFlagDef PlayerPawnFlagDefs[] =
DEFINE_FLAG(PPF, CROUCHABLEMORPH, APlayerPawn, PlayerFlags), DEFINE_FLAG(PPF, CROUCHABLEMORPH, APlayerPawn, PlayerFlags),
}; };
static FFlagDef DynLightFlagDefs[] =
{
// PlayerPawn flags
DEFINE_FLAG(MF4, SUBTRACTIVE, ADynamicLight, flags4),
DEFINE_FLAG(MF4, ADDITIVE, ADynamicLight, flags4),
DEFINE_FLAG(MF4, DONTLIGHTSELF, ADynamicLight, flags4),
DEFINE_FLAG(MF4, ATTENUATE, ADynamicLight, flags4),
DEFINE_FLAG(MF4, NOSHADOWMAP, ADynamicLight, flags4),
};
static FFlagDef PowerSpeedFlagDefs[] = static FFlagDef PowerSpeedFlagDefs[] =
{ {
// PowerSpeed flags // PowerSpeed flags