Fixes for building editor for Linux
This commit is contained in:
@@ -103,6 +103,8 @@ void EditorAnalytics::StartSession()
|
|||||||
{ UA_DOCUMENT_TITLE, 0, "Flax Editor" },
|
{ UA_DOCUMENT_TITLE, 0, "Flax Editor" },
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
{ UA_USER_AGENT, 0, "Windows " FLAXENGINE_VERSION_TEXT },
|
{ UA_USER_AGENT, 0, "Windows " FLAXENGINE_VERSION_TEXT },
|
||||||
|
#elif PLATFORM_LINUX
|
||||||
|
{ UA_USER_AGENT, 0, "Linux " FLAXENGINE_VERSION_TEXT },
|
||||||
#else
|
#else
|
||||||
#error "Unknown platform"
|
#error "Unknown platform"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ void CSG::Mesh::Build(Brush* parentBrush)
|
|||||||
for (int32 planeIndex3 = planeIndex2 + 1; planeIndex3 < surfacesCount; planeIndex3++)
|
for (int32 planeIndex3 = planeIndex2 + 1; planeIndex3 < surfacesCount; planeIndex3++)
|
||||||
{
|
{
|
||||||
Surface plane3 = _surfaces[planeIndex3];
|
Surface plane3 = _surfaces[planeIndex3];
|
||||||
|
int32 vertexIndex;
|
||||||
|
|
||||||
// Calculate the intersection point
|
// Calculate the intersection point
|
||||||
Vector3 vertex = Plane::Intersection(plane1, plane2, plane3);
|
Vector3 vertex = Plane::Intersection(plane1, plane2, plane3);
|
||||||
@@ -127,7 +128,7 @@ void CSG::Mesh::Build(Brush* parentBrush)
|
|||||||
goto SkipIntersection;
|
goto SkipIntersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 vertexIndex = _vertices.Count();
|
vertexIndex = _vertices.Count();
|
||||||
_vertices.Add(vertex);
|
_vertices.Add(vertex);
|
||||||
|
|
||||||
// Add intersection point to our list
|
// Add intersection point to our list
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if PLATFORM_LINUX
|
#if PLATFORM_ANDROID
|
||||||
typedef AndroidPlatformSettings PlatformSettings;
|
typedef AndroidPlatformSettings PlatformSettings;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ public class ShadersCompilation : EngineModule
|
|||||||
//options.PrivateDependencies.Add("ShaderCompilerOGL");
|
//options.PrivateDependencies.Add("ShaderCompilerOGL");
|
||||||
options.PrivateDependencies.Add("ShaderCompilerVulkan");
|
options.PrivateDependencies.Add("ShaderCompilerVulkan");
|
||||||
break;
|
break;
|
||||||
|
case TargetPlatform.Linux:
|
||||||
|
options.PrivateDependencies.Add("ShaderCompilerVulkan");
|
||||||
|
break;
|
||||||
default: throw new InvalidPlatformException(options.Platform.Target);
|
default: throw new InvalidPlatformException(options.Platform.Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include "Engine/ContentImporters/AssetsImportingManager.h"
|
#include "Engine/ContentImporters/AssetsImportingManager.h"
|
||||||
#include "Engine/ContentImporters/ImportTexture.h"
|
#include "Engine/ContentImporters/ImportTexture.h"
|
||||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||||
#include <ThirdParty/DirectXTex/DirectXTex.h>
|
|
||||||
|
|
||||||
ShadowsOfMordor::Builder::LightmapBuildCache::~LightmapBuildCache()
|
ShadowsOfMordor::Builder::LightmapBuildCache::~LightmapBuildCache()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,13 +8,313 @@
|
|||||||
#include "Engine/Graphics/RenderTargetPool.h"
|
#include "Engine/Graphics/RenderTargetPool.h"
|
||||||
|
|
||||||
#define STEPS_SLEEP_TIME 20
|
#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()
|
int32 ShadowsOfMordor::Builder::doWork()
|
||||||
{
|
{
|
||||||
// Start
|
// Start
|
||||||
bool buildFailed = true;
|
bool buildFailed = true;
|
||||||
DateTime buildEnd, buildStart = DateTime::NowUTC();
|
DateTime buildStart = DateTime::NowUTC();
|
||||||
_lastStep = BuildProgressStep::CacheEntries;
|
_lastStep = BuildProgressStep::CacheEntries;
|
||||||
_lastStepStart = buildStart;
|
_lastStepStart = buildStart;
|
||||||
_hemispheresPerJob = HEMISPHERES_PER_JOB_MIN;
|
_hemispheresPerJob = HEMISPHERES_PER_JOB_MIN;
|
||||||
@@ -84,309 +384,14 @@ int32 ShadowsOfMordor::Builder::doWork()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run
|
||||||
IsBakingLightmaps = true;
|
IsBakingLightmaps = true;
|
||||||
|
buildFailed = doWorkInner(buildStart);
|
||||||
#if HEMISPHERES_BAKE_STATE_SAVE
|
if (buildFailed && !checkBuildCancelled())
|
||||||
_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);
|
OnBuildFinished(buildFailed);
|
||||||
const int32 firstScene = _workerActiveSceneIndex;
|
return 0;
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
#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
|
// Cleanup cached data
|
||||||
reportProgress(BuildProgressStep::Cleanup, 0.0f);
|
reportProgress(BuildProgressStep::Cleanup, 0.0f);
|
||||||
|
|||||||
@@ -313,6 +313,7 @@ namespace ShadowsOfMordor
|
|||||||
bool waitForJobDataSync();
|
bool waitForJobDataSync();
|
||||||
static bool sortCharts(const LightmapUVsChart& a, const LightmapUVsChart& b);
|
static bool sortCharts(const LightmapUVsChart& a, const LightmapUVsChart& b);
|
||||||
|
|
||||||
|
bool doWorkInner(DateTime buildStart);
|
||||||
int32 doWork();
|
int32 doWork();
|
||||||
|
|
||||||
void cacheEntries();
|
void cacheEntries();
|
||||||
|
|||||||
@@ -49,8 +49,17 @@ public class ModelTool : EngineModule
|
|||||||
options.PrivateDependencies.Add("TextureTool");
|
options.PrivateDependencies.Add("TextureTool");
|
||||||
options.PrivateDefinitions.Add("COMPILE_WITH_ASSETS_IMPORTER");
|
options.PrivateDefinitions.Add("COMPILE_WITH_ASSETS_IMPORTER");
|
||||||
|
|
||||||
options.PrivateDependencies.Add("DirectXMesh");
|
switch (options.Platform.Target)
|
||||||
options.PrivateDependencies.Add("UVAtlas");
|
{
|
||||||
|
case TargetPlatform.Windows:
|
||||||
|
options.PrivateDependencies.Add("DirectXMesh");
|
||||||
|
options.PrivateDependencies.Add("UVAtlas");
|
||||||
|
break;
|
||||||
|
case TargetPlatform.Linux:
|
||||||
|
break;
|
||||||
|
default: throw new InvalidPlatformException(options.Platform.Target);
|
||||||
|
}
|
||||||
|
|
||||||
options.PrivateDependencies.Add("meshoptimizer");
|
options.PrivateDependencies.Add("meshoptimizer");
|
||||||
|
|
||||||
options.PublicDefinitions.Add("COMPILE_WITH_MODEL_TOOL");
|
options.PublicDefinitions.Add("COMPILE_WITH_MODEL_TOOL");
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ void OptimizeCurve(LinearCurve<T>& curve)
|
|||||||
{
|
{
|
||||||
auto& oldKeyframes = curve.GetKeyframes();
|
auto& oldKeyframes = curve.GetKeyframes();
|
||||||
const int32 keyCount = oldKeyframes.Count();
|
const int32 keyCount = oldKeyframes.Count();
|
||||||
LinearCurve<T>::KeyFrameCollection newKeyframes(keyCount);
|
typename LinearCurve<T>::KeyFrameCollection newKeyframes(keyCount);
|
||||||
bool lastWasEqual = false;
|
bool lastWasEqual = false;
|
||||||
|
|
||||||
for (int32 i = 0; i < keyCount; i++)
|
for (int32 i = 0; i < keyCount; i++)
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
// [Graph]
|
// [Graph]
|
||||||
bool onNodeLoaded(Node* n) override
|
bool onNodeLoaded(NodeType* n) override
|
||||||
{
|
{
|
||||||
// Check if this node needs a state or data cache
|
// Check if this node needs a state or data cache
|
||||||
switch (n->GroupID)
|
switch (n->GroupID)
|
||||||
|
|||||||
2
Source/ThirdParty/curl/curl.Build.cs
vendored
2
Source/ThirdParty/curl/curl.Build.cs
vendored
@@ -34,6 +34,8 @@ public class curl : DepsModule
|
|||||||
options.OutputFiles.Add("wldap32.lib");
|
options.OutputFiles.Add("wldap32.lib");
|
||||||
options.OutputFiles.Add("crypt32.lib");
|
options.OutputFiles.Add("crypt32.lib");
|
||||||
break;
|
break;
|
||||||
|
case TargetPlatform.Linux:
|
||||||
|
break;
|
||||||
default: throw new InvalidPlatformException(options.Platform.Target);
|
default: throw new InvalidPlatformException(options.Platform.Target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user