Fixes for building editor for Linux
This commit is contained in:
@@ -8,13 +8,313 @@
|
||||
#include "Engine/Graphics/RenderTargetPool.h"
|
||||
|
||||
#define STEPS_SLEEP_TIME 20
|
||||
#define RUN_STEP(handler) handler(); if (checkBuildCancelled()) goto BUILDING_END; Platform::Sleep(STEPS_SLEEP_TIME)
|
||||
#define RUN_STEP(handler) handler(); if (checkBuildCancelled()) return true; Platform::Sleep(STEPS_SLEEP_TIME)
|
||||
|
||||
bool ShadowsOfMordor::Builder::doWorkInner(DateTime buildStart)
|
||||
{
|
||||
#if HEMISPHERES_BAKE_STATE_SAVE
|
||||
_lastStateSaveTime = DateTime::Now();
|
||||
_firstStateSave = true;
|
||||
|
||||
// Try to load the state that was cached during hemispheres rendering (restore rendering in case of GPU driver crash)
|
||||
if (loadState())
|
||||
{
|
||||
reportProgress(BuildProgressStep::RenderHemispheres, 0.0f);
|
||||
const int32 firstScene = _workerActiveSceneIndex;
|
||||
{
|
||||
// Wait for lightmaps to be fully loaded
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
if (_scenes[_workerActiveSceneIndex]->WaitForLightmaps())
|
||||
{
|
||||
LOG(Error, "Failed to load lightmap textures.");
|
||||
_wasBuildCalled = false;
|
||||
_isActive = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (checkBuildCancelled())
|
||||
return true;
|
||||
}
|
||||
|
||||
// Continue the hemispheres rendering for the last scene from the cached position
|
||||
{
|
||||
_workerActiveSceneIndex = firstScene;
|
||||
if (runStage(RenderHemispheres, false))
|
||||
return true;
|
||||
|
||||
// Fill black holes with blurred data to prevent artifacts on the edges
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(PostprocessLightmaps))
|
||||
return true;
|
||||
|
||||
// Wait for GPU commands to sync
|
||||
if (waitForJobDataSync())
|
||||
return true;
|
||||
|
||||
// Update lightmaps textures
|
||||
_scenes[_workerActiveSceneIndex]->UpdateLightmaps();
|
||||
}
|
||||
for (_workerActiveSceneIndex = firstScene + 1; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
// Skip scenes without any lightmaps
|
||||
if (_scenes[_workerActiveSceneIndex]->Lightmaps.IsEmpty())
|
||||
continue;
|
||||
|
||||
// Clear hemispheres target
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(ClearLightmapData))
|
||||
return true;
|
||||
|
||||
// Render all registered Hemispheres rendering
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(RenderHemispheres))
|
||||
return true;
|
||||
|
||||
// Fill black holes with blurred data to prevent artifacts on the edges
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(PostprocessLightmaps))
|
||||
return true;
|
||||
|
||||
// Wait for GPU commands to sync
|
||||
if (waitForJobDataSync())
|
||||
return true;
|
||||
|
||||
// Update lightmaps textures
|
||||
_scenes[_workerActiveSceneIndex]->UpdateLightmaps();
|
||||
}
|
||||
}
|
||||
for (int32 bounce = _giBounceRunningIndex + 1; bounce < _bounceCount; bounce++)
|
||||
{
|
||||
_giBounceRunningIndex = bounce;
|
||||
|
||||
// Wait for lightmaps to be fully loaded
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
if (_scenes[_workerActiveSceneIndex]->WaitForLightmaps())
|
||||
{
|
||||
LOG(Error, "Failed to load lightmap textures.");
|
||||
_wasBuildCalled = false;
|
||||
_isActive = false;
|
||||
return true;
|
||||
}
|
||||
if (checkBuildCancelled())
|
||||
return true;
|
||||
}
|
||||
|
||||
// Render bounce for every scene separately
|
||||
for (_workerActiveSceneIndex = firstScene; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
// Skip scenes without any lightmaps
|
||||
if (_scenes[_workerActiveSceneIndex]->Lightmaps.IsEmpty())
|
||||
continue;
|
||||
|
||||
// Clear hemispheres target
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(ClearLightmapData))
|
||||
return true;
|
||||
|
||||
// Render all registered Hemispheres rendering
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(RenderHemispheres))
|
||||
return true;
|
||||
|
||||
// Fill black holes with blurred data to prevent artifacts on the edges
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(PostprocessLightmaps))
|
||||
return true;
|
||||
|
||||
// Wait for GPU commands to sync
|
||||
if (waitForJobDataSync())
|
||||
return true;
|
||||
|
||||
// Update lightmaps textures
|
||||
_scenes[_workerActiveSceneIndex]->UpdateLightmaps();
|
||||
}
|
||||
}
|
||||
reportProgress(BuildProgressStep::RenderHemispheres, 1.0f);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compute the final weight for integration
|
||||
{
|
||||
float weightSum = 0.0f;
|
||||
for (uint32 y = 0; y < HEMISPHERES_RESOLUTION; y++)
|
||||
{
|
||||
const float v = (float(y) / float(HEMISPHERES_RESOLUTION)) * 2.0f - 1.0f;
|
||||
for (uint32 x = 0; x < HEMISPHERES_RESOLUTION; x++)
|
||||
{
|
||||
const float u = (float(x) / float(HEMISPHERES_RESOLUTION)) * 2.0f - 1.0f;
|
||||
const float t = 1.0f + u * u + v * v;
|
||||
const float weight = 4.0f / (Math::Sqrt(t) * t);
|
||||
weightSum += weight;
|
||||
}
|
||||
}
|
||||
weightSum *= 6;
|
||||
_hemisphereTexelsTotalWeight = (4.0f * PI) / weightSum;
|
||||
}
|
||||
|
||||
// Initialize the lightmaps and pack entries to the charts
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
RUN_STEP(cacheEntries);
|
||||
RUN_STEP(generateCharts);
|
||||
RUN_STEP(packCharts);
|
||||
RUN_STEP(updateLightmaps);
|
||||
RUN_STEP(updateEntries);
|
||||
}
|
||||
|
||||
// TODO: if settings require wait for asset dependencies to all materials and models be loaded (maybe only for higher quality profiles)
|
||||
|
||||
// Generate hemispheres cache and prepare for baking
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
// Wait for lightmaps to be fully loaded
|
||||
if (_scenes[_workerActiveSceneIndex]->WaitForLightmaps())
|
||||
{
|
||||
LOG(Error, "Failed to load lightmap textures.");
|
||||
_wasBuildCalled = false;
|
||||
_isActive = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ASSERT(_cachePositions == nullptr && _cacheNormals == nullptr);
|
||||
const int32 atlasSize = (int32)_scenes[_workerActiveSceneIndex]->GetSettings().AtlasSize;
|
||||
auto tempDesc = GPUTextureDescription::New2D(atlasSize, atlasSize, HemispheresFormatToPixelFormat[CACHE_POSITIONS_FORMAT]);
|
||||
_cachePositions = RenderTargetPool::Get(tempDesc);
|
||||
tempDesc.Format = HemispheresFormatToPixelFormat[CACHE_NORMALS_FORMAT];
|
||||
_cacheNormals = RenderTargetPool::Get(tempDesc);
|
||||
if (_cachePositions == nullptr || _cacheNormals == nullptr)
|
||||
return true;
|
||||
|
||||
generateHemispheres();
|
||||
|
||||
RenderTargetPool::Release(_cachePositions);
|
||||
_cachePositions = nullptr;
|
||||
RenderTargetPool::Release(_cacheNormals);
|
||||
_cacheNormals = nullptr;
|
||||
|
||||
if (checkBuildCancelled())
|
||||
return true;
|
||||
Platform::Sleep(STEPS_SLEEP_TIME);
|
||||
}
|
||||
|
||||
// Prepare before actual baking
|
||||
int32 hemispheresCount = 0;
|
||||
int32 mergedHemispheresCount = 0;
|
||||
int32 bounceCount = 0;
|
||||
int32 lightmapsCount = 0;
|
||||
int32 entriesCount = 0;
|
||||
for (int32 sceneIndex = 0; sceneIndex < _scenes.Count(); sceneIndex++)
|
||||
{
|
||||
auto& scene = *_scenes[sceneIndex];
|
||||
hemispheresCount += scene.HemispheresCount;
|
||||
mergedHemispheresCount += scene.MergedHemispheresCount;
|
||||
lightmapsCount += scene.Lightmaps.Count();
|
||||
entriesCount += scene.Entries.Count();
|
||||
bounceCount = Math::Max(bounceCount, scene.GetSettings().BounceCount);
|
||||
|
||||
// Cleanup unused data to reduce memory usage
|
||||
scene.Entries.Resize(0);
|
||||
scene.Charts.Resize(0);
|
||||
for (auto& lightmap : scene.Lightmaps)
|
||||
lightmap.Entries.Resize(0);
|
||||
}
|
||||
_bounceCount = bounceCount;
|
||||
LOG(Info, "Rendering {0} hemispheres in {1} bounce(s) (merged: {2})", hemispheresCount, bounceCount, mergedHemispheresCount);
|
||||
if (bounceCount <= 0 || hemispheresCount <= 0)
|
||||
{
|
||||
LOG(Warning, "No data to render");
|
||||
return true;
|
||||
}
|
||||
|
||||
// For each bounce
|
||||
for (int32 bounce = 0; bounce < _bounceCount; bounce++)
|
||||
{
|
||||
_giBounceRunningIndex = bounce;
|
||||
|
||||
// Wait for lightmaps to be fully loaded
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
if (_scenes[_workerActiveSceneIndex]->WaitForLightmaps())
|
||||
{
|
||||
LOG(Error, "Failed to load lightmap textures.");
|
||||
_wasBuildCalled = false;
|
||||
_isActive = false;
|
||||
return true;
|
||||
}
|
||||
if (checkBuildCancelled())
|
||||
return true;
|
||||
}
|
||||
|
||||
// Render bounce for every scene separately
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
// Skip scenes without any lightmaps
|
||||
if (_scenes[_workerActiveSceneIndex]->Lightmaps.IsEmpty())
|
||||
continue;
|
||||
|
||||
// Clear hemispheres target
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(ClearLightmapData))
|
||||
return true;
|
||||
|
||||
// Render all registered Hemispheres rendering
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(RenderHemispheres))
|
||||
return true;
|
||||
|
||||
// Fill black holes with blurred data to prevent artifacts on the edges
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(PostprocessLightmaps))
|
||||
return true;
|
||||
|
||||
// Wait for GPU commands to sync
|
||||
if (waitForJobDataSync())
|
||||
return true;
|
||||
|
||||
// Update lightmaps textures
|
||||
_scenes[_workerActiveSceneIndex]->UpdateLightmaps();
|
||||
}
|
||||
}
|
||||
|
||||
reportProgress(BuildProgressStep::RenderHemispheres, 1.0f);
|
||||
|
||||
#if DEBUG_EXPORT_HEMISPHERES_PREVIEW
|
||||
for (int32 sceneIndex = 0; sceneIndex < _scenes.Count(); sceneIndex++)
|
||||
downloadDebugHemisphereAtlases(_scenes[sceneIndex]);
|
||||
#endif
|
||||
|
||||
// References:
|
||||
// "Optimization of numerical calculations execution time in multiprocessor systems" - Wojciech Figat
|
||||
// https://knarkowicz.wordpress.com/2014/07/20/lightmapping-in-anomaly-2-mobile/
|
||||
// http://the-witness.net/news/2010/09/hemicube-rendering-and-integration/
|
||||
// http://the-witness.net/news/2010/03/graphics-tech-texture-parameterization/
|
||||
// http://the-witness.net/news/2010/03/graphics-tech-lighting-comparison/
|
||||
|
||||
// Some ideas:
|
||||
// - render hemispheres to atlas or sth and batch integration and downscalling for multiply texels
|
||||
// - use conservative rasterization for dx12 instead of blur or MSAA for all platforms
|
||||
// - use hemisphere depth buffer to compute AO
|
||||
|
||||
// End
|
||||
const int32 hemispheresRenderedCount = hemispheresCount * bounceCount;
|
||||
DateTime buildEnd = DateTime::NowUTC();
|
||||
LOG(Info, "Building lightmap finished! Time: {0}s, Lightmaps: {1}, Entries: {2}, Hemicubes rendered: {3}",
|
||||
static_cast<int32>((buildEnd - buildStart).GetTotalSeconds()),
|
||||
lightmapsCount,
|
||||
entriesCount,
|
||||
hemispheresRenderedCount);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 ShadowsOfMordor::Builder::doWork()
|
||||
{
|
||||
// Start
|
||||
bool buildFailed = true;
|
||||
DateTime buildEnd, buildStart = DateTime::NowUTC();
|
||||
DateTime buildStart = DateTime::NowUTC();
|
||||
_lastStep = BuildProgressStep::CacheEntries;
|
||||
_lastStepStart = buildStart;
|
||||
_hemispheresPerJob = HEMISPHERES_PER_JOB_MIN;
|
||||
@@ -84,309 +384,14 @@ int32 ShadowsOfMordor::Builder::doWork()
|
||||
}
|
||||
}
|
||||
|
||||
// Run
|
||||
IsBakingLightmaps = true;
|
||||
|
||||
#if HEMISPHERES_BAKE_STATE_SAVE
|
||||
_lastStateSaveTime = DateTime::Now();
|
||||
_firstStateSave = true;
|
||||
|
||||
// Try to load the state that was cached during hemispheres rendering (restore rendering in case of GPU driver crash)
|
||||
if (loadState())
|
||||
buildFailed = doWorkInner(buildStart);
|
||||
if (buildFailed && !checkBuildCancelled())
|
||||
{
|
||||
reportProgress(BuildProgressStep::RenderHemispheres, 0.0f);
|
||||
const int32 firstScene = _workerActiveSceneIndex;
|
||||
{
|
||||
// Wait for lightmaps to be fully loaded
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
if (_scenes[_workerActiveSceneIndex]->WaitForLightmaps())
|
||||
{
|
||||
LOG(Error, "Failed to load lightmap textures.");
|
||||
_wasBuildCalled = false;
|
||||
_isActive = false;
|
||||
OnBuildFinished(buildFailed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (checkBuildCancelled())
|
||||
goto BUILDING_END;
|
||||
}
|
||||
|
||||
// Continue the hemispheres rendering for the last scene from the cached position
|
||||
{
|
||||
_workerActiveSceneIndex = firstScene;
|
||||
if (runStage(RenderHemispheres, false))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Fill black holes with blurred data to prevent artifacts on the edges
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(PostprocessLightmaps))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Wait for GPU commands to sync
|
||||
if (waitForJobDataSync())
|
||||
goto BUILDING_END;
|
||||
|
||||
// Update lightmaps textures
|
||||
_scenes[_workerActiveSceneIndex]->UpdateLightmaps();
|
||||
}
|
||||
for (_workerActiveSceneIndex = firstScene + 1; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
// Skip scenes without any lightmaps
|
||||
if (_scenes[_workerActiveSceneIndex]->Lightmaps.IsEmpty())
|
||||
continue;
|
||||
|
||||
// Clear hemispheres target
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(ClearLightmapData))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Render all registered Hemispheres rendering
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(RenderHemispheres))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Fill black holes with blurred data to prevent artifacts on the edges
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(PostprocessLightmaps))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Wait for GPU commands to sync
|
||||
if (waitForJobDataSync())
|
||||
goto BUILDING_END;
|
||||
|
||||
// Update lightmaps textures
|
||||
_scenes[_workerActiveSceneIndex]->UpdateLightmaps();
|
||||
}
|
||||
}
|
||||
for (int32 bounce = _giBounceRunningIndex + 1; bounce < _bounceCount; bounce++)
|
||||
{
|
||||
_giBounceRunningIndex = bounce;
|
||||
|
||||
// Wait for lightmaps to be fully loaded
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
if (_scenes[_workerActiveSceneIndex]->WaitForLightmaps())
|
||||
{
|
||||
LOG(Error, "Failed to load lightmap textures.");
|
||||
_wasBuildCalled = false;
|
||||
_isActive = false;
|
||||
OnBuildFinished(buildFailed);
|
||||
return 0;
|
||||
}
|
||||
if (checkBuildCancelled())
|
||||
goto BUILDING_END;
|
||||
}
|
||||
|
||||
// Render bounce for every scene separately
|
||||
for (_workerActiveSceneIndex = firstScene; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
// Skip scenes without any lightmaps
|
||||
if (_scenes[_workerActiveSceneIndex]->Lightmaps.IsEmpty())
|
||||
continue;
|
||||
|
||||
// Clear hemispheres target
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(ClearLightmapData))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Render all registered Hemispheres rendering
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(RenderHemispheres))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Fill black holes with blurred data to prevent artifacts on the edges
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(PostprocessLightmaps))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Wait for GPU commands to sync
|
||||
if (waitForJobDataSync())
|
||||
goto BUILDING_END;
|
||||
|
||||
// Update lightmaps textures
|
||||
_scenes[_workerActiveSceneIndex]->UpdateLightmaps();
|
||||
}
|
||||
}
|
||||
reportProgress(BuildProgressStep::RenderHemispheres, 1.0f);
|
||||
goto BUILDING_END;
|
||||
OnBuildFinished(buildFailed);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compute the final weight for integration
|
||||
{
|
||||
float weightSum = 0.0f;
|
||||
for (uint32 y = 0; y < HEMISPHERES_RESOLUTION; y++)
|
||||
{
|
||||
const float v = (float(y) / float(HEMISPHERES_RESOLUTION)) * 2.0f - 1.0f;
|
||||
for (uint32 x = 0; x < HEMISPHERES_RESOLUTION; x++)
|
||||
{
|
||||
const float u = (float(x) / float(HEMISPHERES_RESOLUTION)) * 2.0f - 1.0f;
|
||||
const float t = 1.0f + u * u + v * v;
|
||||
const float weight = 4.0f / (Math::Sqrt(t) * t);
|
||||
weightSum += weight;
|
||||
}
|
||||
}
|
||||
weightSum *= 6;
|
||||
_hemisphereTexelsTotalWeight = (4.0f * PI) / weightSum;
|
||||
}
|
||||
|
||||
// Initialize the lightmaps and pack entries to the charts
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
RUN_STEP(cacheEntries);
|
||||
RUN_STEP(generateCharts);
|
||||
RUN_STEP(packCharts);
|
||||
RUN_STEP(updateLightmaps);
|
||||
RUN_STEP(updateEntries);
|
||||
}
|
||||
|
||||
// TODO: if settings require wait for asset dependencies to all materials and models be loaded (maybe only for higher quality profiles)
|
||||
|
||||
// Generate hemispheres cache and prepare for baking
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
// Wait for lightmaps to be fully loaded
|
||||
if (_scenes[_workerActiveSceneIndex]->WaitForLightmaps())
|
||||
{
|
||||
LOG(Error, "Failed to load lightmap textures.");
|
||||
_wasBuildCalled = false;
|
||||
_isActive = false;
|
||||
OnBuildFinished(buildFailed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ASSERT(_cachePositions == nullptr && _cacheNormals == nullptr);
|
||||
const int32 atlasSize = (int32)_scenes[_workerActiveSceneIndex]->GetSettings().AtlasSize;
|
||||
auto tempDesc = GPUTextureDescription::New2D(atlasSize, atlasSize, HemispheresFormatToPixelFormat[CACHE_POSITIONS_FORMAT]);
|
||||
_cachePositions = RenderTargetPool::Get(tempDesc);
|
||||
tempDesc.Format = HemispheresFormatToPixelFormat[CACHE_NORMALS_FORMAT];
|
||||
_cacheNormals = RenderTargetPool::Get(tempDesc);
|
||||
if (_cachePositions == nullptr || _cacheNormals == nullptr)
|
||||
goto BUILDING_END;
|
||||
|
||||
generateHemispheres();
|
||||
|
||||
RenderTargetPool::Release(_cachePositions);
|
||||
_cachePositions = nullptr;
|
||||
RenderTargetPool::Release(_cacheNormals);
|
||||
_cacheNormals = nullptr;
|
||||
|
||||
if (checkBuildCancelled())
|
||||
goto BUILDING_END;
|
||||
Platform::Sleep(STEPS_SLEEP_TIME);
|
||||
}
|
||||
|
||||
// Prepare before actual baking
|
||||
int32 hemispheresCount = 0;
|
||||
int32 mergedHemispheresCount = 0;
|
||||
int32 bounceCount = 0;
|
||||
int32 lightmapsCount = 0;
|
||||
int32 entriesCount = 0;
|
||||
for (int32 sceneIndex = 0; sceneIndex < _scenes.Count(); sceneIndex++)
|
||||
{
|
||||
auto& scene = *_scenes[sceneIndex];
|
||||
hemispheresCount += scene.HemispheresCount;
|
||||
mergedHemispheresCount += scene.MergedHemispheresCount;
|
||||
lightmapsCount += scene.Lightmaps.Count();
|
||||
entriesCount += scene.Entries.Count();
|
||||
bounceCount = Math::Max(bounceCount, scene.GetSettings().BounceCount);
|
||||
|
||||
// Cleanup unused data to reduce memory usage
|
||||
scene.Entries.Resize(0);
|
||||
scene.Charts.Resize(0);
|
||||
for (auto& lightmap : scene.Lightmaps)
|
||||
lightmap.Entries.Resize(0);
|
||||
}
|
||||
_bounceCount = bounceCount;
|
||||
LOG(Info, "Rendering {0} hemispheres in {1} bounce(s) (merged: {2})", hemispheresCount, bounceCount, mergedHemispheresCount);
|
||||
if (bounceCount <= 0 || hemispheresCount <= 0)
|
||||
{
|
||||
LOG(Warning, "No data to render");
|
||||
goto BUILDING_END;
|
||||
}
|
||||
|
||||
// For each bounce
|
||||
for (int32 bounce = 0; bounce < _bounceCount; bounce++)
|
||||
{
|
||||
_giBounceRunningIndex = bounce;
|
||||
|
||||
// Wait for lightmaps to be fully loaded
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
if (_scenes[_workerActiveSceneIndex]->WaitForLightmaps())
|
||||
{
|
||||
LOG(Error, "Failed to load lightmap textures.");
|
||||
_wasBuildCalled = false;
|
||||
_isActive = false;
|
||||
OnBuildFinished(buildFailed);
|
||||
return 0;
|
||||
}
|
||||
if (checkBuildCancelled())
|
||||
goto BUILDING_END;
|
||||
}
|
||||
|
||||
// Render bounce for every scene separately
|
||||
for (_workerActiveSceneIndex = 0; _workerActiveSceneIndex < _scenes.Count(); _workerActiveSceneIndex++)
|
||||
{
|
||||
// Skip scenes without any lightmaps
|
||||
if (_scenes[_workerActiveSceneIndex]->Lightmaps.IsEmpty())
|
||||
continue;
|
||||
|
||||
// Clear hemispheres target
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(ClearLightmapData))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Render all registered Hemispheres rendering
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(RenderHemispheres))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Fill black holes with blurred data to prevent artifacts on the edges
|
||||
_workerStagePosition0 = 0;
|
||||
if (runStage(PostprocessLightmaps))
|
||||
goto BUILDING_END;
|
||||
|
||||
// Wait for GPU commands to sync
|
||||
if (waitForJobDataSync())
|
||||
goto BUILDING_END;
|
||||
|
||||
// Update lightmaps textures
|
||||
_scenes[_workerActiveSceneIndex]->UpdateLightmaps();
|
||||
}
|
||||
}
|
||||
|
||||
reportProgress(BuildProgressStep::RenderHemispheres, 1.0f);
|
||||
|
||||
#if DEBUG_EXPORT_HEMISPHERES_PREVIEW
|
||||
for (int32 sceneIndex = 0; sceneIndex < _scenes.Count(); sceneIndex++)
|
||||
downloadDebugHemisphereAtlases(_scenes[sceneIndex]);
|
||||
#endif
|
||||
|
||||
// References:
|
||||
// "Optimization of numerical calculations execution time in multiprocessor systems" - Wojciech Figat
|
||||
// https://knarkowicz.wordpress.com/2014/07/20/lightmapping-in-anomaly-2-mobile/
|
||||
// http://the-witness.net/news/2010/09/hemicube-rendering-and-integration/
|
||||
// http://the-witness.net/news/2010/03/graphics-tech-texture-parameterization/
|
||||
// http://the-witness.net/news/2010/03/graphics-tech-lighting-comparison/
|
||||
|
||||
// Some ideas:
|
||||
// - render hemispheres to atlas or sth and batch integration and downscalling for multiply texels
|
||||
// - use conservative rasterization for dx12 instead of blur or MSAA for all platforms
|
||||
// - use hemisphere depth buffer to compute AO
|
||||
|
||||
// End
|
||||
const int32 hemispheresRenderedCount = hemispheresCount * bounceCount;
|
||||
buildEnd = DateTime::NowUTC();
|
||||
LOG(Info, "Building lightmap finished! Time: {0}s, Lightmaps: {1}, Entries: {2}, Hemicubes rendered: {3}",
|
||||
static_cast<int32>((buildEnd - buildStart).GetTotalSeconds()),
|
||||
lightmapsCount,
|
||||
entriesCount,
|
||||
hemispheresRenderedCount);
|
||||
buildFailed = false;
|
||||
|
||||
BUILDING_END:
|
||||
|
||||
// Cleanup cached data
|
||||
reportProgress(BuildProgressStep::Cleanup, 0.0f);
|
||||
|
||||
Reference in New Issue
Block a user