diff --git a/examples/VerifyData/CDToRenderData/Main.cpp b/examples/VerifyData/CDToRenderData/Main.cpp new file mode 100644 index 00000000..2367bf8f --- /dev/null +++ b/examples/VerifyData/CDToRenderData/Main.cpp @@ -0,0 +1,40 @@ +#include "CDProducer.h" +#include "Framework/Processor.h" +#include "Scene/SceneDatabase.h" +#include "Utilities/MeshUtils.hpp" +#include "Utilities/PerformanceProfiler.h" + +int main(int argc, char** argv) +{ + // argv[0] : exe name + // argv[1] : input file path + if (argc != 2) + { + return 1; + } + + using namespace cdtools; + + PerformanceProfiler profiler("AssetPipeline"); + + const char* pInputFilePath = argv[1]; + + auto pSceneDatabase = std::make_unique(); + CDProducer producer(pInputFilePath); + Processor processor(&producer, nullptr, pSceneDatabase.get()); + processor.Run(); + + for (const auto& mesh : pSceneDatabase->GetMeshes()) + { + auto vb = cd::BuildVertexBufferForStaticMesh(mesh, mesh.GetVertexFormat()); + assert(vb.has_value()); + + auto ibs = cd::BuildIndexBufferesForMesh(mesh); + for (const auto& ib : ibs) + { + assert(ib.has_value()); + } + } + + return 0; +} \ No newline at end of file diff --git a/private/Consumers/FbxConsumer/FbxConsumer.cpp b/private/Consumers/FbxConsumer/FbxConsumer.cpp index 2d520d41..9b04ceaa 100644 --- a/private/Consumers/FbxConsumer/FbxConsumer.cpp +++ b/private/Consumers/FbxConsumer/FbxConsumer.cpp @@ -23,4 +23,19 @@ void FbxConsumer::Execute(const cd::SceneDatabase* pSceneDatabase) m_pFbxConsumerImpl->Execute(pSceneDatabase); } +void FbxConsumer::EnableOption(FbxConsumerOptions option) +{ + m_pFbxConsumerImpl->GetOptions().Enable(option); +} + +void FbxConsumer::DisableOption(FbxConsumerOptions option) +{ + m_pFbxConsumerImpl->GetOptions().Disable(option); +} + +bool FbxConsumer::IsOptionEnabled(FbxConsumerOptions option) const +{ + return m_pFbxConsumerImpl->GetOptions().IsEnabled(option); +} + } \ No newline at end of file diff --git a/private/Consumers/FbxConsumer/FbxConsumerImpl.cpp b/private/Consumers/FbxConsumer/FbxConsumerImpl.cpp index eda5ec36..cc8be704 100644 --- a/private/Consumers/FbxConsumer/FbxConsumerImpl.cpp +++ b/private/Consumers/FbxConsumer/FbxConsumerImpl.cpp @@ -6,24 +6,34 @@ #include #include -// C/C++ #include +#include + +namespace +{ + +void PrintLog(const std::string& msg) +{ + printf("[AssetPipeline][FbxConsumer] %s\n", msg.c_str()); +} + +} namespace cdtools { -FbxConsumerImpl::~FbxConsumerImpl() +FbxConsumerImpl::FbxConsumerImpl(std::string filePath) : + m_filePath(cd::MoveTemp(filePath)) { - if(m_pSDKScene) - { - m_pSDKScene->Destroy(); - } + // Default + m_options.Enable(FbxConsumerOptions::SaveAsASCII); + m_options.Enable(FbxConsumerOptions::ExportMaterial); + m_options.Enable(FbxConsumerOptions::ExportTexture); + m_options.Enable(FbxConsumerOptions::ExportStaticMesh); +} - if(m_pSDKExporter) - { - m_pSDKExporter->Destroy(); - } - +FbxConsumerImpl::~FbxConsumerImpl() +{ if(m_pSDKManager) { m_pSDKManager->Destroy(); @@ -34,92 +44,235 @@ void FbxConsumerImpl::Execute(const cd::SceneDatabase* pSceneDatabase) { // Init settings m_pSDKManager = fbxsdk::FbxManager::Create(); - fbxsdk::FbxIOSettings* pIOSettings = fbxsdk::FbxIOSettings::Create(m_pSDKManager, "IOSROOT"); - pIOSettings->SetBoolProp(EXP_FBX_MODEL, true); - pIOSettings->SetBoolProp(EXP_FBX_MATERIAL, false); - pIOSettings->SetBoolProp(EXP_FBX_TEXTURE, false); - pIOSettings->SetBoolProp(EXP_FBX_EMBEDDED, false); + auto* pIOSettings = fbxsdk::FbxIOSettings::Create(m_pSDKManager, IOSROOT); m_pSDKManager->SetIOSettings(pIOSettings); - // Scene - m_pSDKScene = fbxsdk::FbxScene::Create(m_pSDKManager, pSceneDatabase->GetName()); + fbxsdk::FbxScene* pScene = CreateScene(pSceneDatabase); + assert(pScene); + + // Create a root fbx node. + auto* pRootNode = fbxsdk::FbxNode::Create(pScene, "Root"); + pRootNode->SetShadingMode(fbxsdk::FbxNode::EShadingMode::eTextureShading); + + fbxsdk::FbxVector4 translation(0.0, 0.0, 0.0, 0.0); + fbxsdk::FbxVector4 rotation(0.0, 0.0, 0.0, 0.0); + fbxsdk::FbxVector4 scale(1.0, 1.0, 1.0, 1.0); + pRootNode->LclTranslation.Set(translation); + pRootNode->LclRotation.Set(rotation); + pRootNode->LclScaling.Set(scale); + + pScene->GetRootNode()->AddChild(pRootNode); // Build fbx scene by converting SceneDatabase for (const auto& mesh : pSceneDatabase->GetMeshes()) { - fbxsdk::FbxMesh* pFbxMesh = fbxsdk::FbxMesh::Create(m_pSDKScene, mesh.GetName()); - pFbxMesh->InitControlPoints(mesh.GetVertexCount()); + ExportMesh(pScene, pRootNode, mesh, pSceneDatabase); + } - fbxsdk::FbxGeometryElementNormal* pNormalElement = pFbxMesh->CreateElementNormal(); - assert(pNormalElement && "Failed to create fbx normal element."); - pNormalElement->SetMappingMode(fbxsdk::FbxGeometryElement::eByControlPoint); - pNormalElement->SetReferenceMode(fbxsdk::FbxGeometryElement::eDirect); + if (!ExportFbxFile(pScene)) + { + PrintLog("Error : Failed to export fbx file."); + } +} + +fbxsdk::FbxScene* FbxConsumerImpl::CreateScene(const cd::SceneDatabase* pSceneDatabase) +{ + auto* pScene = fbxsdk::FbxScene::Create(m_pSDKManager, pSceneDatabase->GetName()); + + // Tag source information. + auto* pDocument = fbxsdk::FbxDocumentInfo::Create(m_pSDKManager, "Document"); + pDocument->mTitle = "FBX Exporter"; + pDocument->mSubject = "Export FBX"; + pScene->SetSceneInfo(pDocument); + + // Set AxisSystem and Unit. + auto frontVector = fbxsdk::FbxAxisSystem::eParityOdd; + fbxsdk::FbxAxisSystem axisSystem(fbxsdk::FbxAxisSystem::eYAxis, frontVector, fbxsdk::FbxAxisSystem::eLeftHanded); + auto& globalSettings = pScene->GetGlobalSettings(); + globalSettings.SetAxisSystem(axisSystem); + globalSettings.SetOriginalUpAxis(axisSystem); + globalSettings.SetSystemUnit(fbxsdk::FbxSystemUnit::cm); + globalSettings.SetTimeMode(fbxsdk::FbxTime::eDefaultMode); + + return pScene; +} + +fbxsdk::FbxFileTexture* FbxConsumerImpl::ExportTexture(fbxsdk::FbxScene* pScene, cd::TextureID textureID, const cd::SceneDatabase* pSceneDatabase) +{ + if (!textureID.IsValid() || textureID.Data() >= pSceneDatabase->GetTextureCount()) + { + PrintLog(std::format("Warning : Texture missing at ID : {}", textureID.Data())); + return nullptr; + } + + const cd::Texture& texture = pSceneDatabase->GetTexture(textureID.Data()); + const char* pTextureName = texture.GetName(); + auto* pTexture = static_cast(pScene->GetTexture(pTextureName)); + if (pTexture) + { + return pTexture; + } - fbxsdk::FbxGeometryElementUV* pUVElement = nullptr; - if(mesh.GetVertexUVSetCount() > 0U) + // TODO : support other texture types. + pTexture = fbxsdk::FbxFileTexture::Create(pScene, pTextureName); + pTexture->SetFileName(texture.GetPath()); + pTexture->SetTextureUse(FbxTexture::eStandard); + pTexture->SetMappingType(FbxTexture::eUV); + return pTexture; +} + +fbxsdk::FbxSurfaceMaterial* FbxConsumerImpl::ExportMaterial(fbxsdk::FbxScene* pScene, fbxsdk::FbxNode* pNode, cd::MaterialID materialID, const cd::SceneDatabase* pSceneDatabase) +{ + bool useDefaultMaterial = !materialID.IsValid() || materialID.Data() >= pSceneDatabase->GetMaterialCount(); + if (useDefaultMaterial) + { + constexpr const char* DefaultMaterialName = "Default"; + fbxsdk::FbxSurfaceMaterial* pFbxMaterial = pScene->GetMaterial(DefaultMaterialName); + if (!pFbxMaterial) { - pUVElement = pFbxMesh->CreateElementUV("BaseUV"); - assert(pUVElement && "Failed to create fbx uv element."); - pUVElement->SetMappingMode(fbxsdk::FbxGeometryElement::eByControlPoint); - pUVElement->SetReferenceMode(fbxsdk::FbxGeometryElement::eDirect); + auto* pLambert = fbxsdk::FbxSurfaceLambert::Create(pScene, DefaultMaterialName); + pLambert->Diffuse.Set(fbxsdk::FbxDouble3(0.72)); + pFbxMaterial = pLambert; } - fbxsdk::FbxVector4* pFbxVertices = pFbxMesh->GetControlPoints(); - for(uint32_t vertexIndex = 0U; vertexIndex < mesh.GetVertexCount(); ++vertexIndex) - { - const cd::Point& position = mesh.GetVertexPosition(vertexIndex); - pFbxVertices[vertexIndex].Set(position.x(), position.y(), position.z(), 1.0f); + return pFbxMaterial; + } + + const cd::Material& material = pSceneDatabase->GetMaterial(materialID.Data()); + const char* pMaterialName = material.GetName(); + fbxsdk::FbxSurfaceMaterial* pFbxMaterial = pScene->GetMaterial(pMaterialName); + if (pFbxMaterial) + { + return pFbxMaterial; + } + + pFbxMaterial = fbxsdk::FbxSurfaceLambert::Create(m_pSDKManager, pMaterialName); + + // Fill parameter info. + // TODO. - const cd::Direction& normal = mesh.GetVertexNormal(vertexIndex); - pNormalElement->GetDirectArray().Add(fbxsdk::FbxVector4(normal.x(), normal.y(), normal.z(), 0.0f)); + // Fill texture info. + static std::map MapTextureTypeToFbxPropertyName; + MapTextureTypeToFbxPropertyName[cd::MaterialTextureType::BaseColor] = fbxsdk::FbxSurfaceMaterial::sDiffuse; + MapTextureTypeToFbxPropertyName[cd::MaterialTextureType::Normal] = fbxsdk::FbxSurfaceMaterial::sNormalMap; + MapTextureTypeToFbxPropertyName[cd::MaterialTextureType::Emissive] = fbxsdk::FbxSurfaceMaterial::sEmissive; + for (int textureTypeValue = 0; textureTypeValue < nameof::enum_count(); ++textureTypeValue) + { + auto textureType = static_cast(textureTypeValue); + auto itProperty = MapTextureTypeToFbxPropertyName.find(textureType); + if (itProperty == MapTextureTypeToFbxPropertyName.end()) + { + continue; + } - // Only the first channel now - if (pUVElement) + fbxsdk::FbxProperty textureProperty = pFbxMaterial->FindProperty(itProperty->second); + assert(textureProperty.IsValid()); // Wrong mapping? + if (material.IsTextureSetup(textureType)) + { + fbxsdk::FbxFileTexture* pFileTexture = ExportTexture(pScene, material.GetTextureID(textureType), pSceneDatabase); + if (pFileTexture) { - const cd::UV& uv = mesh.GetVertexUV(0)[vertexIndex]; - pUVElement->GetDirectArray().Add(fbxsdk::FbxVector2(uv.x(), uv.y())); + pFileTexture->ConnectDstProperty(textureProperty); } } + } + + return pFbxMaterial; +} + +void FbxConsumerImpl::ExportMesh(fbxsdk::FbxScene* pScene, fbxsdk::FbxNode* pNode, const cd::Mesh& mesh, const cd::SceneDatabase* pSceneDatabase) +{ + uint32_t vertexCount = mesh.GetVertexCount(); + uint32_t polygonCount = mesh.GetPolygonCount(); + assert(vertexCount > 0U && polygonCount > 0U); + + auto* pFbxMesh = fbxsdk::FbxMesh::Create(pScene, mesh.GetName()); + pNode->SetNodeAttribute(pFbxMesh); + + // Export position. + pFbxMesh->InitControlPoints(vertexCount); + fbxsdk::FbxVector4* pFbxVertices = pFbxMesh->GetControlPoints(); + for (uint32_t vertexIndex = 0U; vertexIndex < vertexCount; ++vertexIndex) + { + const cd::Point& position = mesh.GetVertexPosition(vertexIndex); + pFbxVertices[vertexIndex].Set(position.x(), -position.y(), position.z(), 1.0f); + } + + // Create mesh base layer. + int baseLayerIndex = pFbxMesh->CreateLayer(); + assert(0 == baseLayerIndex); + fbxsdk::FbxLayer* pBaseLayer = pFbxMesh->GetLayer(baseLayerIndex); + + // Create base normal for every vertex which directly maps to control point. + auto* pNormalElement = fbxsdk::FbxLayerElementNormal::Create(pFbxMesh, "BaseNormal"); + pNormalElement->SetMappingMode(fbxsdk::FbxGeometryElement::eByControlPoint); + pNormalElement->SetReferenceMode(fbxsdk::FbxGeometryElement::eDirect); + pBaseLayer->SetNormals(pNormalElement); + + for (uint32_t vertexIndex = 0U; vertexIndex < vertexCount; ++vertexIndex) + { + const cd::Direction& normal = mesh.GetVertexNormal(vertexIndex); + pNormalElement->GetDirectArray().Add(fbxsdk::FbxVector4(normal.x(), normal.y(), normal.z(), 0.0f)); + } + + // Create base color uv. + if (mesh.GetVertexUVSetCount() > 0U) + { + auto* pAlbedoUVElement = fbxsdk::FbxLayerElementUV::Create(pFbxMesh, "Albedo"); + pAlbedoUVElement->SetMappingMode(fbxsdk::FbxGeometryElement::eByControlPoint); + pAlbedoUVElement->SetReferenceMode(fbxsdk::FbxGeometryElement::eDirect); + pBaseLayer->SetUVs(pAlbedoUVElement, fbxsdk::FbxLayerElement::eTextureDiffuse); + + for (uint32_t vertexIndex = 0U; vertexIndex < vertexCount; ++vertexIndex) + { + const cd::UV& uv = mesh.GetVertexUV(0U)[vertexIndex]; + pAlbedoUVElement->GetDirectArray().Add(fbxsdk::FbxVector2(uv.x(), 1.0f - uv.y())); + } + } - pFbxMesh->ReservePolygonCount(mesh.GetPolygonCount()); - for (const auto& polygonGroup : mesh.GetPolygonGroups()) + // Export polygon indices per material. + pFbxMesh->ReservePolygonCount(polygonCount); + for (uint32_t materialIndex = 0U, materialCount = mesh.GetMaterialIDCount(); materialIndex < materialCount; ++materialIndex) + { + cd::MaterialID materialID = mesh.GetMaterialID(materialIndex); + fbxsdk::FbxSurfaceMaterial* pMaterial = ExportMaterial(pScene, pNode, materialID, pSceneDatabase); + assert(pMaterial); // If nullptr, may cause a wrong mapping result. + uint32_t actualMaterialIndex = pNode->AddMaterial(pMaterial); + + const cd::PolygonGroup& polygonGroup = mesh.GetPolygonGroup(materialIndex); + for (const auto& polygon : polygonGroup) { - for (const auto& polygon : polygonGroup) + pFbxMesh->BeginPolygon(actualMaterialIndex); + for (auto vertexID : polygon) { - pFbxMesh->BeginPolygon(-1, -1, -1, false); - for (uint32_t index = 0U; index < polygon.size(); ++index) - { - pFbxMesh->AddPolygon(polygon[index].Data()); - } - pFbxMesh->EndPolygon(); + pFbxMesh->AddPolygon(vertexID.Data()); } + pFbxMesh->EndPolygon(); } - - fbxsdk::FbxNode* pFbxNode = fbxsdk::FbxNode::Create(m_pSDKScene, pFbxMesh->GetName()); - pFbxNode->SetNodeAttribute(pFbxMesh); - pFbxNode->SetShadingMode(fbxsdk::FbxNode::EShadingMode::eWireFrame); - - fbxsdk::FbxVector4 translation(0.0, 0.0, 0.0, 0.0); - fbxsdk::FbxVector4 rotation(0.0, 0.0, 0.0, 0.0); - fbxsdk::FbxVector4 scale(1.0, 1.0, 1.0, 1.0); - pFbxNode->LclTranslation.Set(translation); - pFbxNode->LclRotation.Set(rotation); - pFbxNode->LclScaling.Set(scale); - - m_pSDKScene->GetRootNode()->AddChild(pFbxNode); } +} + +bool FbxConsumerImpl::ExportFbxFile(fbxsdk::FbxScene* pScene) +{ + auto* pExporter = fbxsdk::FbxExporter::Create(m_pSDKManager, ""); - // Export - m_pSDKExporter = fbxsdk::FbxExporter::Create(m_pSDKManager, ""); - int fileFormat = m_pSDKManager->GetIOPluginRegistry()->FindWriterIDByDescription("FBX ascii (*.fbx)"); - if (m_pSDKExporter->Initialize(m_filePath.c_str(), fileFormat)) + int fileFormat; + if (IsOptionEnabled(FbxConsumerOptions::SaveAsASCII)) { - m_pSDKExporter->Export(m_pSDKScene); + fileFormat = m_pSDKManager->GetIOPluginRegistry()->FindWriterIDByDescription("FBX ascii (*.fbx)"); } else { - assert("Failed to export fbx scene"); + fileFormat = m_pSDKManager->GetIOPluginRegistry()->GetNativeWriterFormat(); } + + pExporter->SetFileExportVersion(FBX_2018_00_COMPATIBLE, fbxsdk::FbxSceneRenamer::eNone); + if (!pExporter->Initialize(m_filePath.c_str(), fileFormat)) + { + return false; + } + + return pExporter->Export(pScene); } } \ No newline at end of file diff --git a/private/Consumers/FbxConsumer/FbxConsumerImpl.h b/private/Consumers/FbxConsumer/FbxConsumerImpl.h index 42e99094..555caba1 100644 --- a/private/Consumers/FbxConsumer/FbxConsumerImpl.h +++ b/private/Consumers/FbxConsumer/FbxConsumerImpl.h @@ -1,15 +1,18 @@ #pragma once #include "Base/Template.h" - -#include +#include "Base/BitFlags.h" +#include "Consumers/FbxConsumer/FbxConsumerOptions.h" +#include "Scene/SceneDatabase.h" namespace fbxsdk { -class FbxExporter; +class FbxFileTexture; class FbxManager; +class FbxNode; class FbxScene; +class FbxSurfaceMaterial; } @@ -27,19 +30,29 @@ class FbxConsumerImpl final { public: FbxConsumerImpl() = delete; - explicit FbxConsumerImpl(std::string filePath) : m_filePath(cd::MoveTemp(filePath)) {} + explicit FbxConsumerImpl(std::string filePath); FbxConsumerImpl(const FbxConsumerImpl&) = delete; FbxConsumerImpl& operator=(const FbxConsumerImpl&) = delete; FbxConsumerImpl(FbxConsumerImpl&&) = delete; FbxConsumerImpl& operator=(FbxConsumerImpl&&) = delete; ~FbxConsumerImpl(); + void Execute(const cd::SceneDatabase* pSceneDatabase); + fbxsdk::FbxScene* CreateScene(const cd::SceneDatabase* pSceneDatabase); + fbxsdk::FbxFileTexture* ExportTexture(fbxsdk::FbxScene* pScene, cd::TextureID textureID, const cd::SceneDatabase* pSceneDatabase); + fbxsdk::FbxSurfaceMaterial* ExportMaterial(fbxsdk::FbxScene* pScene, fbxsdk::FbxNode* pNode, cd::MaterialID materialID, const cd::SceneDatabase* pSceneDatabase); + void ExportMesh(fbxsdk::FbxScene* pScene, fbxsdk::FbxNode* pNode, const cd::Mesh& mesh, const cd::SceneDatabase* pSceneDatabase); + bool ExportFbxFile(fbxsdk::FbxScene* pScene); + + cd::BitFlags& GetOptions() { return m_options; } + const cd::BitFlags& GetOptions() const { return m_options; } + bool IsOptionEnabled(FbxConsumerOptions option) const { return m_options.IsEnabled(option); } private: - fbxsdk::FbxManager* m_pSDKManager = nullptr; - fbxsdk::FbxScene* m_pSDKScene = nullptr; - fbxsdk::FbxExporter* m_pSDKExporter = nullptr; + cd::BitFlags m_options; std::string m_filePath; + + fbxsdk::FbxManager* m_pSDKManager = nullptr; }; } \ No newline at end of file diff --git a/private/Producers/FbxProducer/FbxProducerImpl.cpp b/private/Producers/FbxProducer/FbxProducerImpl.cpp index 392d8826..6fcdf009 100644 --- a/private/Producers/FbxProducer/FbxProducerImpl.cpp +++ b/private/Producers/FbxProducer/FbxProducerImpl.cpp @@ -1064,10 +1064,11 @@ cd::MeshID FbxProducerImpl::ParseMesh(const fbxsdk::FbxMesh* pFbxMesh, cd::Scene for (uint32_t polygonVertexIndex = 0U; polygonVertexIndex < polygonVertexCount; ++polygonVertexIndex) { uint32_t controlPointIndex = pFbxMesh->GetPolygonVertex(polygonIndex, polygonVertexIndex); - polygon.push_back(controlPointIndex); - uint32_t vertexInstanceID = polygonVertexBeginIndex + polygonVertexIndex; - mesh.SetVertexInstanceID(controlPointIndex, vertexInstanceID); + mesh.SetVertexIDToInstance(controlPointIndex, vertexInstanceID); + mesh.SetVertexInstanceToID(vertexInstanceID, controlPointIndex); + + polygon.push_back(vertexInstanceID); } // Add polygon to according group split by material. diff --git a/private/Producers/FbxProducer/FbxProducerImpl.h b/private/Producers/FbxProducer/FbxProducerImpl.h index 9ee7ebaf..450be796 100644 --- a/private/Producers/FbxProducer/FbxProducerImpl.h +++ b/private/Producers/FbxProducer/FbxProducerImpl.h @@ -2,9 +2,7 @@ #include "Base/Template.h" #include "Base/BitFlags.h" -#include "Math/Transform.hpp" #include "Producers/FbxProducer/FbxProducerOptions.h" -#include "Scene/MaterialTextureType.h" #include "Scene/ObjectIDGenerator.h" #include @@ -103,9 +101,9 @@ class FbxProducerImpl final void ParseAnimation(fbxsdk::FbxScene* scene, cd::SceneDatabase* pSceneDatabase); private: - std::string m_filePath; cd::BitFlags m_options; - + std::string m_filePath; + fbxsdk::FbxManager* m_pSDKManager = nullptr; std::unique_ptr m_pSDKGeometryConverter; diff --git a/private/Scene/Mesh.cpp b/private/Scene/Mesh.cpp index 2fa7b8cd..4bc55d2b 100644 --- a/private/Scene/Mesh.cpp +++ b/private/Scene/Mesh.cpp @@ -9,14 +9,14 @@ namespace cd PIMPL_SCENE_CLASS(Mesh); PIMPL_SIMPLE_TYPE_APIS(Mesh, ID); -PIMPL_SIMPLE_TYPE_APIS(Mesh, VertexAttributeCount); PIMPL_STRING_TYPE_APIS(Mesh, Name); PIMPL_COMPLEX_TYPE_APIS(Mesh, AABB); PIMPL_COMPLEX_TYPE_APIS(Mesh, VertexFormat); PIMPL_VECTOR_TYPE_APIS(Mesh, MaterialID); PIMPL_VECTOR_TYPE_APIS(Mesh, BlendShapeID); PIMPL_VECTOR_TYPE_APIS(Mesh, SkinID); -PIMPL_VECTOR_TYPE_APIS(Mesh, VertexInstanceID); +PIMPL_VECTOR_TYPE_APIS(Mesh, VertexInstanceToID); +PIMPL_VECTOR_TYPE_APIS(Mesh, VertexIDToInstance); PIMPL_VECTOR_TYPE_APIS(Mesh, VertexPosition); PIMPL_VECTOR_TYPE_APIS(Mesh, VertexNormal); PIMPL_VECTOR_TYPE_APIS(Mesh, VertexTangent); @@ -36,9 +36,9 @@ void Mesh::Init(uint32_t vertexCount) m_pMeshImpl->Init(vertexCount); } -void Mesh::Init(uint32_t vertexPositionCount, uint32_t vertexAttributeCount) +void Mesh::Init(uint32_t vertexCount, uint32_t vertexInstanceCount) { - m_pMeshImpl->Init(vertexPositionCount, vertexAttributeCount); + m_pMeshImpl->Init(vertexCount, vertexInstanceCount); } uint32_t Mesh::GetVertexCount() const @@ -46,6 +46,11 @@ uint32_t Mesh::GetVertexCount() const return m_pMeshImpl->GetVertexCount(); } +uint32_t Mesh::GetVertexAttributeCount() const +{ + return m_pMeshImpl->GetVertexAttributeCount(); +} + uint32_t Mesh::GetPolygonCount() const { return m_pMeshImpl->GetPolygonCount(); diff --git a/private/Scene/MeshImpl.cpp b/private/Scene/MeshImpl.cpp index 50026973..afe72c12 100644 --- a/private/Scene/MeshImpl.cpp +++ b/private/Scene/MeshImpl.cpp @@ -158,61 +158,80 @@ void MeshImpl::FromHalfEdgeMesh(const HalfEdgeMesh& halfEdgeMesh, ConvertStrateg void MeshImpl::Init(uint32_t vertexCount) { SetVertexPositionCount(vertexCount); - SetVertexInstanceIDCount(0U); + SetVertexIDToInstanceCount(0U); + SetVertexInstanceToIDCount(0U); InitVertexAttributes(vertexCount); } -void MeshImpl::Init(uint32_t vertexPositionCount, uint32_t vertexAttributeCount) +void MeshImpl::Init(uint32_t vertexCount, uint32_t vertexInstanceCount) { - SetVertexPositionCount(vertexPositionCount); - SetVertexInstanceIDCount(vertexPositionCount); + if (0U == vertexInstanceCount) + { + Init(vertexCount); + } + else + { + SetVertexPositionCount(vertexCount); + SetVertexIDToInstanceCount(vertexCount); + SetVertexInstanceToIDCount(vertexInstanceCount); - InitVertexAttributes(vertexAttributeCount); + InitVertexAttributes(vertexInstanceCount); + } } -void MeshImpl::InitVertexAttributes(uint32_t vertexAttributeCount) +void MeshImpl::InitVertexAttributes(uint32_t vertexInstanceCount) { - SetVertexAttributeCount(vertexAttributeCount); - SetVertexNormalCount(GetVertexAttributeCount()); - SetVertexTangentCount(GetVertexAttributeCount()); - SetVertexBiTangentCount(GetVertexAttributeCount()); + SetVertexNormalCount(vertexInstanceCount); + SetVertexTangentCount(vertexInstanceCount); + SetVertexBiTangentCount(vertexInstanceCount); for (uint32_t setIndex = 0U; setIndex < GetVertexUVSetCount(); ++setIndex) { - m_vertexUVSets[setIndex].resize(GetVertexAttributeCount()); + m_vertexUVSets[setIndex].resize(vertexInstanceCount); } for (uint32_t setIndex = 0U; setIndex < m_vertexColorSetCount; ++setIndex) { - m_vertexColorSets[setIndex].resize(GetVertexAttributeCount()); + m_vertexColorSets[setIndex].resize(vertexInstanceCount); } } void MeshImpl::ShrinkToFit() { GetVertexPositions().shrink_to_fit(); - GetVertexInstanceIDs().shrink_to_fit(); + GetVertexInstanceToIDs().shrink_to_fit(); + GetVertexIDToInstances().shrink_to_fit(); GetVertexNormals().shrink_to_fit(); GetVertexTangents().shrink_to_fit(); GetVertexBiTangents().shrink_to_fit(); - for (uint32_t setIndex = 0U; setIndex < GetVertexUVSetCount(); ++setIndex) + for (uint32_t setIndex = 0U, setCount = GetVertexUVSetCount(); setIndex < setCount; ++setIndex) { m_vertexUVSets[setIndex].shrink_to_fit(); } - for (uint32_t setIndex = 0U; setIndex < GetVertexColorSetCount(); ++setIndex) + for (uint32_t setIndex = 0U, setCount = GetVertexColorSetCount(); setIndex < setCount; ++setIndex) { m_vertexColorSets[setIndex].shrink_to_fit(); } GetPolygonGroups().shrink_to_fit(); - for (uint32_t polygonGroupIndex = 0U; polygonGroupIndex < GetPolygonGroupCount(); ++polygonGroupIndex) + for (auto& polygonGroup : GetPolygonGroups()) { - GetPolygonGroup(polygonGroupIndex).shrink_to_fit(); + polygonGroup.shrink_to_fit(); + for (auto& polygon : polygonGroup) + { + polygon.shrink_to_fit(); + } } } +uint32_t MeshImpl::GetVertexAttributeCount() const +{ + uint32_t vertexAttributeCount = GetVertexInstanceToIDCount(); + return vertexAttributeCount > 0U ? vertexAttributeCount : GetVertexPositionCount(); +} + uint32_t MeshImpl::GetPolygonCount() const { size_t polygonCount = 0U; diff --git a/private/Scene/MeshImpl.h b/private/Scene/MeshImpl.h index 4d239790..99744223 100644 --- a/private/Scene/MeshImpl.h +++ b/private/Scene/MeshImpl.h @@ -27,14 +27,14 @@ class MeshImpl final DECLARE_SCENE_IMPL_CLASS(Mesh); IMPLEMENT_SIMPLE_TYPE_APIS(Mesh, ID); - IMPLEMENT_SIMPLE_TYPE_APIS(Mesh, VertexAttributeCount); IMPLEMENT_STRING_TYPE_APIS(Mesh, Name); IMPLEMENT_COMPLEX_TYPE_APIS(Mesh, AABB); IMPLEMENT_COMPLEX_TYPE_APIS(Mesh, VertexFormat); IMPLEMENT_VECTOR_TYPE_APIS(Mesh, MaterialID); IMPLEMENT_VECTOR_TYPE_APIS(Mesh, BlendShapeID); IMPLEMENT_VECTOR_TYPE_APIS(Mesh, SkinID); - IMPLEMENT_VECTOR_TYPE_APIS(Mesh, VertexInstanceID); + IMPLEMENT_VECTOR_TYPE_APIS(Mesh, VertexInstanceToID); + IMPLEMENT_VECTOR_TYPE_APIS(Mesh, VertexIDToInstance); IMPLEMENT_VECTOR_TYPE_APIS(Mesh, VertexPosition); IMPLEMENT_VECTOR_TYPE_APIS(Mesh, VertexNormal); IMPLEMENT_VECTOR_TYPE_APIS(Mesh, VertexTangent); @@ -42,11 +42,12 @@ class MeshImpl final IMPLEMENT_VECTOR_TYPE_APIS(Mesh, PolygonGroup); void Init(uint32_t vertexCount); - void Init(uint32_t vertexPositionCount, uint32_t vertexAttributeCount); - void InitVertexAttributes(uint32_t vertexAttributeCount); + void Init(uint32_t vertexCount, uint32_t vertexInstanceCount); + void InitVertexAttributes(uint32_t vertexInstanceCount); void ShrinkToFit(); uint32_t GetVertexCount() const { return GetVertexPositionCount(); } + uint32_t GetVertexAttributeCount() const; uint32_t GetPolygonCount() const; void UpdateAABB(); @@ -76,13 +77,14 @@ class MeshImpl final uint32_t blendShapeCount; uint32_t skinCount; uint32_t vertexCount; + uint32_t vertexInstanceCount; uint32_t vertexUVSetCount; uint32_t vertexColorSetCount; uint32_t polygonGroupCount; inputArchive >> GetName() >> GetID().Data() >> GetAABB() >> materialCount >> blendShapeCount >> skinCount - >> vertexCount >> GetVertexAttributeCount() >> vertexUVSetCount >> vertexColorSetCount + >> vertexCount >> vertexInstanceCount >> vertexUVSetCount >> vertexColorSetCount >> polygonGroupCount; GetVertexFormat() << inputArchive; @@ -96,9 +98,10 @@ class MeshImpl final SetSkinIDCount(skinCount); inputArchive.ImportBuffer(GetSkinIDs().data()); - Init(vertexCount, GetVertexAttributeCount()); + Init(vertexCount, vertexInstanceCount); + inputArchive.ImportBuffer(GetVertexInstanceToIDs().data()); + inputArchive.ImportBuffer(GetVertexIDToInstances().data()); inputArchive.ImportBuffer(GetVertexPositions().data()); - inputArchive.ImportBuffer(GetVertexInstanceIDs().data()); inputArchive.ImportBuffer(GetVertexNormals().data()); inputArchive.ImportBuffer(GetVertexTangents().data()); inputArchive.ImportBuffer(GetVertexBiTangents().data()); @@ -140,15 +143,16 @@ class MeshImpl final { outputArchive << GetName() << GetID().Data() << GetAABB() << GetMaterialIDCount() << GetBlendShapeIDCount() << GetSkinIDCount() - << GetVertexPositionCount() << GetVertexAttributeCount() << GetVertexUVSetCount() << GetVertexColorSetCount() + << GetVertexPositionCount() << GetVertexInstanceToIDCount() << GetVertexUVSetCount() << GetVertexColorSetCount() << GetPolygonGroupCount(); GetVertexFormat() >> outputArchive; outputArchive.ExportBuffer(GetMaterialIDs().data(), GetMaterialIDs().size()); outputArchive.ExportBuffer(GetBlendShapeIDs().data(), GetBlendShapeIDs().size()); outputArchive.ExportBuffer(GetSkinIDs().data(), GetSkinIDs().size()); + outputArchive.ExportBuffer(GetVertexInstanceToIDs().data(), GetVertexInstanceToIDs().size()); + outputArchive.ExportBuffer(GetVertexIDToInstances().data(), GetVertexIDToInstances().size()); outputArchive.ExportBuffer(GetVertexPositions().data(), GetVertexPositions().size()); - outputArchive.ExportBuffer(GetVertexInstanceIDs().data(), GetVertexInstanceIDs().size()); outputArchive.ExportBuffer(GetVertexNormals().data(), GetVertexNormals().size()); outputArchive.ExportBuffer(GetVertexTangents().data(), GetVertexTangents().size()); outputArchive.ExportBuffer(GetVertexBiTangents().data(), GetVertexBiTangents().size()); diff --git a/private/Scene/SceneDatabaseImpl.cpp b/private/Scene/SceneDatabaseImpl.cpp index 5bae53e9..2bd42d37 100644 --- a/private/Scene/SceneDatabaseImpl.cpp +++ b/private/Scene/SceneDatabaseImpl.cpp @@ -197,13 +197,15 @@ void SceneDatabaseImpl::Dump() const for (const auto& mesh : GetMeshes()) { printf("[Mesh %u] Name = %s, VertexCount = %u\n", mesh.GetID().Data(), mesh.GetName(), mesh.GetVertexCount()); + printf("\tPolygonCount = %u, VertexInstanceCount = %u\n", mesh.GetPolygonCount(), mesh.GetVertexInstanceToIDCount()); const auto& polygonGroups = mesh.GetPolygonGroups(); for (uint32_t polygonGroupIndex = 0U; polygonGroupIndex < polygonGroups.size(); ++polygonGroupIndex) { auto& polygonGroup = polygonGroups[polygonGroupIndex]; - auto materialID = mesh.GetMaterialID(polygonGroupIndex); printf("\t[PolygonGroup %u] PolygonCount = %u\n", polygonGroupIndex, static_cast(polygonGroup.size())); - printf("\t\t[Associated Material %u] Name = %s\n", materialID.Data(), GetMaterial(materialID.Data()).GetName()); + + auto materialID = mesh.GetMaterialID(polygonGroupIndex); + printf("\t\t[Associated Material %u] Name = %s\n", materialID.Data(), materialID.IsValid() ? GetMaterial(materialID.Data()).GetName() : ""); if (materialID.IsValid()) { materialDrawMeshPolygonGroupIDs[materialID][mesh.GetID()].push_back(polygonGroupIndex); diff --git a/public/Consumers/FbxConsumer/FbxConsumer.h b/public/Consumers/FbxConsumer/FbxConsumer.h index 5832a6e4..f18ecd51 100644 --- a/public/Consumers/FbxConsumer/FbxConsumer.h +++ b/public/Consumers/FbxConsumer/FbxConsumer.h @@ -1,5 +1,6 @@ #pragma once +#include "Consumers/FbxConsumer/FbxConsumerOptions.h" #include "Framework/IConsumer.h" namespace cd @@ -26,6 +27,10 @@ class TOOL_API FbxConsumer final : public IConsumer virtual ~FbxConsumer(); virtual void Execute(const cd::SceneDatabase* pSceneDatabase) override; + void EnableOption(FbxConsumerOptions option); + void DisableOption(FbxConsumerOptions option); + bool IsOptionEnabled(FbxConsumerOptions option) const; + private: FbxConsumerImpl* m_pFbxConsumerImpl; }; diff --git a/public/Consumers/FbxConsumer/FbxConsumerOptions.h b/public/Consumers/FbxConsumer/FbxConsumerOptions.h new file mode 100644 index 00000000..172a327e --- /dev/null +++ b/public/Consumers/FbxConsumer/FbxConsumerOptions.h @@ -0,0 +1,22 @@ +#pragma once + +namespace cdtools +{ + +enum class FbxConsumerOptions +{ + // File Format + SaveAsASCII, + + // Scene objects + ExportAnimation, + ExportBlendShape, + ExportMaterial, + ExportTexture, + ExportLight, + ExportSkeleton, + ExportSkeletalMesh, + ExportStaticMesh, +}; + +} \ No newline at end of file diff --git a/public/Scene/APITypeTraits.inl b/public/Scene/APITypeTraits.inl index 0f842fb3..2702ecb8 100644 --- a/public/Scene/APITypeTraits.inl +++ b/public/Scene/APITypeTraits.inl @@ -149,7 +149,6 @@ struct MeshTypeTraits { // Simple using ID = cd::MeshID; - using VertexAttributeCount = uint32_t; // String using Name = std::string; @@ -162,8 +161,9 @@ struct MeshTypeTraits using MaterialID = cd::MaterialID; using BlendShapeID = cd::BlendShapeID; using SkinID = cd::SkinID; + using VertexInstanceToID = uint32_t; + using VertexIDToInstance = uint32_t; using VertexPosition = cd::Point; - using VertexInstanceID = uint32_t; using VertexNormal = cd::Direction; using VertexTangent = cd::Direction; using VertexBiTangent = cd::Direction; diff --git a/public/Scene/Mesh.h b/public/Scene/Mesh.h index 49d36c4b..178254d6 100644 --- a/public/Scene/Mesh.h +++ b/public/Scene/Mesh.h @@ -25,14 +25,14 @@ class CORE_API Mesh final DECLARE_SCENE_CLASS(Mesh); EXPORT_SIMPLE_TYPE_APIS(Mesh, ID); - EXPORT_SIMPLE_TYPE_APIS(Mesh, VertexAttributeCount); EXPORT_STRING_TYPE_APIS(Mesh, Name); EXPORT_COMPLEX_TYPE_APIS(Mesh, AABB); EXPORT_COMPLEX_TYPE_APIS(Mesh, VertexFormat); EXPORT_VECTOR_TYPE_APIS(Mesh, MaterialID); EXPORT_VECTOR_TYPE_APIS(Mesh, BlendShapeID); EXPORT_VECTOR_TYPE_APIS(Mesh, SkinID); - EXPORT_VECTOR_TYPE_APIS(Mesh, VertexInstanceID); + EXPORT_VECTOR_TYPE_APIS(Mesh, VertexInstanceToID); + EXPORT_VECTOR_TYPE_APIS(Mesh, VertexIDToInstance); EXPORT_VECTOR_TYPE_APIS(Mesh, VertexPosition); EXPORT_VECTOR_TYPE_APIS(Mesh, VertexNormal); EXPORT_VECTOR_TYPE_APIS(Mesh, VertexTangent); @@ -40,9 +40,10 @@ class CORE_API Mesh final EXPORT_VECTOR_TYPE_APIS(Mesh, PolygonGroup); void Init(uint32_t vertexCount); - void Init(uint32_t vertexPositionCount, uint32_t vertexAttributeCount); + void Init(uint32_t vertexCount, uint32_t vertexInstanceCount); uint32_t GetVertexCount() const; + uint32_t GetVertexAttributeCount() const; uint32_t GetPolygonCount() const; void UpdateAABB(); diff --git a/public/Utilities/MeshUtils.hpp b/public/Utilities/MeshUtils.hpp index 6b3f4fb9..9fc9adca 100644 --- a/public/Utilities/MeshUtils.hpp +++ b/public/Utilities/MeshUtils.hpp @@ -30,7 +30,7 @@ std::optional BuildVertexBufferForStaticMesh(const cd::Mesh& mesh, vbDataSize += dataSize; }; - bool mappingSurfaceAttributes = mesh.GetVertexInstanceIDCount() > 0U; + bool mappingSurfaceAttributes = mesh.GetVertexIDToInstanceCount() > 0U; for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) { if (containsPosition) @@ -42,7 +42,7 @@ std::optional BuildVertexBufferForStaticMesh(const cd::Mesh& mesh, uint32_t vertexInstanceID = vertexIndex; if (mappingSurfaceAttributes) { - vertexInstanceID = mesh.GetVertexInstanceID(vertexIndex); + vertexInstanceID = mesh.GetVertexIDToInstance(vertexIndex); } if (containsNormal) @@ -147,7 +147,7 @@ std::optional BuildVertexBufferForSkeletalMesh(const cd::Mesh& mes vbDataSize += dataSize; }; - bool mappingSurfaceAttributes = mesh.GetVertexInstanceIDCount() > 0U; + bool mappingSurfaceAttributes = mesh.GetVertexIDToInstanceCount() > 0U; for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) { if (containsPosition) @@ -159,7 +159,7 @@ std::optional BuildVertexBufferForSkeletalMesh(const cd::Mesh& mes uint32_t vertexInstanceID = vertexIndex; if (mappingSurfaceAttributes) { - vertexInstanceID = mesh.GetVertexInstanceID(vertexIndex); + vertexInstanceID = mesh.GetVertexIDToInstance(vertexIndex); } if (containsNormal) @@ -246,24 +246,34 @@ std::optional BuildIndexBufferesForPolygonGroup(const cd::Mesh& mes ibDataSize += dataSize; }; + bool mappingInstanceToID = mesh.GetVertexInstanceToIDCount() > 0U; for (const auto& polygon : mesh.GetPolygonGroup(polygonGroupIndex)) { - if (useU16Index) + for (auto instanceID : polygon) { - // cd::Mesh always uses uint32_t to store index so it is not convenient to copy servals elements at the same time. - for (auto vertexID : polygon) + uint32_t vertexIndex; + if (mappingInstanceToID) + { + vertexIndex = mesh.GetVertexInstanceToID(instanceID.Data()); + } + else + { + vertexIndex = instanceID.Data(); + } + + if (useU16Index) + { + // Endian safe. Can optimize for little endian to avoid cast. + uint16_t vertexIndex16 = static_cast(vertexIndex); + FillIndexBuffer(&vertexIndex16, indexTypeSize); + } + else { - uint16_t vertexIndex = static_cast(vertexID.Data()); FillIndexBuffer(&vertexIndex, indexTypeSize); } } - else - { - FillIndexBuffer(polygon.data(), static_cast(polygon.size() * indexTypeSize)); - } } - return indexBuffer; }