WIP partial lightmapping

This commit is contained in:
RaveYard 2023-09-07 23:27:20 +02:00 committed by Christoph Oelckers
parent 5fc7a4dc41
commit d19a73641a
10 changed files with 84 additions and 7 deletions

View file

@ -52,6 +52,8 @@ struct LevelMeshSurface
int texWidth = 0;
int texHeight = 0;
bool needsUpdate = true;
//
// Required for internal lightmapper:
//

View file

@ -3,6 +3,7 @@
#include "vectors.h"
#include "matrix.h"
#include "hw_material.h"
#include "hw_levelmesh.h"
#include "texmanip.h"
#include "version.h"
#include "i_interface.h"
@ -257,6 +258,7 @@ protected:
EPassType mPassType = NORMAL_PASS;
TArray<LevelMeshSurface*> mActiveLightmapSurfaces;
public:
uint64_t firstFrame = 0;
@ -729,6 +731,22 @@ public:
return SetViewpoint(matrices);
}
inline void PushVisibleSurface(LevelMeshSurface* surface)
{
if(surface && surface->needsUpdate && mActiveLightmapSurfaces.Find(surface) >= mActiveLightmapSurfaces.Size()) // yikes, how awful
mActiveLightmapSurfaces.Push(surface);
}
inline const auto& GetVisibleSurfaceList() const
{
return mActiveLightmapSurfaces;
}
inline void ClearVisibleSurfaceList()
{
mActiveLightmapSurfaces.Clear();
}
// API-dependent render interface
// Worker threads

View file

@ -156,6 +156,7 @@ public:
virtual bool IsPoly() { return false; }
virtual bool CompileNextShader() { return true; }
virtual void SetLevelMesh(LevelMesh *mesh) { }
virtual void UpdateLightmaps(const TArray<LevelMeshSurface*>& surfaces) {}
bool allowSSBO() const
{
#ifndef HW_BLOCK_SSBO

View file

@ -31,6 +31,17 @@ VkLightmap::~VkLightmap()
lights.Buffer->Unmap();
}
static int lastSurfaceCount;
ADD_STAT(lightmapper)
{
FString out;
out.Format("Last batch surface count: %d", lastSurfaceCount);
return out;
}
void VkLightmap::Raytrace(LevelMesh* level, const TArray<LevelMeshSurface*>& surfaces)
{
bool newLevel = (mesh != level);
@ -42,8 +53,15 @@ void VkLightmap::Raytrace(LevelMesh* level, const TArray<LevelMeshSurface*>& sur
CreateAtlasImages();
}
for (auto surface : surfaces)
{
surface->needsUpdate = false;
}
UploadUniforms();
lastSurfaceCount = surfaces.Size();
for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++)
{
RenderAtlasImage(pageIndex, surfaces);
@ -53,7 +71,7 @@ void VkLightmap::Raytrace(LevelMesh* level, const TArray<LevelMeshSurface*>& sur
{
ResolveAtlasImage(pageIndex);
BlurAtlasImage(pageIndex);
CopyAtlasImageResult(pageIndex);
CopyAtlasImageResult(pageIndex, surfaces);
}
}
@ -375,14 +393,14 @@ void VkLightmap::BlurAtlasImage(size_t pageIndex)
}
}
void VkLightmap::CopyAtlasImageResult(size_t pageIndex)
void VkLightmap::CopyAtlasImageResult(size_t pageIndex, const TArray<LevelMeshSurface*>& surfaces)
{
LightmapImage& img = atlasImages[pageIndex];
std::vector<VkImageCopy> regions;
for (int i = 0, count = mesh->GetSurfaceCount(); i < count; i++)
for (int i = 0, count = surfaces.Size(); i < count; i++)
{
LevelMeshSurface* surface = mesh->GetSurface(i);
LevelMeshSurface* surface = surfaces[i];
if (surface->lightmapperAtlasPage != pageIndex)
continue;

View file

@ -96,7 +96,7 @@ private:
void RenderAtlasImage(size_t pageIndex, const TArray<LevelMeshSurface*>& surfaces);
void ResolveAtlasImage(size_t pageIndex);
void BlurAtlasImage(size_t pageIndex);
void CopyAtlasImageResult(size_t pageIndex);
void CopyAtlasImageResult(size_t pageIndex, const TArray<LevelMeshSurface*>& surfaces);
LightmapImage CreateImage(int width, int height);

View file

@ -531,17 +531,20 @@ void VulkanRenderDevice::PrintStartupLog()
Printf("Min. uniform buffer offset alignment: %" PRIu64 "\n", limits.minUniformBufferOffsetAlignment);
}
LevelMesh* lastMesh = nullptr; // Temp hack; Since this function is called every frame we only want to do this once
void VulkanRenderDevice::SetLevelMesh(LevelMesh* mesh)
{
mRaytrace->SetLevelMesh(mesh);
static LevelMesh* lastMesh = nullptr; // Temp hack; Since this function is called every frame we only want to do this once
if (lastMesh != mesh && mesh->GetSurfaceCount() > 0)
{
lastMesh = mesh;
mesh->UpdateLightLists();
GetTextureManager()->CreateLightmap(mesh->LMTextureSize, mesh->LMTextureCount);
#if 0 // full lightmap generation
TArray<LevelMeshSurface*> surfaces;
surfaces.Reserve(mesh->GetSurfaceCount());
for (unsigned i = 0, count = mesh->GetSurfaceCount(); i < count; ++i)
@ -549,8 +552,23 @@ void VulkanRenderDevice::SetLevelMesh(LevelMesh* mesh)
surfaces[i] = mesh->GetSurface(i);
}
GetTextureManager()->CreateLightmap(mesh->LMTextureSize, mesh->LMTextureCount);
GetLightmap()->Raytrace(mesh, surfaces);
#else
GetLightmap()->Raytrace(mesh, {});
#endif
}
}
void VulkanRenderDevice::UpdateLightmaps(const TArray<LevelMeshSurface*>& surfaces)
{
if (surfaces.Size() > 0)
{
auto levelMesh = lastMesh; // There's nothing more permanent than a temporary solution
if (levelMesh)
{
GetLightmap()->Raytrace(levelMesh, surfaces);
}
}
}

