From 0a7108c3b1015995cbdd1ffe7ce01cf21bc78651 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 17 Oct 2023 18:29:27 +0200 Subject: [PATCH] Add lights --- src/lightmapper/doom_levelmesh.cpp | 96 +++++++++++++++++++++++++++++- src/lightmapper/doom_levelmesh.h | 14 ++++- src/lightmapper/gpuraytracer.cpp | 15 ++--- 3 files changed, 114 insertions(+), 11 deletions(-) diff --git a/src/lightmapper/doom_levelmesh.cpp b/src/lightmapper/doom_levelmesh.cpp index fc41b3e..59e6087 100644 --- a/src/lightmapper/doom_levelmesh.cpp +++ b/src/lightmapper/doom_levelmesh.cpp @@ -5,6 +5,7 @@ #include "framework/binfile.h" #include #include +#include extern float lm_scale; @@ -13,16 +14,42 @@ DoomLevelMesh::DoomLevelMesh(FLevel& doomMap, int samples, int lmdims) SunColor = doomMap.defaultSunColor; // TODO keep only one copy? SunDirection = doomMap.defaultSunDirection; + printf(" Building level mesh\n"); + StaticMesh = std::make_unique(); static_cast(StaticMesh.get())->CreateStatic(doomMap); static_cast(StaticMesh.get())->PackLightmapAtlas(0); static_cast(StaticMesh.get())->BindLightmapSurfacesToGeometry(doomMap); + + BuildLightLists(doomMap); } int DoomLevelMesh::AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) { - return 0; + const DoomLevelMeshSurface* doomsurface = static_cast(surface); + int listpos = 0; + for (ThingLight* light : doomsurface->LightList) + { + if (listpos == listMaxSize) + break; + + LevelMeshLight& meshlight = list[listpos++]; + meshlight.Origin = light->LightOrigin(); + meshlight.RelativeOrigin = light->LightRelativeOrigin(); + meshlight.Radius = light->LightRadius(); + meshlight.Intensity = light->intensity; + meshlight.InnerAngleCos = light->innerAngleCos; + meshlight.OuterAngleCos = light->outerAngleCos; + meshlight.SpotDir = light->SpotDir(); + meshlight.Color = light->rgb; + + /*if (light->sector) + meshlight.SectorGroup = static_cast(StaticMesh.get())->sectorGroup[light->sector->Index()]; + else*/ + meshlight.SectorGroup = 0; + } + return listpos; } void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilename) const @@ -202,6 +229,73 @@ void DoomLevelMesh::AddLightmapLump(FLevel& doomMap, FWadWriter& wadFile) zout.Write(buffer.data(), (int)(ptrdiff_t)(lumpFile.BufferAt() - lumpFile.Buffer())); } +void DoomLevelMesh::PropagateLight(FLevel& doomMap, ThingLight* light, int recursiveDepth) +{ + if (recursiveDepth > 32) + return; + + auto submesh = static_cast(StaticMesh.get()); + + SphereShape sphere; + sphere.center = light->LightRelativeOrigin(); + sphere.radius = light->LightRadius(); + //std::set portalsToErase; + for (int triangleIndex : TriangleMeshShape::find_all_hits(submesh->Collision.get(), &sphere)) + { + DoomLevelMeshSurface* surface = &submesh->Surfaces[submesh->MeshSurfaceIndexes[triangleIndex]]; + + // skip any surface which isn't physically connected to the sector group in which the light resides + //if (light->sectorGroup == surface->sectorGroup) + { + /*if (surface->portalIndex >= 0) + { + auto portal = portals[surface->portalIndex].get(); + + if (touchedPortals.insert(*portal).second) + { + auto fakeLight = std::make_unique(*light); + + fakeLight->relativePosition.emplace(portal->TransformPosition(light->LightRelativeOrigin())); + fakeLight->sectorGroup = portal->targetSectorGroup; + + PropagateLight(doomMap, fakeLight.get(), recursiveDepth + 1); + portalsToErase.insert(*portal); + portalLights.push_back(std::move(fakeLight)); + } + }*/ + + // Add light to the list if it isn't already there + bool found = false; + for (ThingLight* light2 : surface->LightList) + { + if (light2 == light) + { + found = true; + break; + } + } + if (!found) + surface->LightList.push_back(light); + } + } + + /*for (auto& portal : portalsToErase) + { + touchedPortals.erase(portal); + }*/ +} + +void DoomLevelMesh::BuildLightLists(FLevel& doomMap) +{ + for (unsigned i = 0; i < doomMap.ThingLights.Size(); ++i) + { + printf(" Building light lists: %u / %u\r", i, doomMap.ThingLights.Size()); + PropagateLight(doomMap, &doomMap.ThingLights[i]); + } + + printf(" Building light lists: %u / %u\n", doomMap.ThingLights.Size(), doomMap.ThingLights.Size()); +} + ///////////////////////////////////////////////////////////////////////////// void DoomLevelSubmesh::CreateStatic(FLevel& doomMap) diff --git a/src/lightmapper/doom_levelmesh.h b/src/lightmapper/doom_levelmesh.h index 15db55e..d356fa1 100644 --- a/src/lightmapper/doom_levelmesh.h +++ b/src/lightmapper/doom_levelmesh.h @@ -14,8 +14,18 @@ public: int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) override; void DumpMesh(const FString& objFilename, const FString& mtlFilename) const; - void AddLightmapLump(FLevel& doomMap, FWadWriter& out); + +private: + void BuildLightLists(FLevel& doomMap); + void PropagateLight(FLevel& doomMap, ThingLight* light, int recursiveDepth = 0); + + // Portal to portals[] index + //std::map portalCache; + + // Portal lights + //std::vector> portalLights; + //std::set touchedPortals; }; enum DoomLevelMeshSurfaceType @@ -38,6 +48,8 @@ struct DoomLevelMeshSurface : public LevelMeshSurface IntSector* ControlSector = nullptr; float* TexCoords = nullptr; + + std::vector LightList; }; class DoomLevelSubmesh : public LevelSubmesh diff --git a/src/lightmapper/gpuraytracer.cpp b/src/lightmapper/gpuraytracer.cpp index 49f10fb..3cd20d3 100644 --- a/src/lightmapper/gpuraytracer.cpp +++ b/src/lightmapper/gpuraytracer.cpp @@ -32,26 +32,22 @@ void GPURaytracer::Raytrace(DoomLevelMesh* mesh) QueryPerformanceCounter(&s); #endif - printf(" Ray tracing in progress\n"); - printf(" ["); - try { auto raytrace = mDevice->GetRaytrace(); auto lightmap = mDevice->GetLightmap(); auto submesh = mesh->StaticMesh.get(); + printf(" Map uses %u lightmap textures\n", submesh->LMTextureCount); + mDevice->GetTextureManager()->CreateLightmap(submesh->LMTextureSize, submesh->LMTextureCount); - printf("."); raytrace->SetLevelMesh(mesh); lightmap->SetLevelMesh(mesh); // Keep baking until all surfaces have been processed while (true) { - printf("."); - raytrace->BeginFrame(); lightmap->BeginFrame(); @@ -68,12 +64,14 @@ void GPURaytracer::Raytrace(DoomLevelMesh* mesh) if (surfaces.Size() == 0) break; + printf(" Ray tracing surfaces: %u / %u\r", submesh->GetSurfaceCount() - surfaces.Size(), submesh->GetSurfaceCount()); + lightmap->Raytrace(surfaces); mDevice->GetCommands()->SubmitAndWait(); } - printf("."); + printf(" Ray tracing surfaces: %u / %u\n", submesh->GetSurfaceCount(), submesh->GetSurfaceCount()); submesh->LMTextureData.Resize(submesh->LMTextureSize * submesh->LMTextureSize * submesh->LMTextureCount * 4); for (int arrayIndex = 0; arrayIndex < submesh->LMTextureCount; arrayIndex++) @@ -83,10 +81,9 @@ void GPURaytracer::Raytrace(DoomLevelMesh* mesh) } catch (...) { - printf("]\n"); + printf("\n"); throw; } - printf("]\n"); #ifdef WIN32 LARGE_INTEGER e, f;