You're breathtaking!
This commit is contained in:
167
Source/Engine/ShadowsOfMordor/Builder.Charts.cpp
Normal file
167
Source/Engine/ShadowsOfMordor/Builder.Charts.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Builder.h"
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "AtlasChartsPacker.h"
|
||||
#include "Engine/Level/Scene/SceneLightmapsData.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Core/Collections/Sorting.h"
|
||||
#include "Engine/ContentImporters/ImportTexture.h"
|
||||
#include "Engine/Level/SceneQuery.h"
|
||||
#include "Engine/Level/Scene/Lightmap.h"
|
||||
|
||||
bool ShadowsOfMordor::Builder::sortCharts(const LightmapUVsChart& a, const LightmapUVsChart& b)
|
||||
{
|
||||
// Sort by area
|
||||
return (b.Width * b.Height) < (a.Width * a.Height);
|
||||
}
|
||||
|
||||
void ShadowsOfMordor::Builder::generateCharts()
|
||||
{
|
||||
reportProgress(BuildProgressStep::GenerateLightmapCharts, 0.0f);
|
||||
|
||||
auto scene = _scenes[_workerActiveSceneIndex];
|
||||
auto& settings = scene->GetSettings();
|
||||
ScopeLock lock(scene->EntriesLocker);
|
||||
|
||||
// Generate lightmap UVs charts
|
||||
const int32 entriesCount = scene->Entries.Count();
|
||||
scene->Charts.EnsureCapacity(entriesCount);
|
||||
const int32 MaximumChartSize = (int32)settings.AtlasSize - settings.ChartsPadding * 2;
|
||||
for (int32 i = 0; i < entriesCount; i++)
|
||||
{
|
||||
LightmapUVsChart chart;
|
||||
chart.Result.TextureIndex = INVALID_INDEX;
|
||||
|
||||
GeometryEntry& entry = scene->Entries[i];
|
||||
entry.ChartIndex = INVALID_INDEX;
|
||||
|
||||
// Calculate desired area for the entry's chart (based on object dimensions and settings)
|
||||
// Reject missing models or too small objects
|
||||
Vector3 size = entry.Box.GetSize();
|
||||
float dimensionsCoeff = size.AverageArithmetic();
|
||||
if (size.X <= 1.0f)
|
||||
dimensionsCoeff = Vector2(size.Y, size.Z).AverageArithmetic();
|
||||
else if (size.Y <= 1.0f)
|
||||
dimensionsCoeff = Vector2(size.X, size.Z).AverageArithmetic();
|
||||
else if (size.Z <= 1.0f)
|
||||
dimensionsCoeff = Vector2(size.Y, size.X).AverageArithmetic();
|
||||
const float scale = settings.GlobalObjectsScale * entry.Scale * LightmapTexelsPerWorldUnit * dimensionsCoeff;
|
||||
if (scale <= ZeroTolerance)
|
||||
continue;
|
||||
|
||||
// Apply lightmap uvs bounding box (in uv space) to reduce waste of lightmap atlas space
|
||||
chart.Width = Math::Clamp(Math::CeilToInt(scale * entry.UVsBox.GetWidth()), LightmapMinChartSize, MaximumChartSize);
|
||||
chart.Height = Math::Clamp(Math::CeilToInt(scale * entry.UVsBox.GetHeight()), LightmapMinChartSize, MaximumChartSize);
|
||||
|
||||
// Register lightmap atlas chart entry
|
||||
chart.EntryIndex = i;
|
||||
scene->Charts.Add(chart);
|
||||
|
||||
// Progress Point
|
||||
reportProgress(BuildProgressStep::GenerateLightmapCharts, static_cast<float>(i) / entriesCount);
|
||||
}
|
||||
|
||||
reportProgress(BuildProgressStep::GenerateLightmapCharts, 1.0f);
|
||||
}
|
||||
|
||||
void ShadowsOfMordor::Builder::packCharts()
|
||||
{
|
||||
reportProgress(BuildProgressStep::PackLightmapCharts, 0.0f);
|
||||
auto scene = _scenes[_workerActiveSceneIndex];
|
||||
|
||||
// Pack UV charts into atlases
|
||||
Array<AtlasChartsPacker*> packers;
|
||||
if (scene->Charts.HasItems())
|
||||
{
|
||||
// Sort charts from the biggest to the smallest
|
||||
Sorting::QuickSort(scene->Charts.Get(), scene->Charts.Count(), &sortCharts);
|
||||
|
||||
reportProgress(BuildProgressStep::PackLightmapCharts, 0.1f);
|
||||
|
||||
// Cache charts indices after sorting operation
|
||||
scene->EntriesLocker.Lock();
|
||||
for (int32 chartIndex = 0; chartIndex < scene->Charts.Count(); chartIndex++)
|
||||
{
|
||||
auto& chart = scene->Charts[chartIndex];
|
||||
scene->Entries[chart.EntryIndex].ChartIndex = chartIndex;
|
||||
}
|
||||
scene->EntriesLocker.Unlock();
|
||||
|
||||
reportProgress(BuildProgressStep::PackLightmapCharts, 0.5f);
|
||||
|
||||
// Pack all the charts
|
||||
for (int32 i = 0; i < scene->Charts.Count(); i++)
|
||||
{
|
||||
auto chart = &scene->Charts[i];
|
||||
|
||||
bool cannotPack = true;
|
||||
for (int32 j = 0; j < packers.Count(); j++)
|
||||
{
|
||||
if (packers[j]->Insert(chart))
|
||||
{
|
||||
chart->Result.TextureIndex = j;
|
||||
cannotPack = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cannotPack)
|
||||
{
|
||||
auto packer = New<AtlasChartsPacker>(&scene->GetSettings());
|
||||
auto result = packer->Insert(chart);
|
||||
ASSERT(result);
|
||||
chart->Result.TextureIndex = packers.Count();
|
||||
packers.Add(packer);
|
||||
}
|
||||
}
|
||||
}
|
||||
const int32 lightmapsCount = scene->LightmapsCount = packers.Count();
|
||||
LOG(Info, "Scene \'{0}\': building {1} lightmap(s) ({2} chart(s) to bake)...", scene->Scene->GetName(), lightmapsCount, scene->Charts.Count());
|
||||
packers.ClearDelete();
|
||||
|
||||
// Progress Point
|
||||
reportProgress(BuildProgressStep::PackLightmapCharts, 1.0f);
|
||||
}
|
||||
|
||||
void ShadowsOfMordor::Builder::updateLightmaps()
|
||||
{
|
||||
reportProgress(BuildProgressStep::UpdateLightmapsCollection, 0.0f);
|
||||
|
||||
auto scene = _scenes[_workerActiveSceneIndex];
|
||||
auto& settings = scene->GetSettings();
|
||||
const int32 lightmapsCount = scene->LightmapsCount;
|
||||
|
||||
// Update lightmaps collection
|
||||
scene->Scene->LightmapsData.UpdateLightmapsCollection(lightmapsCount, (int32)settings.AtlasSize);
|
||||
scene->Lightmaps.Resize(lightmapsCount, false);
|
||||
for (int32 lightmapIndex = 0; lightmapIndex < lightmapsCount; lightmapIndex++)
|
||||
{
|
||||
if (scene->Lightmaps[lightmapIndex].Init(&settings))
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for all lightmaps to be ready (after creating new lightmaps assets we need to wait for resources to be prepared)
|
||||
GPUDevice::Instance->Locker.Lock();
|
||||
for (int32 lightmapIndex = 0; lightmapIndex < lightmapsCount; lightmapIndex++)
|
||||
{
|
||||
Texture* textures[NUM_SH_TARGETS];
|
||||
scene->Scene->LightmapsData.GetLightmap(lightmapIndex)->GetTextures(textures);
|
||||
for (int32 textureIndex = 0; textureIndex < NUM_SH_TARGETS; textureIndex++)
|
||||
{
|
||||
auto texture = textures[textureIndex];
|
||||
GPUDevice::Instance->Locker.Unlock();
|
||||
if (texture->WaitForLoaded())
|
||||
{
|
||||
LOG(Error, "Lightmap load failed.");
|
||||
return;
|
||||
}
|
||||
GPUDevice::Instance->Locker.Lock();
|
||||
}
|
||||
|
||||
reportProgress(BuildProgressStep::UpdateLightmapsCollection, (float)lightmapIndex / lightmapsCount);
|
||||
}
|
||||
GPUDevice::Instance->Locker.Unlock();
|
||||
|
||||
reportProgress(BuildProgressStep::UpdateLightmapsCollection, 1.0f);
|
||||
}
|
||||
Reference in New Issue
Block a user