From c05ef6767905b9c0cfcdb9a0123305db4602e99a Mon Sep 17 00:00:00 2001 From: RaveYard <29225776+MrRaveYard@users.noreply.github.com> Date: Wed, 6 Sep 2023 15:15:58 +0200 Subject: [PATCH] Add ZDRay light intensity support --- .../rendering/hwrenderer/data/hw_levelmesh.h | 4 +- .../vulkan/accelstructs/vk_lightmap.cpp | 2 +- src/rendering/hwrenderer/doom_levelmesh.cpp | 187 ++++++++++++------ src/rendering/hwrenderer/doom_levelmesh.h | 8 +- 4 files changed, 135 insertions(+), 66 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index f7343c106..9a3648c63 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -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 uvs; // Touching light sources - std::vector LightList; - std::vector LightListBuffer; + std::vector LightList; // Lightmapper has a lot of additional padding around the borders int lightmapperAtlasPage = -1; diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp index 119413f7b..977a9f226 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -143,7 +143,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; diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 866733499..e47c27c0b 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -174,19 +174,138 @@ void DoomLevelMesh::CreatePortals() } } -void DoomLevelMesh::UpdateLightLists() +void DoomLevelMesh::PropagateLight(const LevelMeshLight* light, std::set& 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 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(*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 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(meshlight)); + } + } + + node = node->nextLight; + } + } + } + + std::set 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; diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 93ff54407..8205337e2 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -8,6 +8,8 @@ #include "bounds.h" #include +#include + typedef dp::rect_pack::RectPacker RectPacker; struct FLevelLocals; @@ -43,7 +45,7 @@ public: int GetSurfaceCount() override { return Surfaces.Size(); } TArray Surfaces; - + std::vector> Lights; TArray 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& touchedPortals, int lightPropagationRecursiveDepth); + void CreateLightList(); + static bool IsTopSideSky(sector_t* frontsector, sector_t* backsector, side_t* side); static bool IsTopSideVisible(side_t* side);