Cache the result of traces so that it only needs to be done for visible moving actors

This commit is contained in:
Magnus Norddahl 2023-04-07 18:44:59 +02:00 committed by Christoph Oelckers
parent d97f9f3055
commit e1b333432d
2 changed files with 67 additions and 17 deletions

View file

@ -1576,6 +1576,11 @@ public:
bool hasmodel;
struct
{
DVector3 Pos = DVector3(-12345678.0, -12345678.0, -12345678.0);
uint64_t Bits = 0;
} StaticLightsTraceCache;
};
class FActorIterator

View file

@ -46,23 +46,64 @@ T smoothstep(const T edge0, const T edge1, const T x)
return t * t * (3.0 - 2.0 * t);
}
static bool TraceLightVisbility(FLightNode* node, const FVector3& L, float dist)
class ActorTraceStaticLight
{
FDynamicLight* light = node->lightsource;
if (!light->Trace() || !level.levelMesh)
return true;
public:
ActorTraceStaticLight(AActor* actor) : Actor(actor)
{
if (Actor->Pos() != Actor->StaticLightsTraceCache.Pos)
{
Actor->StaticLightsTraceCache.Pos = Actor->Pos();
Actor->StaticLightsTraceCache.Bits = 0;
ActorMoved = true;
}
}
// Note: this is not thread safe (modifies validcount and calls other setup functions)
// FTraceResults results;
// return !Trace(light->Pos, light->Sector, DVector3(-L.X, -L.Y, -L.Z), dist, 0, ML_BLOCKING, nullptr, results);
bool TraceLightVisbility(FLightNode* node, const FVector3& L, float dist)
{
FDynamicLight* light = node->lightsource;
if (!light->Trace() || !level.levelMesh)
return true;
return level.levelMesh->Trace(FVector3((float)light->Pos.X, (float)light->Pos.Y, (float)light->Pos.Z), FVector3(-L.X, -L.Y, -L.Z), dist);
}
if (!ActorMoved && CurrentBit < 64)
{
bool traceResult = (Actor->StaticLightsTraceCache.Bits >> CurrentBit) & 1;
CurrentBit++;
return traceResult;
}
else
{
bool traceResult = level.levelMesh->Trace(FVector3((float)light->Pos.X, (float)light->Pos.Y, (float)light->Pos.Z), FVector3(-L.X, -L.Y, -L.Z), dist);
Actor->StaticLightsTraceCache.Bits |= ((uint64_t)traceResult) << CurrentBit;
CurrentBit++;
return traceResult;
}
}
static bool TraceSunVisibility(float x, float y, float z)
{
return level.LMTextureCount != 0 && level.levelMesh->TraceSky(FVector3(x, y, z), level.SunDirection, 10000.0f);
}
bool TraceSunVisibility(float x, float y, float z)
{
if (level.LMTextureCount == 0)
return false;
if (!ActorMoved && CurrentBit < 64)
{
bool traceResult = (Actor->StaticLightsTraceCache.Bits >> CurrentBit) & 1;
CurrentBit++;
return traceResult;
}
else
{
bool traceResult = level.levelMesh->TraceSky(FVector3(x, y, z), level.SunDirection, 10000.0f);
Actor->StaticLightsTraceCache.Bits |= ((uint64_t)traceResult) << CurrentBit;
CurrentBit++;
return traceResult;
}
}
AActor* Actor;
bool ActorMoved = false;
int CurrentBit = 0;
};
//==========================================================================
//
@ -78,7 +119,9 @@ void HWDrawInfo::GetDynSpriteLight(AActor *self, float x, float y, float z, FLig
out[0] = out[1] = out[2] = 0.f;
if (TraceSunVisibility(x, y, z))
ActorTraceStaticLight staticLight(self);
if (staticLight.TraceSunVisibility(x, y, z))
{
out[0] = Level->SunColor.X;
out[1] = Level->SunColor.Y;
@ -121,7 +164,7 @@ void HWDrawInfo::GetDynSpriteLight(AActor *self, float x, float y, float z, FLig
if (light->IsSpot() || light->Trace())
L *= -1.0f / dist;
if (TraceLightVisbility(node, L, dist))
if (staticLight.TraceLightVisbility(node, L, dist))
{
frac = 1.0f - (dist / radius);
@ -195,7 +238,9 @@ void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata)
float radiusSquared = actorradius * actorradius;
dl_validcount++;
if (TraceSunVisibility(x, y, z))
ActorTraceStaticLight staticLight(self);
if (staticLight.TraceSunVisibility(x, y, z))
{
AddSunLightToList(modellightdata, x, y, z, self->Level->SunDirection, self->Level->SunColor);
}
@ -226,7 +271,7 @@ void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata)
if (light->Trace())
L *= 1.0f / dist;
if (TraceLightVisbility(node, L, dist))
if (staticLight.TraceLightVisbility(node, L, dist))
{
AddLightToList(modellightdata, group, light, true);
}