**Refactor meshes format to support custom vertex layouts and new flexible api to access mesh data**
#3044 #2667
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
|
||||
|
||||
/// <summary>
|
||||
/// Model Asset Upgrader
|
||||
@@ -13,17 +16,145 @@
|
||||
class ModelAssetUpgrader : public BinaryAssetUpgrader
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ModelAssetUpgrader"/> class.
|
||||
/// </summary>
|
||||
ModelAssetUpgrader()
|
||||
{
|
||||
static const Upgrader upgraders[] =
|
||||
Upgrader upgraders[] =
|
||||
{
|
||||
{},
|
||||
{ 25, 30, Upgrade_25_To_30 }, // [Deprecated in v1.10]
|
||||
};
|
||||
setup(upgraders, ARRAY_COUNT(upgraders));
|
||||
}
|
||||
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
static bool Upgrade_25_To_30(AssetMigrationContext& context)
|
||||
{
|
||||
// [Deprecated in v1.10]
|
||||
ASSERT(context.Input.SerializedVersion == 25 && context.Output.SerializedVersion == 30);
|
||||
MemoryWriteStream output;
|
||||
|
||||
// Upgrade header
|
||||
byte lodsCount;
|
||||
Array<int32, FixedAllocation<6>> meshesCountPerLod;
|
||||
{
|
||||
if (context.AllocateChunk(0))
|
||||
return true;
|
||||
auto& data = context.Input.Header.Chunks[0]->Data;
|
||||
MemoryReadStream stream(data.Get(), data.Length());
|
||||
|
||||
constexpr byte headerVersion = 2;
|
||||
output.Write(headerVersion);
|
||||
|
||||
float minScreenSize;
|
||||
stream.Read(minScreenSize);
|
||||
output.Write(minScreenSize);
|
||||
|
||||
// Materials
|
||||
int32 materialSlotsCount;
|
||||
stream.Read(materialSlotsCount);
|
||||
output.Write(materialSlotsCount);
|
||||
CHECK_RETURN(materialSlotsCount >= 0 && materialSlotsCount < 4096, true);
|
||||
for (int32 materialSlotIndex = 0; materialSlotIndex < materialSlotsCount; materialSlotIndex++)
|
||||
{
|
||||
Guid materialId;
|
||||
stream.Read(materialId);
|
||||
output.Write(materialId);
|
||||
byte shadowsCastingMode;
|
||||
stream.Read(shadowsCastingMode);
|
||||
output.Write(shadowsCastingMode);
|
||||
String name;
|
||||
stream.Read(name, 11);
|
||||
output.Write(name, 11);
|
||||
}
|
||||
|
||||
// LODs
|
||||
stream.Read(lodsCount);
|
||||
output.Write(lodsCount);
|
||||
CHECK_RETURN(lodsCount <= 6, true);
|
||||
meshesCountPerLod.Resize(lodsCount);
|
||||
for (int32 lodIndex = 0; lodIndex < lodsCount; lodIndex++)
|
||||
{
|
||||
float screenSize;
|
||||
stream.Read(screenSize);
|
||||
output.Write(screenSize);
|
||||
|
||||
// Amount of meshes
|
||||
uint16 meshesCount;
|
||||
stream.Read(meshesCount);
|
||||
output.Write(meshesCount);
|
||||
CHECK_RETURN(meshesCount > 0 && meshesCount < 4096, true);
|
||||
meshesCountPerLod[lodIndex] = meshesCount;
|
||||
for (uint16 meshIndex = 0; meshIndex < meshesCount; meshIndex++)
|
||||
{
|
||||
int32 materialSlotIndex;
|
||||
stream.Read(materialSlotIndex);
|
||||
output.Write(materialSlotIndex);
|
||||
BoundingBox box;
|
||||
stream.Read(box);
|
||||
output.Write(box);
|
||||
BoundingSphere sphere;
|
||||
stream.Read(sphere);
|
||||
output.Write(sphere);
|
||||
bool hasLightmapUVs = stream.ReadBool();
|
||||
int8 lightmapUVsIndex = hasLightmapUVs ? 1 : -1;
|
||||
output.Write(lightmapUVsIndex);
|
||||
}
|
||||
}
|
||||
|
||||
context.Output.Header.Chunks[0]->Data.Copy(output.GetHandle(), output.GetPosition());
|
||||
}
|
||||
|
||||
// Upgrade meshes data
|
||||
for (int32 lodIndex = 0; lodIndex < lodsCount; lodIndex++)
|
||||
{
|
||||
output.SetPosition(0);
|
||||
const int32 chunkIndex = lodIndex + 1;
|
||||
const FlaxChunk* lodData = context.Input.Header.Chunks[chunkIndex];
|
||||
MemoryReadStream stream(lodData->Get(), lodData->Size());
|
||||
|
||||
constexpr byte meshVersion = 2;
|
||||
output.Write(meshVersion);
|
||||
for (int32 meshIndex = 0; meshIndex < meshesCountPerLod[lodIndex]; meshIndex++)
|
||||
{
|
||||
// Descriptor
|
||||
uint32 vertices, triangles;
|
||||
stream.Read(vertices);
|
||||
stream.Read(triangles);
|
||||
output.Write(vertices);
|
||||
output.Write(triangles);
|
||||
auto vb0 = stream.Move<VB0ElementType18>(vertices);
|
||||
auto vb1 = stream.Move<VB1ElementType18>(vertices);
|
||||
bool hasColors = stream.ReadBool();
|
||||
VB2ElementType18* vb2 = nullptr;
|
||||
if (hasColors)
|
||||
vb2 = stream.Move<VB2ElementType18>(vertices);
|
||||
uint32 indicesCount = triangles * 3;
|
||||
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
|
||||
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
||||
auto ibData = stream.Move(indicesCount * ibStride);
|
||||
byte vbCount = hasColors ? 3 : 2;
|
||||
output.Write(vbCount);
|
||||
output.Write(VB0ElementType18::GetLayout()->GetElements());
|
||||
output.Write(VB1ElementType18::GetLayout()->GetElements());
|
||||
if (hasColors)
|
||||
output.Write(VB2ElementType18::GetLayout()->GetElements());
|
||||
|
||||
// Buffers
|
||||
output.WriteBytes(vb0, vertices * sizeof(VB0ElementType18));
|
||||
output.WriteBytes(vb1, vertices * sizeof(VB1ElementType18));
|
||||
if (hasColors)
|
||||
output.WriteBytes(vb2, vertices * sizeof(VB2ElementType18));
|
||||
output.WriteBytes(ibData, indicesCount * ibStride);
|
||||
}
|
||||
|
||||
if (context.AllocateChunk(chunkIndex))
|
||||
return true;
|
||||
context.Output.Header.Chunks[chunkIndex]->Data.Copy(output.GetHandle(), output.GetPosition());
|
||||
}
|
||||
|
||||
// Copy SDF data
|
||||
return CopyChunk(context, 15);
|
||||
}
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||
#include "Engine/Graphics/Models/BlendShape.h"
|
||||
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
|
||||
|
||||
/// <summary>
|
||||
/// Skinned Model Asset Upgrader
|
||||
@@ -13,17 +17,218 @@
|
||||
class SkinnedModelAssetUpgrader : public BinaryAssetUpgrader
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SkinnedModelAssetUpgrader"/> class.
|
||||
/// </summary>
|
||||
SkinnedModelAssetUpgrader()
|
||||
{
|
||||
static const Upgrader upgraders[] =
|
||||
const Upgrader upgraders[] =
|
||||
{
|
||||
{},
|
||||
{ 5, 30, Upgrade_5_To_30 }, // [Deprecated in v1.10]
|
||||
};
|
||||
setup(upgraders, ARRAY_COUNT(upgraders));
|
||||
}
|
||||
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
static bool Upgrade_5_To_30(AssetMigrationContext& context)
|
||||
{
|
||||
// [Deprecated in v1.10]
|
||||
ASSERT(context.Input.SerializedVersion == 5 && context.Output.SerializedVersion == 30);
|
||||
MemoryWriteStream output;
|
||||
|
||||
// Upgrade header
|
||||
byte lodsCount;
|
||||
Array<int32, FixedAllocation<6>> meshesCountPerLod;
|
||||
{
|
||||
if (context.AllocateChunk(0))
|
||||
return true;
|
||||
auto& data = context.Input.Header.Chunks[0]->Data;
|
||||
MemoryReadStream stream(data.Get(), data.Length());
|
||||
|
||||
constexpr byte headerVersion = 2;
|
||||
byte headerVersionOld;
|
||||
stream.Read(headerVersionOld);
|
||||
CHECK_RETURN(headerVersionOld == 1, true);
|
||||
output.Write(headerVersion);
|
||||
|
||||
float minScreenSize;
|
||||
stream.Read(minScreenSize);
|
||||
output.Write(minScreenSize);
|
||||
|
||||
// Materials
|
||||
int32 materialSlotsCount;
|
||||
stream.Read(materialSlotsCount);
|
||||
output.Write(materialSlotsCount);
|
||||
CHECK_RETURN(materialSlotsCount >= 0 && materialSlotsCount < 4096, true);
|
||||
for (int32 materialSlotIndex = 0; materialSlotIndex < materialSlotsCount; materialSlotIndex++)
|
||||
{
|
||||
Guid materialId;
|
||||
stream.Read(materialId);
|
||||
output.Write(materialId);
|
||||
byte shadowsCastingMode;
|
||||
stream.Read(shadowsCastingMode);
|
||||
output.Write(shadowsCastingMode);
|
||||
String name;
|
||||
stream.Read(name, 11);
|
||||
output.Write(name, 11);
|
||||
}
|
||||
|
||||
// LODs
|
||||
stream.Read(lodsCount);
|
||||
output.Write(lodsCount);
|
||||
CHECK_RETURN(materialSlotsCount <= 6, true);
|
||||
meshesCountPerLod.Resize(lodsCount);
|
||||
for (int32 lodIndex = 0; lodIndex < lodsCount; lodIndex++)
|
||||
{
|
||||
float screenSize;
|
||||
stream.Read(screenSize);
|
||||
output.Write(screenSize);
|
||||
|
||||
// Amount of meshes
|
||||
uint16 meshesCount;
|
||||
stream.Read(meshesCount);
|
||||
output.Write(meshesCount);
|
||||
CHECK_RETURN(meshesCount > 0 && meshesCount < 4096, true);
|
||||
meshesCountPerLod[lodIndex] = meshesCount;
|
||||
for (uint16 meshIndex = 0; meshIndex < meshesCount; meshIndex++)
|
||||
{
|
||||
int32 materialSlotIndex;
|
||||
stream.Read(materialSlotIndex);
|
||||
output.Write(materialSlotIndex);
|
||||
BoundingBox box;
|
||||
stream.Read(box);
|
||||
output.Write(box);
|
||||
BoundingSphere sphere;
|
||||
stream.Read(sphere);
|
||||
output.Write(sphere);
|
||||
uint16 blendShapesCount;
|
||||
stream.Read(blendShapesCount);
|
||||
output.Write(blendShapesCount);
|
||||
for (int32 blendShapeIndex = 0; blendShapeIndex < blendShapesCount; blendShapeIndex++)
|
||||
{
|
||||
String name;
|
||||
stream.Read(name, 13);
|
||||
output.Write(name, 13);
|
||||
float weight;
|
||||
stream.Read(weight);
|
||||
output.Write(weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skeleton
|
||||
{
|
||||
int32 nodesCount;
|
||||
stream.Read(nodesCount);
|
||||
output.Write(nodesCount);
|
||||
if (nodesCount < 0)
|
||||
return true;
|
||||
for (int32 i = 0 ; i < nodesCount; i++)
|
||||
{
|
||||
int32 parentIndex;
|
||||
Transform localTransform;
|
||||
String name;
|
||||
stream.Read(parentIndex);
|
||||
output.Write(parentIndex);
|
||||
stream.Read(localTransform);
|
||||
output.Write(localTransform);
|
||||
stream.Read(name, 71);
|
||||
output.Write(name, 71);
|
||||
}
|
||||
|
||||
int32 bonesCount;
|
||||
stream.Read(bonesCount);
|
||||
output.Write(bonesCount);
|
||||
if (bonesCount < 0)
|
||||
return true;
|
||||
for (int32 i = 0 ; i < bonesCount; i++)
|
||||
{
|
||||
int32 parentIndex, nodeIndex;
|
||||
Transform localTransform;
|
||||
String name;
|
||||
Matrix offsetMatrix;
|
||||
stream.Read(parentIndex);
|
||||
output.Write(parentIndex);
|
||||
stream.Read(nodeIndex);
|
||||
output.Write(nodeIndex);
|
||||
stream.Read(localTransform);
|
||||
output.Write(localTransform);
|
||||
stream.Read(offsetMatrix);
|
||||
output.Write(offsetMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
// Retargeting
|
||||
{
|
||||
int32 entriesCount;
|
||||
stream.Read(entriesCount);
|
||||
output.Write(entriesCount);
|
||||
for (int32 i = 0 ; i < entriesCount; i++)
|
||||
{
|
||||
Guid sourceAsset, skeletonAsset;
|
||||
Dictionary<String, String> nodesMapping;
|
||||
stream.Read(sourceAsset);
|
||||
output.Write(sourceAsset);
|
||||
stream.Read(skeletonAsset);
|
||||
output.Write(skeletonAsset);
|
||||
stream.Read(nodesMapping);
|
||||
output.Write(nodesMapping);
|
||||
}
|
||||
}
|
||||
|
||||
context.Output.Header.Chunks[0]->Data.Copy(output.GetHandle(), output.GetPosition());
|
||||
}
|
||||
|
||||
// Upgrade meshes data
|
||||
for (int32 lodIndex = 0; lodIndex < lodsCount; lodIndex++)
|
||||
{
|
||||
output.SetPosition(0);
|
||||
const int32 chunkIndex = lodIndex + 1;
|
||||
const FlaxChunk* lodData = context.Input.Header.Chunks[chunkIndex];
|
||||
MemoryReadStream stream(lodData->Get(), lodData->Size());
|
||||
|
||||
constexpr byte meshVersion = 2;
|
||||
byte headerVersionOld;
|
||||
stream.Read(headerVersionOld);
|
||||
CHECK_RETURN(headerVersionOld == 1, true);
|
||||
output.Write(meshVersion);
|
||||
for (int32 meshIndex = 0; meshIndex < meshesCountPerLod[lodIndex]; meshIndex++)
|
||||
{
|
||||
// Descriptor
|
||||
uint32 vertices, triangles;
|
||||
stream.Read(vertices);
|
||||
stream.Read(triangles);
|
||||
output.Write(vertices);
|
||||
output.Write(triangles);
|
||||
uint16 blendShapesCount;
|
||||
stream.Read(blendShapesCount);
|
||||
Array<BlendShape> blendShapes;
|
||||
blendShapes.Resize(blendShapesCount);
|
||||
for (auto& blendShape : blendShapes)
|
||||
blendShape.Load(stream, meshVersion);
|
||||
auto vb0 = stream.Move<VB0SkinnedElementType2>(vertices);
|
||||
uint32 indicesCount = triangles * 3;
|
||||
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
|
||||
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
||||
auto ibData = stream.Move(indicesCount * ibStride);
|
||||
output.Write((byte)1);
|
||||
output.Write(VB0SkinnedElementType2::GetLayout()->GetElements());
|
||||
|
||||
// Buffers
|
||||
output.WriteBytes(vb0, vertices * sizeof(VB0SkinnedElementType2));
|
||||
output.WriteBytes(ibData, indicesCount * ibStride);
|
||||
|
||||
// Blend Shapes
|
||||
output.Write(blendShapesCount);
|
||||
for (auto& blendShape : blendShapes)
|
||||
blendShape.Save(output);
|
||||
}
|
||||
|
||||
if (context.AllocateChunk(chunkIndex))
|
||||
return true;
|
||||
context.Output.Header.Chunks[chunkIndex]->Data.Copy(output.GetHandle(), output.GetPosition());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user