Continue refactoring model tool to support importing multiple objects properly

This commit is contained in:
Wojtek Figat
2023-12-03 10:55:40 +01:00
parent c8dd2c045c
commit 022a69aaf2
3 changed files with 452 additions and 493 deletions

View File

@@ -16,6 +16,7 @@
#include "Engine/Content/Assets/Animation.h"
#include "Engine/Content/Content.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Utilities/RectPack.h"
#include "AssetsImportingManager.h"
bool ImportModel::TryGetImportOptions(const StringView& path, Options& options)
@@ -48,6 +49,85 @@ bool ImportModel::TryGetImportOptions(const StringView& path, Options& options)
return false;
}
void RepackMeshLightmapUVs(ModelData& data)
{
// Use weight-based coordinates space placement and rect-pack to allocate more space for bigger meshes in the model lightmap chart
int32 lodIndex = 0;
auto& lod = data.LODs[lodIndex];
// Build list of meshes with their area
struct LightmapUVsPack : RectPack<LightmapUVsPack, float>
{
LightmapUVsPack(float x, float y, float width, float height)
: RectPack<LightmapUVsPack, float>(x, y, width, height)
{
}
void OnInsert()
{
}
};
struct MeshEntry
{
MeshData* Mesh;
float Area;
float Size;
LightmapUVsPack* Slot;
};
Array<MeshEntry> entries;
entries.Resize(lod.Meshes.Count());
float areaSum = 0;
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
{
auto& entry = entries[meshIndex];
entry.Mesh = lod.Meshes[meshIndex];
entry.Area = entry.Mesh->CalculateTrianglesArea();
entry.Size = Math::Sqrt(entry.Area);
areaSum += entry.Area;
}
if (areaSum > ZeroTolerance)
{
// Pack all surfaces into atlas
float atlasSize = Math::Sqrt(areaSum) * 1.02f;
int32 triesLeft = 10;
while (triesLeft--)
{
bool failed = false;
const float chartsPadding = (4.0f / 256.0f) * atlasSize;
LightmapUVsPack root(chartsPadding, chartsPadding, atlasSize - chartsPadding, atlasSize - chartsPadding);
for (auto& entry : entries)
{
entry.Slot = root.Insert(entry.Size, entry.Size, chartsPadding);
if (entry.Slot == nullptr)
{
// Failed to insert surface, increase atlas size and try again
atlasSize *= 1.5f;
failed = true;
break;
}
}
if (!failed)
{
// Transform meshes lightmap UVs into the slots in the whole atlas
const float atlasSizeInv = 1.0f / atlasSize;
for (const auto& entry : entries)
{
Float2 uvOffset(entry.Slot->X * atlasSizeInv, entry.Slot->Y * atlasSizeInv);
Float2 uvScale((entry.Slot->Width - chartsPadding) * atlasSizeInv, (entry.Slot->Height - chartsPadding) * atlasSizeInv);
// TODO: SIMD
for (auto& uv : entry.Mesh->LightmapUVs)
{
uv = uv * uvScale + uvOffset;
}
}
break;
}
}
}
}
void TryRestoreMaterials(CreateAssetContext& context, ModelData& modelData)
{
// Skip if file is missing
@@ -295,6 +375,13 @@ CreateAssetResult ImportModel::Import(CreateAssetContext& context)
TryRestoreMaterials(context, *data);
}
// When using generated lightmap UVs those coordinates needs to be moved so all meshes are in unique locations in [0-1]x[0-1] coordinates space
// Model importer generates UVs in [0-1] space for each mesh so now we need to pack them inside the whole model (only when using multiple meshes)
if (options.Type == ModelTool::ModelType::Model && options.LightmapUVsSource == ModelLightmapUVsSource::Generate && data->LODs.HasItems() && data->LODs[0].Meshes.Count() > 1)
{
RepackMeshLightmapUVs(*data);
}
// Create destination asset type
CreateAssetResult result = CreateAssetResult::InvalidTypeID;
switch (options.Type)