View file

@ -63,6 +63,7 @@ public:
void AmbientOccludeScene(float m5) override;
void SetSceneRenderTarget(bool useSSAO) override;
void SetLevelMesh(LevelMesh* mesh) override;
void UpdateLightmaps(const TArray<LevelMeshSurface*>& surfaces) override;
void SetShadowMaps(const TArray<float>& lights, hwrenderer::LevelAABBTree* tree, bool newTree) override;
void SetSaveBuffers(bool yes) override;
void ImageTransitionScene(bool unknown) override;

View file

@ -23,6 +23,18 @@ CCMD(dumplevelmesh)
}
}
CCMD(invalidatelightmap)
{
int count = 0;
for (auto& surface : level.levelMesh->Surfaces)
{
if (!surface.needsUpdate)
++count;
surface.needsUpdate = true;
}
Printf("Marked %d out of %d surfaces for update.\n", count, level.levelMesh->Surfaces.Size());
}
DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap)
{
SunColor = doomMap.SunColor; // TODO keep only one copy?

View file

@ -124,6 +124,7 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou
screen->mShadowMap->SetCollectLights(nullptr);
}
RenderState.ClearVisibleSurfaceList();
screen->SetLevelMesh(camera->Level->levelMesh);
static HWDrawContext mainthread_drawctx;
@ -197,6 +198,8 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou
screen->NextEye(eyeCount);
}
screen->UpdateLightmaps(RenderState.GetVisibleSurfaceList());
return mainvp.sector;
}

View file

@ -192,6 +192,10 @@ void HWFlat::DrawSubsectors(HWDrawInfo *di, FRenderState &state)
}
state.SetLightIndex(dynlightindex);
for (auto& subsector : section->subsectors)
{
state.PushVisibleSurface(subsector->lightmap[ceiling ? 1 : 0][0]);
}
state.DrawIndexed(DT_Triangles, iboindex + section->vertexindex, section->vertexcount);
flatvertices += section->vertexcount;