Refactor light propagation

This commit is contained in:
RaveYard 2022-10-30 16:12:06 +01:00
parent 22f24e7993
commit ea5b1a3cac
3 changed files with 39 additions and 36 deletions

View file

@ -178,16 +178,9 @@ void LevelMesh::BuildSmoothingGroups(FLevel& doomMap)
printf("Created %d smoothing groups for %d surfaces\n\n", (int)smoothingGroups.size(), (int)surfaces.size()); printf("Created %d smoothing groups for %d surfaces\n\n", (int)smoothingGroups.size(), (int)surfaces.size());
} }
#include <set> // hack
std::set<Portal, RejectRecursivePortals> touchedPortals;
int depth = 0;
void LevelMesh::PropagateLight(FLevel& doomMap, ThingLight *light) void LevelMesh::PropagateLight(FLevel& doomMap, ThingLight *light)
{ {
// Because of sectorGroups, this will unlikely get this deep anyway if (lightPropagationRecursiveDepth > 32)
if (depth > 32)
{ {
return; return;
} }
@ -195,17 +188,17 @@ void LevelMesh::PropagateLight(FLevel& doomMap, ThingLight *light)
SphereShape sphere; SphereShape sphere;
sphere.center = light->LightRelativeOrigin(); sphere.center = light->LightRelativeOrigin();
sphere.radius = light->LightRadius(); sphere.radius = light->LightRadius();
depth++; lightPropagationRecursiveDepth++;
std::set<Portal, RejectRecursivePortals> portalsToErase; std::set<Portal, RecursivePortalComparator> portalsToErase;
for (int triangleIndex : TriangleMeshShape::find_all_hits(Collision.get(), &sphere)) for (int triangleIndex : TriangleMeshShape::find_all_hits(Collision.get(), &sphere))
{ {
Surface* surface = surfaces[MeshSurfaces[triangleIndex]].get(); Surface* surface = surfaces[MeshSurfaces[triangleIndex]].get();
// Reject any surface which isn't physically connected to the sector group in which the light resided
// skip any surface which isn't physically connected to the sector group in which the light resides
if (light->sectorGroup == surface->sectorGroup) if (light->sectorGroup == surface->sectorGroup)
{ {
if (surface->portalIndex >= 0) if (surface->portalIndex >= 0)
{ {
auto portal = portals[surface->portalIndex].get(); auto portal = portals[surface->portalIndex].get();
if (touchedPortals.insert(*portal).second) if (touchedPortals.insert(*portal).second)
@ -240,7 +233,8 @@ void LevelMesh::PropagateLight(FLevel& doomMap, ThingLight *light)
{ {
touchedPortals.erase(portal); touchedPortals.erase(portal);
} }
depth--;
lightPropagationRecursiveDepth--;
} }
void LevelMesh::BuildLightLists(FLevel& doomMap) void LevelMesh::BuildLightLists(FLevel& doomMap)

View file

@ -32,6 +32,7 @@
#include <string> #include <string>
#include <cstring> #include <cstring>
#include <map> #include <map>
#include <set>
#include "framework/tarray.h" #include "framework/tarray.h"
#include "framework/halffloat.h" #include "framework/halffloat.h"
@ -154,9 +155,14 @@ public:
std::unique_ptr<TriangleMeshShape> Collision; std::unique_ptr<TriangleMeshShape> Collision;
private: private:
std::vector<std::unique_ptr<ThingLight>> portalLights; // Portal generated lights // Portal to portals[] index
std::map<Portal, int, IdenticalPortalComparator> portalCache; std::map<Portal, int, IdenticalPortalComparator> portalCache;
// Portal lights
std::vector<std::unique_ptr<ThingLight>> portalLights;
std::set<Portal, RecursivePortalComparator> touchedPortals;
int lightPropagationRecursiveDepth = 0;
void CreateSubsectorSurfaces(FLevel &doomMap); void CreateSubsectorSurfaces(FLevel &doomMap);
void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor); void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor);
void CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor); void CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor);

View file

@ -20,51 +20,54 @@ struct Portal
return vec3(v.x, v.y, v.z); return vec3(v.x, v.y, v.z);
} }
// Check if the portal is inverse // Checks only transformation
inline bool IsInversePortal(const Portal& portal) const inline bool IsInverseTransformationPortal(const Portal& portal) const
{ {
auto diff = portal.TransformPosition(TransformPosition(vec3(0))); auto diff = portal.TransformPosition(TransformPosition(vec3(0)));
return abs(diff.x) < 0.001 && abs(diff.y) < 0.001 && abs(diff.z) < 0.001; return abs(diff.x) < 0.001 && abs(diff.y) < 0.001 && abs(diff.z) < 0.001;
} }
// Check if the portal transformation is equal // Checks only transformation
inline bool IsEqualPortal(const Portal& portal) const inline bool IsEqualTransformationPortal(const Portal& portal) const
{ {
auto diff = portal.TransformPosition(vec3(0)) - TransformPosition(vec3(0)); auto diff = portal.TransformPosition(vec3(0)) - TransformPosition(vec3(0));
return (abs(diff.x) < 0.001 && abs(diff.y) < 0.001 && abs(diff.z) < 0.001); return (abs(diff.x) < 0.001 && abs(diff.y) < 0.001 && abs(diff.z) < 0.001);
} }
// Do both portals travel from sector group A to sector group B?
inline bool IsTravelingBetweenSameSectorGroups(const Portal& portal) const // Checks transformation, source and destiantion sector groups
inline bool IsEqualPortal(const Portal& portal) const
{ {
return sourceSectorGroup == portal.sourceSectorGroup && targetSectorGroup == portal.targetSectorGroup; return sourceSectorGroup == portal.sourceSectorGroup && targetSectorGroup == portal.targetSectorGroup && IsEqualTransformationPortal(portal);
}
// Checks transformation, source and destiantion sector groups
inline bool IsInversePortal(const Portal& portal) const
{
return sourceSectorGroup == portal.targetSectorGroup && targetSectorGroup == portal.sourceSectorGroup && IsInverseTransformationPortal(portal);
}
inline void DumpInfo()
{
auto v = TransformPosition(vec3(0));
printf("Portal offset: %.3f %.3f %.3f\n\tsource group:\t%d\n\ttarget group:\t%d", v.x, v.y, v.z, sourceSectorGroup, targetSectorGroup);
} }
}; };
// for use with std::set to recursively go through portals // for use with std::set to recursively go through portals and skip returning portals
struct RejectRecursivePortals struct RecursivePortalComparator
{ {
inline bool IsEqual(const Portal& a, const Portal& b) const
{
return a.IsInversePortal(b) || a.IsEqualPortal(b);
}
bool operator()(const Portal& a, const Portal& b) const bool operator()(const Portal& a, const Portal& b) const
{ {
return !IsEqual(a, b) && std::memcmp(&a.transformation, &b.transformation, sizeof(mat4)) < 0; return !a.IsInversePortal(b) && std::memcmp(&a.transformation, &b.transformation, sizeof(mat4)) < 0;
} }
}; };
// for use with std::map to reject portals which have equal transformation between equal sector groups // for use with std::map to reject portals which have the same effect for light rays
struct IdenticalPortalComparator struct IdenticalPortalComparator
{ {
inline bool IsEqual(const Portal& a, const Portal& b) const
{
return a.IsEqualPortal(b) && a.IsTravelingBetweenSameSectorGroups(b);
}
bool operator()(const Portal& a, const Portal& b) const bool operator()(const Portal& a, const Portal& b) const
{ {
return !IsEqual(a, b) && std::memcmp(&a.transformation, &b.transformation, sizeof(mat4)) < 0; return !a.IsEqualPortal(b) && std::memcmp(&a.transformation, &b.transformation, sizeof(mat4)) < 0;
} }
}; };