Only force baking of tiles where the geometry changed
This commit is contained in:
parent
27f0bea2bc
commit
76fb5901d7
8 changed files with 106 additions and 45 deletions
|
|
@ -72,7 +72,7 @@ void LightmapBuildCmdlet::OnCommand(FArgs args)
|
|||
tiles.Clear();
|
||||
for (auto& e : level.levelMesh->Lightmap.Tiles)
|
||||
{
|
||||
if (e.NeedsUpdate)
|
||||
if (e.NeedsInitialBake)
|
||||
{
|
||||
tiles.Push(&e);
|
||||
if (tiles.Size() == 1001)
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ LevelMeshTileStats LevelMesh::GatherTilePixelStats()
|
|||
|
||||
stats.pixels.total += area;
|
||||
|
||||
if (tile.NeedsUpdate)
|
||||
if (tile.NeedsInitialBake)
|
||||
{
|
||||
stats.tiles.dirty++;
|
||||
stats.pixels.dirty += area;
|
||||
|
|
@ -160,7 +160,7 @@ void LevelMesh::PackLightmapAtlas()
|
|||
|
||||
tile.AddedThisFrame = false;
|
||||
|
||||
if (tile.NeedsUpdate) // false for tiles loaded from lump
|
||||
if (tile.NeedsInitialBake || tile.GeometryUpdate) // NeedsInitialBake is false for tiles loaded from lump
|
||||
tile.SetupTileTransform(Lightmap.TextureSize);
|
||||
|
||||
sortedTiles.push_back(&tile);
|
||||
|
|
|
|||
|
|
@ -57,8 +57,14 @@ struct LightmapTile
|
|||
uint16_t SampleDimension = 0;
|
||||
FVector4 Plane = FVector4(0.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
// True if the tile needs to be rendered into the lightmap texture before it can be used
|
||||
bool NeedsUpdate = true;
|
||||
// Initial tile for surfaces that can be baked in the background
|
||||
bool NeedsInitialBake = false;
|
||||
|
||||
// This tile MUST be baked before it can be rendered
|
||||
bool GeometryUpdate = true;
|
||||
|
||||
// The light for this tile changed since last bake
|
||||
bool ReceivedNewLight = true;
|
||||
|
||||
// Used to track if tile has already been added to the VisibleTiles list for this scene
|
||||
int LastSeen = 0;
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ void VkLightmapper::SelectTiles(const TArray<LightmapTile*>& tiles)
|
|||
{
|
||||
LightmapTile* tile = tiles[i];
|
||||
|
||||
if (!tile->NeedsUpdate)
|
||||
if (!tile->ReceivedNewLight)
|
||||
continue;
|
||||
|
||||
// Only grab surfaces until our bake texture is full
|
||||
|
|
@ -158,7 +158,9 @@ void VkLightmapper::SelectTiles(const TArray<LightmapTile*>& tiles)
|
|||
bakeImage.maxX = std::max<uint16_t>(bakeImage.maxX, uint16_t(result->X + tile->AtlasLocation.Width));
|
||||
bakeImage.maxY = std::max<uint16_t>(bakeImage.maxY, uint16_t(result->Y + tile->AtlasLocation.Height));
|
||||
|
||||
tile->NeedsUpdate = false;
|
||||
tile->ReceivedNewLight = false;
|
||||
tile->NeedsInitialBake = false;
|
||||
tile->GeometryUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +250,7 @@ void VkLightmapper::Render()
|
|||
{
|
||||
while (i < count)
|
||||
{
|
||||
selectedTiles[i].Tile->NeedsUpdate = true;
|
||||
selectedTiles[i].Tile->ReceivedNewLight = true;
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3173,7 +3173,9 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
tile->Transform.TranslateWorldToLocal = entry.translateWorldToLocal;
|
||||
tile->Transform.ProjLocalToU = entry.projLocalToU;
|
||||
tile->Transform.ProjLocalToV = entry.projLocalToV;
|
||||
tile->NeedsUpdate = false;
|
||||
tile->NeedsInitialBake = false;
|
||||
tile->GeometryUpdate = false;
|
||||
tile->ReceivedNewLight = false;
|
||||
|
||||
foundBindings.Push({ &entry, tile });
|
||||
}
|
||||
|
|
@ -3210,7 +3212,9 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
memcpy(dstline, srcline, width * 3 * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
tile->NeedsUpdate = false;
|
||||
tile->NeedsInitialBake = false;
|
||||
tile->GeometryUpdate = false;
|
||||
tile->ReceivedNewLight = false;
|
||||
}
|
||||
|
||||
if (errors > 0)
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ static int InvalidateLightmap()
|
|||
|
||||
for (auto& tile : level.levelMesh->Lightmap.Tiles)
|
||||
{
|
||||
if (!tile.NeedsUpdate)
|
||||
if (!tile.NeedsInitialBake)
|
||||
++count;
|
||||
tile.NeedsUpdate = true;
|
||||
tile.NeedsInitialBake = true;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
|
@ -126,12 +126,7 @@ CCMD(invalidatelightmap)
|
|||
if (!RequireLightmap()) return;
|
||||
|
||||
int count = InvalidateLightmap();
|
||||
for (auto& tile : level.levelMesh->Lightmap.Tiles)
|
||||
{
|
||||
if (!tile.NeedsUpdate)
|
||||
++count;
|
||||
tile.NeedsUpdate = true;
|
||||
}
|
||||
|
||||
Printf("Marked %d out of %d tiles for update.\n", count, level.levelMesh->Lightmap.Tiles.Size());
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +155,9 @@ void DoomLevelMesh::PrintSurfaceInfo(const LevelMeshSurface* surface)
|
|||
Printf(" Atlas page: %d, x:%d, y:%d\n", tile->AtlasLocation.ArrayIndex, tile->AtlasLocation.X, tile->AtlasLocation.Y);
|
||||
Printf(" Pixels: %dx%d (area: %d)\n", tile->AtlasLocation.Width, tile->AtlasLocation.Height, tile->AtlasLocation.Area());
|
||||
Printf(" Sample dimension: %d\n", tile->SampleDimension);
|
||||
Printf(" Needs update?: %d\n", tile->NeedsUpdate);
|
||||
Printf(" Background update?: %d\n", (int)tile->NeedsInitialBake);
|
||||
Printf(" Geometry update?: %d\n", (int)tile->GeometryUpdate);
|
||||
Printf(" Light update?: %d\n", (int)tile->ReceivedNewLight);
|
||||
}
|
||||
Printf(" Sector group: %d\n", surface->SectorGroup);
|
||||
Printf(" Texture: '%s'\n", gameTexture ? gameTexture->GetName().GetChars() : "<nullptr>");
|
||||
|
|
@ -238,9 +235,16 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap)
|
|||
// This is a bit of a hack. Lights aren't available until BeginFrame is called.
|
||||
// Unfortunately we need a surface list already at this point for our Mesh.MaxNodes calculation
|
||||
for (unsigned int i = 0; i < Sides.Size(); i++)
|
||||
UpdateSide(i, SurfaceUpdateType::Full);
|
||||
UpdateSide(i, SurfaceUpdateType::LightList);
|
||||
for (unsigned int i = 0; i < Flats.Size(); i++)
|
||||
UpdateFlat(i, SurfaceUpdateType::Full);
|
||||
UpdateFlat(i, SurfaceUpdateType::LightList);
|
||||
|
||||
// Initial tiles are black and should be background updated
|
||||
for (auto& tile : Lightmap.Tiles)
|
||||
{
|
||||
tile.GeometryUpdate = false;
|
||||
tile.NeedsInitialBake = true;
|
||||
}
|
||||
|
||||
CreateCollision();
|
||||
UploadPortals();
|
||||
|
|
@ -845,7 +849,7 @@ void DoomLevelMesh::UpdateSideLightList(FLevelLocals& doomMap, unsigned int side
|
|||
int tile = Mesh.Surfaces[surf].LightmapTileIndex;
|
||||
if (tile != -1)
|
||||
{
|
||||
Lightmap.Tiles[tile].NeedsUpdate = true;
|
||||
Lightmap.Tiles[tile].ReceivedNewLight = true;
|
||||
}
|
||||
surf = DoomSurfaceInfos[surf].NextSurface;
|
||||
}
|
||||
|
|
@ -853,14 +857,14 @@ void DoomLevelMesh::UpdateSideLightList(FLevelLocals& doomMap, unsigned int side
|
|||
|
||||
void DoomLevelMesh::UpdateFlatLightList(FLevelLocals& doomMap, unsigned int sectorIndex)
|
||||
{
|
||||
for (auto& lightlist : Flats[sectorIndex].Lights)
|
||||
FreeLightList(lightlist.Start, lightlist.Count);
|
||||
Flats[sectorIndex].Lights.Clear();
|
||||
|
||||
sector_t* sector = &doomMap.sectors[sectorIndex];
|
||||
int lightListSection = 0;
|
||||
for (FSection& section : doomMap.sections.SectionsForSector(sectorIndex))
|
||||
{
|
||||
auto& lightlist = Flats[sectorIndex].Lights[lightListSection];
|
||||
FreeLightList(lightlist.Start, lightlist.Count);
|
||||
lightlist = CreateLightList(section.lighthead, section.sector->PortalGroup);
|
||||
lightListSection++;
|
||||
Flats[sectorIndex].Lights.Push(CreateLightList(section.lighthead, section.sector->PortalGroup));
|
||||
}
|
||||
|
||||
int surf = Flats[sectorIndex].FirstSurface;
|
||||
|
|
@ -874,7 +878,7 @@ void DoomLevelMesh::UpdateFlatLightList(FLevelLocals& doomMap, unsigned int sect
|
|||
int tile = Mesh.Surfaces[surf].LightmapTileIndex;
|
||||
if (tile != -1)
|
||||
{
|
||||
Lightmap.Tiles[tile].NeedsUpdate = true;
|
||||
Lightmap.Tiles[tile].ReceivedNewLight = true;
|
||||
}
|
||||
surf = DoomSurfaceInfos[surf].NextSurface;
|
||||
}
|
||||
|
|
@ -888,7 +892,7 @@ void DoomLevelMesh::UpdateSideShadows(FLevelLocals& doomMap, unsigned int sideIn
|
|||
int tile = Mesh.Surfaces[surf].LightmapTileIndex;
|
||||
if (tile != -1)
|
||||
{
|
||||
Lightmap.Tiles[tile].NeedsUpdate = true;
|
||||
Lightmap.Tiles[tile].ReceivedNewLight = true;
|
||||
}
|
||||
surf = DoomSurfaceInfos[surf].NextSurface;
|
||||
}
|
||||
|
|
@ -902,7 +906,7 @@ void DoomLevelMesh::UpdateFlatShadows(FLevelLocals& doomMap, unsigned int sector
|
|||
int tile = Mesh.Surfaces[surf].LightmapTileIndex;
|
||||
if (tile != -1)
|
||||
{
|
||||
Lightmap.Tiles[tile].NeedsUpdate = true;
|
||||
Lightmap.Tiles[tile].ReceivedNewLight = true;
|
||||
}
|
||||
surf = DoomSurfaceInfos[surf].NextSurface;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -720,26 +720,59 @@ void HWDrawInfo::UpdateLightmaps()
|
|||
{
|
||||
if (outer)
|
||||
outer->UpdateLightmaps();
|
||||
/*
|
||||
if (VisibleTiles.size() > (size_t)lm_max_updates)
|
||||
VisibleTiles.resize(lm_max_updates);
|
||||
*/
|
||||
|
||||
if (VisibleTiles.size() < (size_t)lm_background_updates)
|
||||
VisibleTiles.Result.Clear();
|
||||
|
||||
size_t max_updates = (size_t)lm_max_updates;
|
||||
|
||||
// We always must bake tiles that received new geometry
|
||||
for (auto tile : VisibleTiles.Geometry)
|
||||
VisibleTiles.Result.Push(tile);
|
||||
|
||||
if (VisibleTiles.Result.size() < max_updates)
|
||||
{
|
||||
for (auto& e : level.levelMesh->Lightmap.Tiles)
|
||||
// We got room for more. Include some visible tiles that are being background updated
|
||||
for (auto tile : VisibleTiles.Background)
|
||||
VisibleTiles.Result.Push(tile);
|
||||
|
||||
if (VisibleTiles.Result.size() < max_updates)
|
||||
{
|
||||
if (e.NeedsUpdate && e.LastSeen != TileSeenCounter)
|
||||
// We still have room. Add tiles that received new light
|
||||
for (auto tile : VisibleTiles.ReceivedNewLight)
|
||||
VisibleTiles.Result.Push(tile);
|
||||
|
||||
if (VisibleTiles.Result.size() < max_updates)
|
||||
{
|
||||
VisibleTiles.Push(&e);
|
||||
if (VisibleTiles.size() >= (size_t)lm_background_updates)
|
||||
break;
|
||||
max_updates = VisibleTiles.Result.size() + (size_t)lm_background_updates;
|
||||
|
||||
// Look for more background updates
|
||||
for (auto& e : level.levelMesh->Lightmap.Tiles)
|
||||
{
|
||||
if (e.NeedsInitialBake && e.LastSeen != TileSeenCounter)
|
||||
{
|
||||
VisibleTiles.Result.Push(&e);
|
||||
if (VisibleTiles.Result.size() >= max_updates)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VisibleTiles.Result.resize(max_updates);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VisibleTiles.Result.resize(max_updates);
|
||||
}
|
||||
}
|
||||
|
||||
screen->UpdateLightmaps(VisibleTiles);
|
||||
VisibleTiles.Clear();
|
||||
screen->UpdateLightmaps(VisibleTiles.Result);
|
||||
|
||||
VisibleTiles.Geometry.Clear();
|
||||
VisibleTiles.Background.Clear();
|
||||
VisibleTiles.ReceivedNewLight.Clear();
|
||||
VisibleTiles.Result.Clear();
|
||||
}
|
||||
|
||||
void HWDrawInfo::RenderScene(FRenderState &state)
|
||||
|
|
|
|||
|
|
@ -157,7 +157,13 @@ struct HWDrawInfo
|
|||
TArray<HWDecal *> Decals[2]; // the second slot is for mirrors which get rendered in a separate pass.
|
||||
TArray<HUDSprite> hudsprites; // These may just be stored by value.
|
||||
TArray<Fogball> Fogballs;
|
||||
TArray<LightmapTile*> VisibleTiles;
|
||||
struct
|
||||
{
|
||||
TArray<LightmapTile*> Geometry;
|
||||
TArray<LightmapTile*> ReceivedNewLight;
|
||||
TArray<LightmapTile*> Background;
|
||||
TArray<LightmapTile*> Result;
|
||||
} VisibleTiles;
|
||||
int TileSeenCounter = 0;
|
||||
uint64_t LastFrameTime = 0;
|
||||
|
||||
|
|
@ -241,10 +247,16 @@ public:
|
|||
}
|
||||
|
||||
LightmapTile* tile = &Level->levelMesh->Lightmap.Tiles[tileIndex];
|
||||
if (tile->NeedsUpdate && tile->LastSeen != TileSeenCounter)
|
||||
if (tile->LastSeen != TileSeenCounter)
|
||||
{
|
||||
tile->LastSeen = TileSeenCounter;
|
||||
VisibleTiles.Push(tile);
|
||||
|
||||
if (tile->GeometryUpdate)
|
||||
VisibleTiles.Geometry.Push(tile);
|
||||
else if (tile->NeedsInitialBake)
|
||||
VisibleTiles.Background.Push(tile);
|
||||
else if (tile->ReceivedNewLight)
|
||||
VisibleTiles.ReceivedNewLight.Push(tile);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue