580 lines
18 KiB
C++
580 lines
18 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Element2StaticMesh.h"
|
|
#include "Synchronizer.h"
|
|
#include "DatasmithHashTools.h"
|
|
#include "Utils/3DElement2String.h"
|
|
|
|
#include "ConvexPolygon.hpp"
|
|
#include "ModelElement.hpp"
|
|
|
|
#undef TicksPerSecond
|
|
|
|
#include "DatasmithSceneFactory.h"
|
|
#include "DatasmithMesh.h"
|
|
#include "DatasmithMeshExporter.h"
|
|
#include "DatasmithSceneExporter.h"
|
|
#include "Paths.h"
|
|
|
|
BEGIN_NAMESPACE_UE_AC
|
|
|
|
inline const Geometry::Point3D& Vertex2Point3D(const ModelerAPI::Vertex& inV)
|
|
{
|
|
return reinterpret_cast< const Geometry::Point3D& >(inV);
|
|
}
|
|
|
|
inline const Geometry::Vector3D& Vertor2Vector3D(const ModelerAPI::Vector& inV)
|
|
{
|
|
return reinterpret_cast< const Geometry::Vector3D& >(inV);
|
|
}
|
|
|
|
// Vertex value and used flag or mootools index
|
|
class FElement2StaticMesh::FVertex
|
|
{
|
|
public:
|
|
enum
|
|
{
|
|
kInvalidVertex = -1
|
|
};
|
|
|
|
// Constructor
|
|
FVertex()
|
|
: Used(false)
|
|
, Index(kInvalidVertex)
|
|
{
|
|
}
|
|
|
|
ModelerAPI::Vertex LocalVertex; // The vertex in local coordinates
|
|
ModelerAPI::Vertex WorldVertex; // The vertex in world coordinates
|
|
bool Used; // Used flag
|
|
int Index; // New index
|
|
};
|
|
|
|
// Constructor
|
|
FElement2StaticMesh::FElement2StaticMesh(const FSyncContext& InSyncContext)
|
|
: SyncContext(InSyncContext)
|
|
, bSomeHasTextures(false)
|
|
, BugsCount(0)
|
|
, GeometryShift(0, 0, 0)
|
|
{
|
|
}
|
|
|
|
FElement2StaticMesh::~FElement2StaticMesh() {}
|
|
|
|
// Compute name of mesh element
|
|
FString FElement2StaticMesh::ComputeMeshElementName(const TCHAR* InMeshFileHash)
|
|
{
|
|
FDatasmithHash HashName;
|
|
HashName.Update(InMeshFileHash);
|
|
for (VecMaterialSyncData::SizeType i = 0; i < GlobalMaterialsUsed.Num(); ++i)
|
|
{
|
|
HashName.Update(GlobalMaterialsUsed[i]->GetDatasmithId());
|
|
}
|
|
return LexToString(HashName.GetHashValue());
|
|
}
|
|
|
|
#if DUMP_GEOMETRY
|
|
|
|
// Return a mesh dump
|
|
utf8_string FElement2StaticMesh::MeshAsString(const FDatasmithMesh& Mesh)
|
|
{
|
|
utf8_string Dump(Utf8StringFormat("Mesh Name = %s\n", TCHAR_TO_UTF8(Mesh.GetName())));
|
|
|
|
int32 VerticesCount = Mesh.GetVerticesCount();
|
|
Dump += Utf8StringFormat("\tVertices Count = %d\n", VerticesCount);
|
|
for (int32 IdxVertice = 0; IdxVertice < VerticesCount; ++IdxVertice)
|
|
{
|
|
FVector3f Vertex = Mesh.GetVertex(IdxVertice);
|
|
Dump += Utf8StringFormat("\t\tVertice[%d] = {%f, %f, %f}\n", IdxVertice, Vertex.X, Vertex.Y, Vertex.Z);
|
|
}
|
|
|
|
int32 UVChannelCount = Mesh.GetUVChannelsCount();
|
|
Dump += Utf8StringFormat("\tUV Channels Count = %d\n", UVChannelCount);
|
|
for (int32 IdxChannel = 0; IdxChannel < UVChannelCount; ++IdxChannel)
|
|
{
|
|
int32 UVCount = Mesh.GetUVCount(IdxChannel);
|
|
Dump += Utf8StringFormat("\t\tChannels[%d] Count = %d\n", IdxChannel, UVCount);
|
|
for (int32 IdxUV = 0; IdxUV < UVCount; ++IdxUV)
|
|
{
|
|
FVector2D UV = Mesh.GetUV(IdxChannel, IdxUV);
|
|
Dump += Utf8StringFormat("\t\t\tChannels[%d][%d] UV = {%f, %f}\n", IdxChannel, IdxUV, UV.X, UV.Y);
|
|
}
|
|
}
|
|
|
|
int32 FacesCount = Mesh.GetFacesCount();
|
|
Dump += Utf8StringFormat("\tFaces Count = %d\n", FacesCount);
|
|
for (int32 IdxFace = 0; IdxFace < FacesCount; ++IdxFace)
|
|
{
|
|
int32 Vertex1;
|
|
int32 Vertex2;
|
|
int32 Vertex3;
|
|
int32 MaterialId;
|
|
Mesh.GetFace(IdxFace, Vertex1, Vertex2, Vertex3, MaterialId);
|
|
Dump += Utf8StringFormat("\t\tVertex[%d] = {%d, %d, %d} Mat = %d\n", IdxFace, Vertex1, Vertex2, Vertex3,
|
|
MaterialId);
|
|
FVector3f Point1 = Mesh.GetVertex(Vertex1);
|
|
FVector3f Point2 = Mesh.GetVertex(Vertex2);
|
|
FVector3f Point3 = Mesh.GetVertex(Vertex3);
|
|
Dump += Utf8StringFormat("\t\t\t\t{{%f, %f, %f}, {%f, %f, %f}, {%f, %f, %f}}\n", Point1.X, Point1.Y, Point1.Z,
|
|
Point2.X, Point2.Y, Point2.Z, Point3.X, Point3.Y, Point3.Z);
|
|
|
|
for (int32 IdxComponent = 0; IdxComponent < 3; IdxComponent++)
|
|
{
|
|
FVector3f Normal = Mesh.GetNormal(IdxFace * 3 + IdxComponent);
|
|
Dump += Utf8StringFormat("\t\t\tNormal[%d][%d] = {%f, %f, %f}\n", IdxFace, IdxComponent, Normal.X, Normal.Y,
|
|
Normal.Z);
|
|
}
|
|
|
|
for (int32 IdxChannel = 0; IdxChannel < UVChannelCount; ++IdxChannel)
|
|
{
|
|
Mesh.GetFaceUV(IdxFace, IdxChannel, Vertex1, Vertex2, Vertex3);
|
|
FVector2D UV1 = Mesh.GetUV(IdxChannel, Vertex1);
|
|
FVector2D UV2 = Mesh.GetUV(IdxChannel, Vertex2);
|
|
FVector2D UV3 = Mesh.GetUV(IdxChannel, Vertex3);
|
|
Dump += Utf8StringFormat("\t\t\tUV[%d][%d] = {%d, %d, %d} === {{%f, %f}, {%f, %f}, {%f, %f}}\n", IdxFace,
|
|
IdxChannel, Vertex1, Vertex2, Vertex3, UV1.X, UV1.Y, UV2.X, UV2.Y, UV3.X, UV3.Y);
|
|
}
|
|
}
|
|
|
|
return Dump;
|
|
}
|
|
|
|
// Dump a mesh
|
|
void FElement2StaticMesh::DumpMesh(const FDatasmithMesh& Mesh)
|
|
{
|
|
static bool DoDump = false;
|
|
if (DoDump)
|
|
{
|
|
UE_AC_TraceF("%s", MeshAsString(Mesh).c_str());
|
|
}
|
|
}
|
|
|
|
// Return a mesh element dump
|
|
utf8_string FElement2StaticMesh::MeshElementAsString(const IDatasmithMeshElement& Mesh)
|
|
{
|
|
utf8_string Dump;
|
|
|
|
Dump += Utf8StringFormat("Mesh \"%s\"\n", TCHAR_TO_UTF8(Mesh.GetName()));
|
|
Dump += Utf8StringFormat("\tLabel = \"%s\"\n", TCHAR_TO_UTF8(Mesh.GetLabel()));
|
|
Dump += Utf8StringFormat("\tFile = \"%s\"\n", TCHAR_TO_UTF8(Mesh.GetFile()));
|
|
const FVector3f Dim = Mesh.GetDimensions();
|
|
Dump += Utf8StringFormat("\tDimensions = {%f, %f, %f}\n", Dim.X, Dim.Y, Dim.Z);
|
|
Dump += Utf8StringFormat("\tArea = %f\n", Mesh.GetArea());
|
|
Dump +=
|
|
Utf8StringFormat("\tWidth = %f, Height = %f, Depth = %f\n", Mesh.GetWidth(), Mesh.GetHeight(), Mesh.GetDepth());
|
|
Dump += Utf8StringFormat("\tMaterial Slot Count = %d\n", Mesh.GetMaterialSlotCount());
|
|
|
|
return Dump;
|
|
}
|
|
|
|
// Dump a mesh element
|
|
void FElement2StaticMesh::DumpMeshElement(const IDatasmithMeshElement& Mesh)
|
|
{
|
|
static bool DoDump = false;
|
|
if (DoDump)
|
|
{
|
|
UE_AC_TraceF("%s", MeshElementAsString(Mesh).c_str());
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
// Create a triangle for polygon vertex ≈ new Triangle(first, previous, last)
|
|
void FElement2StaticMesh::AddVertex(GS::Int32 InBodyVertex, const Geometry::Vector3D& VertexNormal)
|
|
{
|
|
UE_AC_Assert(InBodyVertex > 0);
|
|
int ObjectVertex = InBodyVertex + StartVertex - 1;
|
|
|
|
// Get the vertex value
|
|
FVertex& vertex = Vertices[ObjectVertex];
|
|
if (!vertex.Used)
|
|
{
|
|
// Not already used, get value from body
|
|
CurrentBody.GetVertex(InBodyVertex, &vertex.LocalVertex, ModelerAPI::CoordinateSystem::ElemLocal);
|
|
|
|
vertex.LocalVertex.x = vertex.LocalVertex.x + GeometryShift.x;
|
|
vertex.LocalVertex.y = vertex.LocalVertex.y + GeometryShift.y;
|
|
vertex.LocalVertex.z = vertex.LocalVertex.z + GeometryShift.z;
|
|
|
|
vertex.LocalVertex.x *= SyncContext.ScaleLength;
|
|
vertex.LocalVertex.y *= SyncContext.ScaleLength;
|
|
vertex.LocalVertex.z *= SyncContext.ScaleLength;
|
|
|
|
CurrentBody.GetVertex(InBodyVertex, &vertex.WorldVertex, ModelerAPI::CoordinateSystem::World);
|
|
vertex.Used = true;
|
|
}
|
|
|
|
// Get vertex texture coordinate index
|
|
int ObjectUV = FTriangle::kInvalidIndex;
|
|
const FMaterialsDatabase::FMaterialSyncData& MatData = *GlobalMaterialsUsed[CurrentTriangle.LocalMatID];
|
|
bool bAlwaysSendUV = true;
|
|
if (MatData.bHasTexture || bAlwaysSendUV)
|
|
{
|
|
// Get texture coordinate
|
|
ModelerAPI::TextureCoordinate AcUV;
|
|
try
|
|
{
|
|
CurrentPolygon.GetTextureCoordinate(&vertex.WorldVertex, &AcUV);
|
|
}
|
|
catch (...)
|
|
{
|
|
UE_AC_STAT(++SyncContext.Stats.TotalBugsCount);
|
|
if (BugsCount++ == 0)
|
|
{
|
|
UE_AC_DebugF("FElement2StaticMesh::AddVertex - Exception in GetTextureCoordinate\n");
|
|
}
|
|
|
|
AcUV.u = 0;
|
|
AcUV.v = 0;
|
|
}
|
|
|
|
// Rotate texture and size the texture (ideally build a material that implement this functionality)
|
|
FTextureCoordinate UV;
|
|
UV.u = AcUV.u; //(MatData.CosAngle * AcUV.u - MatData.SinAngle * AcUV.v) * MatData.InvXSize;
|
|
UV.v = -AcUV.v; //(-MatData.SinAngle * AcUV.u - MatData.CosAngle * AcUV.v) * MatData.InvYSize;
|
|
#if PIVOT_0_5_0_5
|
|
UV.u += 0.5;
|
|
UV.v += 0.5;
|
|
#endif
|
|
// Convert Vertex coordinate to texture coordinate.
|
|
int* UVFound = UVs.Find(UV);
|
|
if (UVFound == nullptr)
|
|
{
|
|
ObjectUV = (int)UVs.Num();
|
|
UVs.Add(UV, ObjectUV);
|
|
bSomeHasTextures = true;
|
|
}
|
|
else
|
|
{
|
|
ObjectUV = *UVFound;
|
|
}
|
|
}
|
|
|
|
FVector3f CurrentNormal(float(VertexNormal.x), -float(VertexNormal.y), float(VertexNormal.z));
|
|
|
|
// Create triangles
|
|
if (VertexCount == 0)
|
|
{
|
|
// First polygon vertex is used for all triangles
|
|
CurrentTriangle.V0 = ObjectVertex;
|
|
CurrentTriangle.UV0 = ObjectUV;
|
|
CurrentTriangle.Normals[0] = CurrentNormal;
|
|
}
|
|
else
|
|
{
|
|
if (VertexCount != 1)
|
|
{
|
|
// Third and following vertex
|
|
CurrentTriangle.V2 = ObjectVertex;
|
|
CurrentTriangle.UV2 = ObjectUV;
|
|
CurrentTriangle.Normals[2] = CurrentNormal;
|
|
#if defined(DEBUG)
|
|
if (CurrentTriangle.V0 == CurrentTriangle.V1 || CurrentTriangle.V0 == CurrentTriangle.V2 ||
|
|
CurrentTriangle.V1 == CurrentTriangle.V2)
|
|
{
|
|
static bool bVertexConfusedSignaled = false;
|
|
if (!bVertexConfusedSignaled)
|
|
{
|
|
bVertexConfusedSignaled = true;
|
|
UE_AC_DebugF("FElement2StaticMesh::AddVertex - Triangle have 2 vertex confused\n");
|
|
}
|
|
}
|
|
if (CurrentTriangle.UV0 == CurrentTriangle.UV1 || CurrentTriangle.UV0 == CurrentTriangle.UV2 ||
|
|
CurrentTriangle.UV1 == CurrentTriangle.UV2)
|
|
{
|
|
static bool bUVConfusedSignaled = false;
|
|
if (!bUVConfusedSignaled)
|
|
{
|
|
bUVConfusedSignaled = true;
|
|
UE_AC_DebugF("FElement2StaticMesh::AddVertex - Triangle have 2 UV confused\n");
|
|
}
|
|
}
|
|
#endif
|
|
Triangles.Add(CurrentTriangle);
|
|
}
|
|
CurrentTriangle.V1 = ObjectVertex;
|
|
CurrentTriangle.UV1 = ObjectUV;
|
|
CurrentTriangle.Normals[1] = CurrentNormal;
|
|
}
|
|
VertexCount++;
|
|
}
|
|
|
|
// Set the material for the current polygon
|
|
void FElement2StaticMesh::InitPolygonMaterial()
|
|
{
|
|
CurrentPolygon.GetMaterialIndex(MaterialIndex);
|
|
GS::Int32 MaterialIdx = MaterialIndex.GetOriginalModelerIndex();
|
|
CurrentPolygon.GetPolygonTextureIndex(TextureIndex);
|
|
GS::Int32 TextureIdx = TextureIndex.GetOriginalModelerIndex();
|
|
|
|
const FMaterialsDatabase::FMaterialSyncData* CurrentMaterial = &SyncContext.GetMaterialsDatabase().GetMaterial(
|
|
SyncContext, MaterialIdx, TextureIdx, bIsSurfaceBody ? kDoubleSide : kSingleSide);
|
|
|
|
// Performance heuristic, we presume reuse of previous one
|
|
if (LocalMaterialIndex >= GlobalMaterialsUsed.Num() || GlobalMaterialsUsed[LocalMaterialIndex] != CurrentMaterial)
|
|
{
|
|
for (LocalMaterialIndex = GlobalMaterialsUsed.Num();;)
|
|
{
|
|
if (LocalMaterialIndex == 0)
|
|
{
|
|
// Not found, add it to the vector and quit the loop
|
|
LocalMaterialIndex = GlobalMaterialsUsed.Num();
|
|
GlobalMaterialsUsed.Add(CurrentMaterial);
|
|
break;
|
|
}
|
|
if (GlobalMaterialsUsed[--LocalMaterialIndex] == CurrentMaterial)
|
|
{
|
|
// found, quit the loop
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
UE_AC_Assert(LocalMaterialIndex < GlobalMaterialsUsed.Num() ||
|
|
GlobalMaterialsUsed[LocalMaterialIndex] == CurrentMaterial);
|
|
CurrentTriangle.LocalMatID = (int)LocalMaterialIndex;
|
|
}
|
|
|
|
void FElement2StaticMesh::AddElementGeometry(const ModelerAPI::Element& InModelElement,
|
|
const Geometry::Vector3D& InGeometryShift)
|
|
{
|
|
#if 0
|
|
UE_AC_TraceF("Element\n%s\n", F3DElement2String::Element2String(InModelElement).c_str());
|
|
#endif
|
|
#if 0
|
|
static GS::Guid BreakGuid("0A0BFAC4-B753-1144-A733-1E73939B3ECB");
|
|
if (InModelElement.GetElemGuid() == BreakGuid)
|
|
{
|
|
UE_AC_DebugF("FElement2StaticMesh::AddElementGeometry - Break element found\n");
|
|
}
|
|
#endif
|
|
GeometryShift = InGeometryShift;
|
|
|
|
// Collect geometry from element's bodies
|
|
GS::Int32 NbBodies = InModelElement.GetTessellatedBodyCount();
|
|
UE_AC_STAT(SyncContext.Stats.BodiesStats.Inc(NbBodies));
|
|
|
|
for (GS::Int32 IndexBody = 1; IndexBody <= NbBodies; IndexBody++)
|
|
{
|
|
InModelElement.GetTessellatedBody(IndexBody, &CurrentBody);
|
|
bIsSurfaceBody = CurrentBody.IsSurfaceBody();
|
|
GS::Int32 NbVertices = CurrentBody.GetVertexCount();
|
|
StartVertex = (int)Vertices.Num();
|
|
Vertices.AddZeroed(NbVertices); // Set space for bodies vertex
|
|
|
|
// Collect triangles from body's polygon
|
|
GS::Int32 NbPolygons = CurrentBody.GetPolygonCount();
|
|
UE_AC_STAT(SyncContext.Stats.PolygonsStats.Inc(NbPolygons));
|
|
|
|
for (GS::Int32 IndexPolygon = 1; IndexPolygon <= NbPolygons; IndexPolygon++)
|
|
{
|
|
CurrentBody.GetPolygon(IndexPolygon, &CurrentPolygon);
|
|
if (!CurrentPolygon.IsInvisible())
|
|
{
|
|
// Cutting plan create invisible polygons contour where it cut. So, we must not export theses polygons
|
|
InitPolygonMaterial();
|
|
if (CurrentPolygon.IsComplex())
|
|
{
|
|
UE_AC_STAT(++SyncContext.Stats.PolygonsComplex);
|
|
// For a complex polygon we decompose it in convex polygons
|
|
GS::Int32 NbPolys = CurrentPolygon.GetConvexPolygonCount();
|
|
for (GS::Int32 i = 1; i <= NbPolys; i++)
|
|
{
|
|
// For all convex polygons
|
|
UE_AC_STAT(++SyncContext.Stats.PolygonsConvex);
|
|
ModelerAPI::ConvexPolygon ConvexPolygon;
|
|
CurrentPolygon.GetConvexPolygon(i, &ConvexPolygon);
|
|
GS::Int32 NbVerts = ConvexPolygon.GetVertexCount();
|
|
VertexCount = 0; // Start polygon triangulation
|
|
for (GS::Int32 j = 1; j <= NbVerts; j++)
|
|
{
|
|
AddVertex(ConvexPolygon.GetVertexIndex(j),
|
|
Vertor2Vector3D(ConvexPolygon.GetNormalVectorByVertex(
|
|
j, ModelerAPI::CoordinateSystem::ElemLocal)));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VertexCount = 0; // Start polygon triangulation
|
|
GS::Int32 NbEdges = CurrentPolygon.GetEdgeCount();
|
|
for (GS::Int32 IndexPedg = 1; IndexPedg <= NbEdges; IndexPedg++)
|
|
{
|
|
AddVertex(CurrentPolygon.GetVertexIndex(IndexPedg),
|
|
Vertor2Vector3D(CurrentPolygon.GetNormalVectorByVertex(
|
|
IndexPedg, ModelerAPI::CoordinateSystem::ElemLocal)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!HasGeometry())
|
|
{
|
|
UE_AC_VerboseF("FElement2StaticMesh::AddElementGeometry - No material used for element %s\n",
|
|
InModelElement.GetElemGuid().ToUniString().ToUtf8());
|
|
}
|
|
}
|
|
|
|
// Validate Vertice
|
|
inline void ValidateVertice(int32 InIndex, const FElement2StaticMesh::VecVertices& InVertices, int32 InVertexUsedCount)
|
|
{
|
|
UE_AC_Assert(InIndex >= 0 && InIndex < InVertices.Num() && InVertices[InIndex].Index >= 0 &&
|
|
InVertices[InIndex].Index < InVertexUsedCount);
|
|
}
|
|
|
|
// Fill 3d maesh data from collected goemetry
|
|
void FElement2StaticMesh::FillMesh(FDatasmithMesh* OutMesh)
|
|
{
|
|
// Count used vertices and set new index value
|
|
int32 VertexUsedCount = 0;
|
|
VecVertices::SizeType NbVertices = Vertices.Num();
|
|
VecVertices::SizeType IndexVertex;
|
|
for (IndexVertex = 0; IndexVertex < NbVertices; IndexVertex++)
|
|
{
|
|
FVertex& vertex = Vertices[IndexVertex];
|
|
if (vertex.Used)
|
|
{
|
|
vertex.Index = VertexUsedCount++;
|
|
}
|
|
else
|
|
{
|
|
vertex.Index = FVertex::kInvalidVertex;
|
|
}
|
|
}
|
|
|
|
// Copy all used vertices
|
|
OutMesh->SetVerticesCount(VertexUsedCount);
|
|
UE_AC_STAT(SyncContext.Stats.TotalTrianglePts += VertexUsedCount);
|
|
for (IndexVertex = 0; IndexVertex < NbVertices; IndexVertex++)
|
|
{
|
|
FVertex& vertex = Vertices[IndexVertex];
|
|
if (vertex.Index != FVertex::kInvalidVertex)
|
|
{
|
|
OutMesh->SetVertex(vertex.Index, (float)vertex.LocalVertex.x, -(float)vertex.LocalVertex.y,
|
|
(float)vertex.LocalVertex.z);
|
|
}
|
|
}
|
|
|
|
// Create a UV channel and fill it
|
|
int32 UVChannel = OutMesh->GetUVChannelsCount();
|
|
UE_AC_Assert(UVChannel == 0); // Must be 0
|
|
OutMesh->AddUVChannel();
|
|
OutMesh->SetUVCount(UVChannel, int32(UVs.Num()));
|
|
UE_AC_STAT(SyncContext.Stats.TotalUVPts += int32(UVs.Num()));
|
|
for (const TPair< FTextureCoordinate, int >& ItUV : UVs)
|
|
{
|
|
OutMesh->SetUV(UVChannel, ItUV.Value, ItUV.Key.u, ItUV.Key.v);
|
|
}
|
|
|
|
// Count valid triangles
|
|
int32 TrianglesValidCount = 0;
|
|
VecTriangles::SizeType NbTriangles = Triangles.Num();
|
|
VecTriangles::SizeType IndexTriangle;
|
|
for (IndexTriangle = 0; IndexTriangle < NbTriangles; IndexTriangle++)
|
|
{
|
|
if (Triangles[IndexTriangle].IsValid())
|
|
{
|
|
TrianglesValidCount++;
|
|
}
|
|
}
|
|
|
|
// Copy triangles to face, normals and UV
|
|
UE_AC_STAT(SyncContext.Stats.TotalTriangles += TrianglesValidCount);
|
|
OutMesh->SetFacesCount(TrianglesValidCount);
|
|
int32 IndexFace = 0;
|
|
for (IndexTriangle = 0; IndexTriangle < NbTriangles; IndexTriangle++)
|
|
{
|
|
const FTriangle& triangle = Triangles[IndexTriangle];
|
|
if (triangle.IsValid())
|
|
{
|
|
#if 0
|
|
ValidateVertice(triangle.V0, Vertices, VertexUsedCount);
|
|
ValidateVertice(triangle.V1, Vertices, VertexUsedCount);
|
|
ValidateVertice(triangle.V2, Vertices, VertexUsedCount);
|
|
#endif
|
|
OutMesh->SetFace(IndexFace, Vertices[triangle.V0].Index, Vertices[triangle.V1].Index,
|
|
Vertices[triangle.V2].Index, triangle.LocalMatID);
|
|
|
|
for (int32 IndexComponent = 0; IndexComponent < 3; IndexComponent++)
|
|
{
|
|
const FVector3f& Normal = triangle.Normals[IndexComponent];
|
|
OutMesh->SetNormal(IndexFace * 3 + IndexComponent, Normal.X, Normal.Y, Normal.Z);
|
|
}
|
|
|
|
OutMesh->SetFaceUV(IndexFace, UVChannel, triangle.UV0, triangle.UV1, triangle.UV2);
|
|
|
|
IndexFace++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create a datasmith mesh element
|
|
TSharedPtr< IDatasmithMeshElement > FElement2StaticMesh::CreateMesh()
|
|
{
|
|
TSharedPtr< IDatasmithMeshElement > MeshElement;
|
|
|
|
FDatasmithMesh Mesh;
|
|
|
|
FillMesh(&Mesh);
|
|
|
|
FDatasmithHash MeshHasher;
|
|
MeshHasher.ComputeDatasmithMeshHash(Mesh);
|
|
FMD5Hash MeshHash = MeshHasher.GetHashValue();
|
|
Mesh.SetName(*LexToString(MeshHash));
|
|
|
|
const FMeshDimensions* Dimensions = SyncContext.GetSyncDatabase().GetMeshIndexor().FindMesh(Mesh.GetName());
|
|
|
|
FString MeshElementName = ComputeMeshElementName(Mesh.GetName());
|
|
|
|
#if DUMP_GEOMETRY
|
|
DumpMesh(Mesh);
|
|
#endif
|
|
|
|
// Define output path
|
|
TCHAR SubDir1[2] = {Mesh.GetName()[0], 0};
|
|
TCHAR SubDir2[2] = {Mesh.GetName()[1], 0};
|
|
FString OutputPath(FPaths::Combine(SyncContext.GetSyncDatabase().GetAssetsFolderPath(), SubDir1, SubDir2));
|
|
|
|
// If mesh already exist ?
|
|
FString FullPath(FPaths::Combine(OutputPath, FPaths::SetExtension(Mesh.GetName(), TEXT("udsmesh"))));
|
|
if (Dimensions == nullptr || !FPaths::FileExists(FullPath))
|
|
{
|
|
// Create a new mesh file
|
|
UE_AC_STAT(SyncContext.Stats.TotalMeshesCreated++);
|
|
FDatasmithMeshExporter MeshExporter;
|
|
MeshElement =
|
|
MeshExporter.ExportToUObject(*OutputPath, Mesh.GetName(), Mesh, nullptr, EDSExportLightmapUV::Never);
|
|
if (MeshElement.IsValid())
|
|
{
|
|
MeshElement->SetName(*MeshElementName);
|
|
MeshElement->SetFileHash(MeshHash);
|
|
SyncContext.GetSyncDatabase().GetMeshIndexor().AddMesh(*MeshElement);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Reuse the previous mesh file
|
|
UE_AC_STAT(SyncContext.Stats.TotalMeshesReused++);
|
|
MeshElement = FDatasmithSceneFactory::CreateMesh(*MeshElementName);
|
|
MeshElement->SetFile(*FullPath);
|
|
MeshElement->SetFileHash(MeshHash);
|
|
MeshElement->SetDimensions(Dimensions->Area, Dimensions->Width, Dimensions->Height, Dimensions->Depth);
|
|
}
|
|
|
|
if (MeshElement.IsValid())
|
|
{
|
|
for (VecMaterialSyncData::SizeType i = 0; i < GlobalMaterialsUsed.Num(); ++i)
|
|
{
|
|
MeshElement->SetMaterial(*GlobalMaterialsUsed[i]->GetDatasmithId(), (int32)i);
|
|
}
|
|
|
|
#if DUMP_GEOMETRY
|
|
DumpMeshElement(*MeshElement);
|
|
#endif
|
|
}
|
|
|
|
return MeshElement;
|
|
}
|
|
|
|
END_NAMESPACE_UE_AC
|