**Refactor meshes format to support custom vertex layouts and new flexible api to access mesh data**
#3044 #2667
This commit is contained in:
@@ -9,12 +9,12 @@
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
#include "Engine/Serialization/FileWriteStream.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Graphics/Models/MeshAccessor.h"
|
||||
#include "Engine/Core/DeleteMe.h"
|
||||
|
||||
ExportAssetResult AssetExporters::ExportModel(ExportAssetContext& context)
|
||||
{
|
||||
// Prepare
|
||||
auto asset = (Model*)context.Asset.Get();
|
||||
auto asset = (ModelBase*)context.Asset.Get();
|
||||
auto lock = asset->Storage->LockSafe();
|
||||
auto path = GET_OUTPUT_PATH(context, "obj");
|
||||
const int32 lodIndex = 0;
|
||||
@@ -26,7 +26,6 @@ ExportAssetResult AssetExporters::ExportModel(ExportAssetContext& context)
|
||||
const auto chunk = asset->GetChunk(chunkIndex);
|
||||
if (!chunk)
|
||||
return ExportAssetResult::CannotLoadData;
|
||||
|
||||
MemoryReadStream stream(chunk->Get(), chunk->Size());
|
||||
FileWriteStream* output = FileWriteStream::Open(path);
|
||||
if (output == nullptr)
|
||||
@@ -37,62 +36,61 @@ ExportAssetResult AssetExporters::ExportModel(ExportAssetContext& context)
|
||||
output->WriteText(StringAnsi::Format("# Exported model {0}\n", name.Get()));
|
||||
|
||||
// Extract all meshes
|
||||
const auto& lod = asset->LODs[lodIndex];
|
||||
int32 vertexStart = 1; // OBJ counts vertices from 1 not from 0
|
||||
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
|
||||
if (asset->GetLODsCount() <= lodIndex)
|
||||
return ExportAssetResult::Error;
|
||||
Array<MeshBase*> meshes;
|
||||
asset->GetMeshes(meshes, lodIndex);
|
||||
uint32 vertexStart = 1; // OBJ counts vertices from 1 not from 0
|
||||
ModelBase::MeshData meshData;
|
||||
byte meshVersion = stream.ReadByte();
|
||||
for (int32 meshIndex = 0; meshIndex < meshes.Count(); meshIndex++)
|
||||
{
|
||||
auto& mesh = lod.Meshes[meshIndex];
|
||||
|
||||
// #MODEL_DATA_FORMAT_USAGE
|
||||
uint32 vertices;
|
||||
stream.ReadUint32(&vertices);
|
||||
uint32 triangles;
|
||||
stream.ReadUint32(&triangles);
|
||||
uint32 indicesCount = triangles * 3;
|
||||
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
|
||||
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
||||
if (vertices == 0 || triangles == 0)
|
||||
auto mesh = meshes[meshIndex];
|
||||
if (asset->LoadMesh(stream, meshVersion, mesh, &meshData))
|
||||
return ExportAssetResult::CannotLoadData;
|
||||
if (meshData.Vertices == 0 || meshData.Triangles == 0)
|
||||
return ExportAssetResult::Error;
|
||||
auto vb0 = stream.Move<VB0ElementType>(vertices);
|
||||
auto vb1 = stream.Move<VB1ElementType>(vertices);
|
||||
bool hasColors = stream.ReadBool();
|
||||
VB2ElementType18* vb2 = nullptr;
|
||||
if (hasColors)
|
||||
{
|
||||
vb2 = stream.Move<VB2ElementType18>(vertices);
|
||||
}
|
||||
auto ib = stream.Move<byte>(indicesCount * ibStride);
|
||||
|
||||
MeshAccessor accessor;
|
||||
if (accessor.LoadFromMeshData(&meshData))
|
||||
return ExportAssetResult::CannotLoadAsset;
|
||||
output->WriteText(StringAnsi::Format("# Mesh {0}\n", meshIndex));
|
||||
|
||||
for (uint32 i = 0; i < vertices; i++)
|
||||
auto positionStream = accessor.Position();
|
||||
if (!positionStream.IsValid())
|
||||
return ExportAssetResult::Error;
|
||||
for (uint32 i = 0; i < meshData.Vertices; i++)
|
||||
{
|
||||
auto v = vb0[i].Position;
|
||||
auto v = positionStream.GetFloat3(i);
|
||||
output->WriteText(StringAnsi::Format("v {0} {1} {2}\n", v.X, v.Y, v.Z));
|
||||
}
|
||||
|
||||
output->WriteChar('\n');
|
||||
|
||||
for (uint32 i = 0; i < vertices; i++)
|
||||
auto texCoordStream = accessor.TexCoord();
|
||||
if (texCoordStream.IsValid())
|
||||
{
|
||||
auto v = vb1[i].TexCoord.ToFloat2();
|
||||
output->WriteText(StringAnsi::Format("vt {0} {1}\n", v.X, v.Y));
|
||||
for (uint32 i = 0; i < meshData.Vertices; i++)
|
||||
{
|
||||
auto v = texCoordStream.GetFloat2(i);
|
||||
output->WriteText(StringAnsi::Format("vt {0} {1}\n", v.X, v.Y));
|
||||
}
|
||||
output->WriteChar('\n');
|
||||
}
|
||||
|
||||
output->WriteChar('\n');
|
||||
|
||||
for (uint32 i = 0; i < vertices; i++)
|
||||
auto normalStream = accessor.Normal();
|
||||
if (normalStream.IsValid())
|
||||
{
|
||||
auto v = vb1[i].Normal.ToFloat3() * 2.0f - 1.0f;
|
||||
output->WriteText(StringAnsi::Format("vn {0} {1} {2}\n", v.X, v.Y, v.Z));
|
||||
for (uint32 i = 0; i < meshData.Vertices; i++)
|
||||
{
|
||||
auto v = normalStream.GetFloat3(i) * 2.0f - 1.0f;
|
||||
output->WriteText(StringAnsi::Format("vn {0} {1} {2}\n", v.X, v.Y, v.Z));
|
||||
}
|
||||
output->WriteChar('\n');
|
||||
}
|
||||
|
||||
output->WriteChar('\n');
|
||||
|
||||
if (use16BitIndexBuffer)
|
||||
if (meshData.IBStride == sizeof(uint16))
|
||||
{
|
||||
auto t = (uint16*)ib;
|
||||
for (uint32 i = 0; i < triangles; i++)
|
||||
auto t = (const uint16*)meshData.IBData;
|
||||
for (uint32 i = 0; i < meshData.Triangles; i++)
|
||||
{
|
||||
auto i0 = vertexStart + *t++;
|
||||
auto i1 = vertexStart + *t++;
|
||||
@@ -102,8 +100,8 @@ ExportAssetResult AssetExporters::ExportModel(ExportAssetContext& context)
|
||||
}
|
||||
else
|
||||
{
|
||||
auto t = (uint32*)ib;
|
||||
for (uint32 i = 0; i < triangles; i++)
|
||||
auto t = (const uint32*)meshData.IBData;
|
||||
for (uint32 i = 0; i < meshData.Triangles; i++)
|
||||
{
|
||||
auto i0 = vertexStart + *t++;
|
||||
auto i1 = vertexStart + *t++;
|
||||
@@ -111,10 +109,9 @@ ExportAssetResult AssetExporters::ExportModel(ExportAssetContext& context)
|
||||
output->WriteText(StringAnsi::Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2));
|
||||
}
|
||||
}
|
||||
|
||||
output->WriteChar('\n');
|
||||
|
||||
vertexStart += vertices;
|
||||
vertexStart += meshData.Vertices;
|
||||
}
|
||||
|
||||
if (output->HasError())
|
||||
@@ -125,120 +122,8 @@ ExportAssetResult AssetExporters::ExportModel(ExportAssetContext& context)
|
||||
|
||||
ExportAssetResult AssetExporters::ExportSkinnedModel(ExportAssetContext& context)
|
||||
{
|
||||
// Prepare
|
||||
auto asset = (SkinnedModel*)context.Asset.Get();
|
||||
auto lock = asset->Storage->LockSafe();
|
||||
auto path = GET_OUTPUT_PATH(context, "obj");
|
||||
const int32 lodIndex = 0;
|
||||
|
||||
// Fetch chunk with data
|
||||
const auto chunkIndex = 1;
|
||||
if (asset->LoadChunk(chunkIndex))
|
||||
return ExportAssetResult::CannotLoadData;
|
||||
const auto chunk = asset->GetChunk(chunkIndex);
|
||||
if (!chunk)
|
||||
return ExportAssetResult::CannotLoadData;
|
||||
|
||||
MemoryReadStream stream(chunk->Get(), chunk->Size());
|
||||
FileWriteStream* output = FileWriteStream::Open(path);
|
||||
if (output == nullptr)
|
||||
return ExportAssetResult::Error;
|
||||
DeleteMe<FileWriteStream> outputDeleteMe(output);
|
||||
|
||||
const auto name = StringUtils::GetFileNameWithoutExtension(asset->GetPath()).ToStringAnsi();
|
||||
output->WriteText(StringAnsi::Format("# Exported model {0}\n", name.Get()));
|
||||
|
||||
// Extract all meshes
|
||||
const auto& lod = asset->LODs[lodIndex];
|
||||
int32 vertexStart = 1; // OBJ counts vertices from 1 not from 0
|
||||
byte version = stream.ReadByte();
|
||||
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
|
||||
{
|
||||
auto& mesh = lod.Meshes[meshIndex];
|
||||
|
||||
// #MODEL_DATA_FORMAT_USAGE
|
||||
uint32 vertices;
|
||||
stream.ReadUint32(&vertices);
|
||||
uint32 triangles;
|
||||
stream.ReadUint32(&triangles);
|
||||
uint16 blendShapesCount;
|
||||
stream.ReadUint16(&blendShapesCount);
|
||||
for (int32 blendShapeIndex = 0; blendShapeIndex < blendShapesCount; blendShapeIndex++)
|
||||
{
|
||||
stream.ReadBool();
|
||||
uint32 tmp;
|
||||
stream.ReadUint32(&tmp);
|
||||
stream.ReadUint32(&tmp);
|
||||
uint32 blendShapeVertices;
|
||||
stream.ReadUint32(&blendShapeVertices);
|
||||
stream.Move(blendShapeVertices * sizeof(BlendShapeVertex));
|
||||
}
|
||||
uint32 indicesCount = triangles * 3;
|
||||
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
|
||||
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
||||
if (vertices == 0 || triangles == 0)
|
||||
return ExportAssetResult::Error;
|
||||
auto vb0 = stream.Move<VB0SkinnedElementType>(vertices);
|
||||
auto ib = stream.Move<byte>(indicesCount * ibStride);
|
||||
|
||||
output->WriteText(StringAnsi::Format("# Mesh {0}\n", meshIndex));
|
||||
|
||||
for (uint32 i = 0; i < vertices; i++)
|
||||
{
|
||||
auto v = vb0[i].Position;
|
||||
output->WriteText(StringAnsi::Format("v {0} {1} {2}\n", v.X, v.Y, v.Z));
|
||||
}
|
||||
|
||||
output->WriteChar('\n');
|
||||
|
||||
for (uint32 i = 0; i < vertices; i++)
|
||||
{
|
||||
auto v = vb0[i].TexCoord.ToFloat2();
|
||||
output->WriteText(StringAnsi::Format("vt {0} {1}\n", v.X, v.Y));
|
||||
}
|
||||
|
||||
output->WriteChar('\n');
|
||||
|
||||
for (uint32 i = 0; i < vertices; i++)
|
||||
{
|
||||
auto v = vb0[i].Normal.ToFloat3() * 2.0f - 1.0f;
|
||||
output->WriteText(StringAnsi::Format("vn {0} {1} {2}\n", v.X, v.Y, v.Z));
|
||||
}
|
||||
|
||||
output->WriteChar('\n');
|
||||
|
||||
if (use16BitIndexBuffer)
|
||||
{
|
||||
auto t = (uint16*)ib;
|
||||
for (uint32 i = 0; i < triangles; i++)
|
||||
{
|
||||
auto i0 = vertexStart + *t++;
|
||||
auto i1 = vertexStart + *t++;
|
||||
auto i2 = vertexStart + *t++;
|
||||
output->WriteText(StringAnsi::Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto t = (uint32*)ib;
|
||||
for (uint32 i = 0; i < triangles; i++)
|
||||
{
|
||||
auto i0 = vertexStart + *t++;
|
||||
auto i1 = vertexStart + *t++;
|
||||
auto i2 = vertexStart + *t++;
|
||||
output->WriteText(StringAnsi::Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2));
|
||||
}
|
||||
}
|
||||
|
||||
output->WriteChar('\n');
|
||||
|
||||
vertexStart += vertices;
|
||||
}
|
||||
|
||||
if (output->HasError())
|
||||
return ExportAssetResult::Error;
|
||||
|
||||
return ExportAssetResult::Ok;
|
||||
// The same code, except SkinnedModel::LoadMesh will be used to read Blend Shapes data
|
||||
return ExportModel(context);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user