Add ZDRay light intensity support

This commit is contained in:
RaveYard 2023-09-06 15:15:58 +02:00 committed by Christoph Oelckers
parent 5a91e8573e
commit 98403698cd
4 changed files with 135 additions and 66 deletions

View file

@ -56,7 +56,6 @@ struct LevelMeshSurface
// Required for internal lightmapper:
//
// int portalDestinationIndex = -1; // line or sector index
int portalIndex = 0;
int sectorGroup = 0;
@ -83,8 +82,7 @@ struct LevelMeshSurface
TArray<FVector2> uvs;
// Touching light sources
std::vector<LevelMeshLight*> LightList;
std::vector<LevelMeshLight> LightListBuffer;
std::vector<const LevelMeshLight*> LightList;
// Lightmapper has a lot of additional padding around the borders
int lightmapperAtlasPage = -1;

View file

@ -144,7 +144,7 @@ void VkLightmap::RenderAtlasImage(size_t pageIndex)
vertices.Pos += vertexCount;
LightInfo* lightinfo = &lights.Lights[firstLight];
for (LevelMeshLight* light : surface->LightList)
for (const LevelMeshLight* light : surface->LightList)
{
lightinfo->Origin = light->Origin;
lightinfo->RelativeOrigin = light->RelativeOrigin;

View file

@ -174,19 +174,138 @@ void DoomLevelMesh::CreatePortals()
}
}
void DoomLevelMesh::UpdateLightLists()
void DoomLevelMesh::PropagateLight(const LevelMeshLight* light, std::set<LevelMeshPortal, RecursivePortalComparator>& touchedPortals, int lightPropagationRecursiveDepth)
{
for (auto& surface : Surfaces)
if (++lightPropagationRecursiveDepth > 32) // TODO is this too much?
{
if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING)
return;
}
SphereShape sphere;
sphere.center = FVector3(light->RelativeOrigin);
sphere.radius = light->Radius;
std::set<LevelMeshPortal, RecursivePortalComparator> portalsToErase;
for (int triangleIndex : TriangleMeshShape::find_all_hits(Collision.get(), &sphere))
{
auto& surface = Surfaces[MeshSurfaceIndexes[triangleIndex]];
// TODO skip any surface which isn't physically connected to the sector group in which the light resides
//if (light-> == surface.sectorGroup)
{
CreateLightList(&surface, surface.Subsector->section->lighthead, surface.Subsector->sector->PortalGroup);
}
else
{
CreateLightList(&surface, surface.Side->lighthead, surface.Side->sector->PortalGroup);
if (surface.portalIndex >= 0)
{
auto& portal = Portals[surface.portalIndex];
if (touchedPortals.insert(portal).second)
{
auto newLight = std::make_unique<LevelMeshLight>(*light);
auto fakeLight = newLight.get();
Lights.push_back(std::move(newLight));
fakeLight->RelativeOrigin = portal.TransformPosition(light->RelativeOrigin);
//fakeLight->sectorGroup = portal->targetSectorGroup;
PropagateLight(fakeLight, touchedPortals, lightPropagationRecursiveDepth);
portalsToErase.insert(portal);
}
}
// Add light to the list if it isn't already there
// TODO in order for this to work the light list be fed from global light buffer? Or just somehow de-duplicate portals?
bool found = false;
for (const LevelMeshLight* light2 : surface.LightList)
{
if (light2 == light)
{
found = true;
break;
}
}
if (!found)
surface.LightList.push_back(light);
}
}
for (auto& portal : portalsToErase)
{
touchedPortals.erase(portal); // Dear me: I wonder what was the reason for all of this.
}
}
void DoomLevelMesh::CreateLightList()
{
std::set<FDynamicLight*> lightList; // bit silly ain't it?
Lights.clear();
for (auto& surface : Surfaces)
{
surface.LightList.clear();
if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING)
{
auto node = surface.Subsector->section->lighthead;
while (node)
{
FDynamicLight* light = node->lightsource;
if (light->Trace())
{
if (lightList.insert(light).second)
{
DVector3 pos = light->Pos; //light->PosRelative(portalgroup);
LevelMeshLight meshlight;
meshlight.Origin = { (float)pos.X, (float)pos.Y, (float)pos.Z };
meshlight.RelativeOrigin = meshlight.Origin;
meshlight.Radius = (float)light->GetRadius();
meshlight.Intensity = light->target->Alpha;
if (light->IsSpot())
{
meshlight.InnerAngleCos = (float)light->pSpotInnerAngle->Cos();
meshlight.OuterAngleCos = (float)light->pSpotOuterAngle->Cos();
DAngle negPitch = -*light->pPitch;
DAngle Angle = light->target->Angles.Yaw;
double xzLen = negPitch.Cos();
meshlight.SpotDir.X = float(-Angle.Cos() * xzLen);
meshlight.SpotDir.Y = float(-negPitch.Sin());
meshlight.SpotDir.Z = float(-Angle.Sin() * xzLen);
}
else
{
meshlight.InnerAngleCos = -1.0f;
meshlight.OuterAngleCos = -1.0f;
meshlight.SpotDir.X = 0.0f;
meshlight.SpotDir.Y = 0.0f;
meshlight.SpotDir.Z = 0.0f;
}
meshlight.Color.X = light->GetRed() * (1.0f / 255.0f);
meshlight.Color.Y = light->GetGreen() * (1.0f / 255.0f);
meshlight.Color.Z = light->GetBlue() * (1.0f / 255.0f);
Lights.push_back(std::make_unique<LevelMeshLight>(meshlight));
}
}
node = node->nextLight;
}
}
}
std::set<LevelMeshPortal, RecursivePortalComparator> touchedPortals;
touchedPortals.insert(Portals[0]);
for (int i = 0, count = Lights.size(); i < count; ++i) // The array expands as the lights are duplicated/propagated
{
PropagateLight(Lights[i].get(), touchedPortals, 0);
}
}
void DoomLevelMesh::UpdateLightLists()
{
CreateLightList(); // full recreation
}
void DoomLevelMesh::BindLightmapSurfacesToGeometry(FLevelLocals& doomMap)
@ -296,58 +415,6 @@ void DoomLevelMesh::SetSideLightmap(DoomLevelMeshSurface* surface)
}
}
void DoomLevelMesh::CreateLightList(DoomLevelMeshSurface* surface, FLightNode* node, int portalgroup)
{
surface->LightListBuffer.clear();
surface->LightList.clear();
while (node)
{
FDynamicLight* light = node->lightsource;
if (light->Trace())
{
DVector3 pos = light->PosRelative(portalgroup);
LevelMeshLight meshlight;
meshlight.Origin = { (float)pos.X, (float)pos.Y, (float)pos.Z };
meshlight.RelativeOrigin = meshlight.Origin; // ?? what is the difference between this and Origin?
meshlight.Radius = (float)light->GetRadius();
meshlight.Intensity = light->target->Alpha;
if (light->IsSpot())
{
meshlight.InnerAngleCos = (float)light->pSpotInnerAngle->Cos();
meshlight.OuterAngleCos = (float)light->pSpotOuterAngle->Cos();
DAngle negPitch = -*light->pPitch;
DAngle Angle = light->target->Angles.Yaw;
double xzLen = negPitch.Cos();
meshlight.SpotDir.X = float(-Angle.Cos() * xzLen);
meshlight.SpotDir.Y = float(-negPitch.Sin());
meshlight.SpotDir.Z = float(-Angle.Sin() * xzLen);
}
else
{
meshlight.InnerAngleCos = -1.0f;
meshlight.OuterAngleCos = -1.0f;
meshlight.SpotDir.X = 0.0f;
meshlight.SpotDir.Y = 0.0f;
meshlight.SpotDir.Z = 0.0f;
}
meshlight.Color.X = light->GetRed() * (1.0f / 255.0f);
meshlight.Color.Y = light->GetGreen() * (1.0f / 255.0f);
meshlight.Color.Z = light->GetBlue() * (1.0f / 255.0f);
surface->LightListBuffer.push_back(meshlight);
}
node = node->nextLight;
}
for (auto& silly : surface->LightListBuffer)
surface->LightList.push_back(&silly);
}
void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
{
sector_t *front;

View file

@ -8,6 +8,8 @@
#include "bounds.h"
#include <dp_rect_pack.h>
#include <set>
typedef dp::rect_pack::RectPacker<int> RectPacker;
struct FLevelLocals;
@ -43,7 +45,7 @@ public:
int GetSurfaceCount() override { return Surfaces.Size(); }
TArray<DoomLevelMeshSurface> Surfaces;
std::vector<std::unique_ptr<LevelMeshLight>> Lights;
TArray<FVector2> LightmapUvs;
static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2);
@ -63,7 +65,9 @@ private:
void SetSubsectorLightmap(DoomLevelMeshSurface* surface);
void SetSideLightmap(DoomLevelMeshSurface* surface);
void CreateLightList(DoomLevelMeshSurface* surface, FLightNode* lighthead, int portalgroup);
void PropagateLight(const LevelMeshLight* light, std::set<LevelMeshPortal, RecursivePortalComparator>& touchedPortals, int lightPropagationRecursiveDepth);
void CreateLightList();
static bool IsTopSideSky(sector_t* frontsector, sector_t* backsector, side_t* side);
static bool IsTopSideVisible(side_t* side);