aboutsummaryrefslogtreecommitdiff
path: root/sdk/extensions/exporter/source
diff options
context:
space:
mode:
Diffstat (limited to 'sdk/extensions/exporter/source')
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporter.cpp116
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.cpp1272
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.h446
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.cpp416
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.h136
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.cpp2880
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.h286
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterJsonCollision.cpp244
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterObjReader.cpp322
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterObjReader.h250
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.cpp530
-rwxr-xr-x[-rw-r--r--]sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.h158
12 files changed, 3543 insertions, 3513 deletions
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporter.cpp b/sdk/extensions/exporter/source/NvBlastExtExporter.cpp
index 405c4a4..790d408 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporter.cpp
+++ b/sdk/extensions/exporter/source/NvBlastExtExporter.cpp
@@ -1,58 +1,58 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "NvBlastExtExporter.h"
-#include "NvBlastExtExporterFbxReader.h"
-#include "NvBlastExtExporterObjReader.h"
-#include "NvBlastExtExporterFbxWriter.h"
-#include "NvBlastExtExporterObjWriter.h"
-
-using namespace Nv::Blast;
-
-IMeshFileReader* NvBlastExtExporterCreateObjFileReader()
-{
- return new ObjFileReader;
-}
-
-IFbxFileReader* NvBlastExtExporterCreateFbxFileReader()
-{
- return new FbxFileReader;
-}
-
-IMeshFileWriter* NvBlastExtExporterCreateObjFileWriter()
-{
- return new ObjFileWriter;
-}
-
-IMeshFileWriter* NvBlastExtExporterCreateFbxFileWriter(bool outputFBXAscii)
-{
- auto ret = new FbxFileWriter;
- ret->bOutputFBXAscii = outputFBXAscii;
- return ret;
-}
-
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastExtExporter.h"
+#include "NvBlastExtExporterFbxReader.h"
+#include "NvBlastExtExporterObjReader.h"
+#include "NvBlastExtExporterFbxWriter.h"
+#include "NvBlastExtExporterObjWriter.h"
+
+using namespace Nv::Blast;
+
+IMeshFileReader* NvBlastExtExporterCreateObjFileReader()
+{
+ return new ObjFileReader;
+}
+
+IFbxFileReader* NvBlastExtExporterCreateFbxFileReader()
+{
+ return new FbxFileReader;
+}
+
+IMeshFileWriter* NvBlastExtExporterCreateObjFileWriter()
+{
+ return new ObjFileWriter;
+}
+
+IMeshFileWriter* NvBlastExtExporterCreateFbxFileWriter(bool outputFBXAscii)
+{
+ auto ret = new FbxFileWriter;
+ ret->bOutputFBXAscii = outputFBXAscii;
+ return ret;
+}
+
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.cpp b/sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.cpp
index edf6c16..99600fd 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.cpp
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.cpp
@@ -1,636 +1,636 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-#include "NvBlastExtExporterFbxReader.h"
-#include "NvBlastExtExporterFbxUtils.h"
-#include "NvBlastGlobals.h"
-#include <fbxsdk.h>
-#include <iostream>
-#include <algorithm>
-#include <cctype>
-#include <sstream>
-#include <unordered_map>
-
-#include "PxVec3.h"
-#include "PxVec2.h"
-#include "PxPlane.h"
-#include "NvBlastExtAuthoringMesh.h"
-#include "NvBlastExtAuthoringBondGenerator.h"
-#include "NvBlastExtAuthoringCollisionBuilder.h"
-
-using physx::PxVec3;
-using physx::PxVec2;
-
-using namespace Nv::Blast;
-
-FbxFileReader::FbxFileReader()
-{
- mMeshCount = 0;
- mChunkCount = 0;
-}
-
-void FbxFileReader::release()
-{
- delete this;
-}
-
-FbxAMatrix FbxFileReader::getTransformForNode(FbxNode* node)
-{
- //The geometry transform contains the information about the pivots in the mesh node relative to the node's transform
- FbxAMatrix geometryTransform(node->GetGeometricTranslation(FbxNode::eSourcePivot),
- node->GetGeometricRotation(FbxNode::eSourcePivot),
- node->GetGeometricScaling(FbxNode::eSourcePivot));
- FbxAMatrix nodeTransform = node->EvaluateGlobalTransform();
-
- return nodeTransform * geometryTransform;
-}
-
-void FbxFileReader::loadFromFile(const char* filename)
-{
- // Wrap in a shared ptr so that when it deallocates we get an auto destroy and all of the other assets created don't leak.
- std::shared_ptr<FbxManager> sdkManager = std::shared_ptr<FbxManager>(FbxManager::Create(), [=](FbxManager* manager)
- {
- manager->Destroy();
- });
-
- mChunkCount = 0;
- mCollisionNodes.clear();
- FbxIOSettings* ios = FbxIOSettings::Create(sdkManager.get(), IOSROOT);
- // Set some properties on the io settings
-
- sdkManager->SetIOSettings(ios);
-
-
- FbxImporter* importer = FbxImporter::Create(sdkManager.get(), "");
-
- bool importStatus = importer->Initialize(filename, -1, sdkManager->GetIOSettings());
-
- if (!importStatus)
- {
- std::cerr << "Call to FbxImporter::Initialize failed." << std::endl;
- std::cerr << "Error returned: " << importer->GetStatus().GetErrorString() << std::endl;
-
- return;
- }
-
- FbxScene* scene = FbxScene::Create(sdkManager.get(), "importScene");
-
-
-
-
- importStatus = importer->Import(scene);
-
- if (!importStatus)
- {
- std::cerr << "Call to FbxImporter::Import failed." << std::endl;
- std::cerr << "Error returned: " << importer->GetStatus().GetErrorString() << std::endl;
-
- return;
- }
-
- int32_t matCount = scene->GetMaterialCount();
-
- for (int32_t i = 0; i < matCount; ++i)
- {
- mMaterialNames.push_back(std::string(scene->GetMaterial(i)->GetName()));
- }
-
- //This removes axis and unit conversion nodes so it converts the entire scene to the header specified axis and units
- FbxRootNodeUtility::RemoveAllFbxRoots(scene);
-
- FbxAxisSystem blastAxisSystem = FbxUtils::getBlastFBXAxisSystem();
- FbxAxisSystem sourceSetup = scene->GetGlobalSettings().GetAxisSystem();
- if (sourceSetup != blastAxisSystem)
- {
- std::cout << "Converting to Blast coordinates" << std::endl;
- std::cout << "Existing axis: " << FbxUtils::FbxAxisSystemToString(sourceSetup) << std::endl;
- blastAxisSystem.ConvertScene(scene);
- }
-
- FbxSystemUnit blastUnits = FbxUtils::getBlastFBXUnit();
- FbxSystemUnit sourceUnits = scene->GetGlobalSettings().GetSystemUnit();
- if (sourceUnits != blastUnits)
- {
- std::cout << "Converting to Blast units" << std::endl;
- std::cout << "Existing units: " << FbxUtils::FbxSystemUnitToString(sourceUnits) << std::endl;
- blastUnits.ConvertScene(scene);
- }
-
- FbxGeometryConverter geoConverter(sdkManager.get());
- FbxDisplayLayer* collisionDisplayLayer = scene->FindMember<FbxDisplayLayer>(FbxUtils::getCollisionGeometryLayerName().c_str());
-
- // Recurse the fbx tree and find all meshes
- std::vector<FbxNode*> meshNodes;
- getFbxMeshes(collisionDisplayLayer, scene->GetRootNode(), meshNodes);
-
- if (isCollisionLoaded())
- {
- std::cout << "Collision geometry is found.";
- getCollisionInternal();
- }
-
- std::cout << "Found " << meshNodes.size() << " meshes." << std::endl;
-
- if (meshNodes.size() > 1)
- {
- FbxArray<FbxNode*> tempMeshArray;
- tempMeshArray.Resize((int)meshNodes.size());
- for (size_t i = 0; i < meshNodes.size(); i++)
- {
- FbxMesh* mesh = meshNodes[i]->GetMesh();
- if (mesh->GetDeformerCount(FbxDeformer::eSkin) != 0)
- {
- std::cerr << "Multi-part mesh " << meshNodes[i]->GetName() << " is already skinned, not sure what to do" << std::endl;
- return;
- }
- //Add a one-bone skin so later when we merge meshes the connection to the chunk transform will stick, this handles the non-skinned layout of the FBX file
- FbxSkin* skin = FbxSkin::Create(scene, (std::string(meshNodes[i]->GetName()) + "_skin").c_str());
- mesh->AddDeformer(skin);
- FbxCluster* cluster = FbxCluster::Create(skin, (std::string(meshNodes[i]->GetName()) + "_cluster").c_str());
- skin->AddCluster(cluster);
- cluster->SetLink(meshNodes[i]);
- const int cpCount = mesh->GetControlPointsCount();
- cluster->SetControlPointIWCount(cpCount);
- //Fully weight to the one bone
- int* cpIdx = cluster->GetControlPointIndices();
- double* cpWeights = cluster->GetControlPointWeights();
- for (int cp = 0; cp < cpCount; cp++)
- {
- cpIdx[cp] = cp;
- cpWeights[cp] = 1.0;
- }
- tempMeshArray.SetAt(int(i), meshNodes[i]);
- }
- meshNodes.resize(1);
- meshNodes[0] = geoConverter.MergeMeshes(tempMeshArray, "MergedMesh", scene);
- }
-
- if (meshNodes.empty())
- {
- return;
- }
-
- FbxNode* meshNode = meshNodes[0];
- FbxMesh* mesh = meshNode->GetMesh();
-
- // Verify that the mesh is triangulated.
- bool bAllTriangles = mesh->IsTriangleMesh();
- if (!bAllTriangles)
- {
- //try letting the FBX SDK triangulate it
- geoConverter.Triangulate(mesh, true);
- bAllTriangles = mesh->IsTriangleMesh();
- }
-
- int polyCount = mesh->GetPolygonCount();
- if (!bAllTriangles)
- {
- std::cerr << "Mesh 0 has " << polyCount << " but not all polygons are triangles. Mesh must be triangulated." << std::endl;
- return;
- }
-
- FbxStringList uvSetNames;
-
- mesh->GetUVSetNames(uvSetNames);
-
- const char * uvSetName = uvSetNames.GetStringAt(0);
-
- std::vector<PxVec3> positions;
- std::vector<PxVec3> normals;
- std::vector<PxVec2> uv;
- std::vector<uint32_t> indices;
-
- int* polyVertices = mesh->GetPolygonVertices();
-
- uint32_t vertIndex = 0;
-
- FbxAMatrix trans = getTransformForNode(meshNode);
- FbxAMatrix normalTransf = trans.Inverse().Transpose();
-
- int32_t matElements = mesh->GetElementMaterialCount();
- if (matElements > 1)
- {
- std::cerr << "Mesh has more than 1 material mappings, first one will be used. " << std::endl;
- }
- auto matLayer = mesh->GetElementMaterial(0);
- auto smLayer = mesh->GetElementSmoothing();
-
- const int triangleIndexMappingUnflipped[3] = { 0, 1, 2 };
- const int triangleIndexMappingFlipped[3] = { 2, 1, 0 };
- const int* triangleIndexMapping = trans.Determinant() < 0 ? triangleIndexMappingFlipped : triangleIndexMappingUnflipped;
-
- for (int i = 0; i < polyCount; i++)
- {
- for (int vi = 0; vi < 3; vi++)
- {
- int polyCPIdx = polyVertices[i*3+ triangleIndexMapping[vi]];
-
- FbxVector4 vert = mesh->GetControlPointAt(polyCPIdx);
- FbxVector4 normVec;
- FbxVector2 uvVec;
-
- bool bUnmapped;
- mesh->GetPolygonVertexNormal(i, vi, normVec);
- mesh->GetPolygonVertexUV(i, vi, uvSetName, uvVec, bUnmapped);
- vert = trans.MultT(vert);
- normVec = normalTransf.MultT(normVec);
-
- positions.push_back(PxVec3((float) vert[0], (float)vert[1], (float)vert[2]));
- normals.push_back(PxVec3((float)normVec[0], (float)normVec[1], (float)normVec[2]));
- uv.push_back(PxVec2((float)uvVec[0], (float)uvVec[1]));
- indices.push_back(vertIndex++);
- }
- if (matLayer != nullptr)
- {
- mMaterialIds.push_back(matLayer->GetIndexArray().GetAt(i));
- }
- if (smLayer != nullptr)
- {
- mSmoothingGroups.push_back(smLayer->GetDirectArray().GetAt(i));
- }
- }
-
- mVertexPositions = positions;
- mVertexNormals = normals;
- mVertexUv = uv;
- mIndices = indices;
-
- getBoneInfluencesInternal(mesh);
-}
-
-int32_t* FbxFileReader::getSmoothingGroups()
-{
- if (!mSmoothingGroups.empty())
- {
- return mSmoothingGroups.data();
- }
- else
- {
- return nullptr;
- }
-}
-
-int32_t FbxFileReader::getMaterialCount()
-{
- return mMaterialNames.size();
-}
-
-void FbxFileReader::getFbxMeshes(FbxDisplayLayer* collisionDisplayLayer, FbxNode* node, std::vector<FbxNode*>& meshNodes)
-{
- FbxMesh* mesh = node->GetMesh();
-
- if (mesh != nullptr)
- {
- if (collisionDisplayLayer == nullptr && node->FindProperty("ParentalChunkIndex").IsValid())
- {
- //Old-style file
- uint32_t chunkIndex = node->FindProperty("ParentalChunkIndex").Get<int32_t>();
- mCollisionNodes.emplace(chunkIndex, node);
- }
- else if (collisionDisplayLayer != nullptr && collisionDisplayLayer->IsMember(node))
- {
- uint32_t chunkIndex = FbxUtils::getChunkIndexForNode(node);
- if (chunkIndex != UINT32_MAX)
- {
- mCollisionNodes.emplace(chunkIndex, node);
- }
- else
- {
- std::cerr << "Warning: Not sure what to do about collision geo " << node->GetName() << ". No corresponding chunk." << std::endl;
- }
- }
- else
- {
- meshNodes.push_back(node);
- }
- }
- int childCount = node->GetChildCount();
-
- for (int i = 0; i < childCount; i++)
- {
- FbxNode * childNode = node->GetChild(i);
-
- getFbxMeshes(collisionDisplayLayer, childNode, meshNodes);
- }
-}
-
-bool FbxFileReader::isCollisionLoaded()
-{
- return !mCollisionNodes.empty();
-}
-
-uint32_t FbxFileReader::getCollision(uint32_t*& hullsOffset, Nv::Blast::CollisionHull**& hulls)
-{
- if (!isCollisionLoaded())
- {
- hullsOffset = nullptr;
- hulls = nullptr;
- return 0;
- }
- hullsOffset = (uint32_t*)NVBLAST_ALLOC(sizeof(uint32_t) * mHullsOffset.size());
- memcpy(hullsOffset, mHullsOffset.data(), sizeof(uint32_t) * mHullsOffset.size());
-
-
- hulls = (Nv::Blast::CollisionHull**)NVBLAST_ALLOC(sizeof(Nv::Blast::CollisionHull*) * mHulls.size());
- for (size_t i = 0; i < mHulls.size(); i++)
- {
- //This deep-copies the data inside
- hulls[i] = new CollisionHullImpl(mHulls[i]);
- }
- return mMeshCount;
-}
-
-bool FbxFileReader::getCollisionInternal()
-{
- mHulls.clear();
- int32_t maxParentIndex = 0;
-
- for (auto p : mCollisionNodes)
- {
- int32_t parentIndex = p.first;
- maxParentIndex = std::max(maxParentIndex, parentIndex);
- }
- mMeshCount = maxParentIndex + 1;
- mHullsOffset.resize(mMeshCount + 1);
- mHulls.resize(mCollisionNodes.size());
-
- uint32_t currentHullCount = 0;
- uint32_t prevParentIndex = 0;
- mHullsOffset[0] = currentHullCount;
-
- for (auto p : mCollisionNodes) // it should be sorted by chunk id
- {
- uint32_t parentIndex = p.first;
- if (prevParentIndex != parentIndex)
- {
- for (uint32_t m = prevParentIndex + 1; m < parentIndex; m++)
- {
- //copy these if there were no collision meshes
- mHullsOffset[m] = mHullsOffset[prevParentIndex];
- }
- mHullsOffset[parentIndex] = currentHullCount;
- prevParentIndex = parentIndex;
- }
- Nv::Blast::CollisionHull& chull = mHulls[currentHullCount];
- currentHullCount++;
-
- FbxMesh* meshNode = p.second->GetMesh();
-
- FbxAMatrix nodeTransform = getTransformForNode(p.second);
- FbxAMatrix nodeTransformNormal = nodeTransform.Inverse().Transpose();
-
- //PhysX seems to care about having welding verticies.
- //Probably doing a dumb search is fast enough since how big could the convex hulls possibly be?
- std::vector<FbxVector4> uniqueCPValues;
- uniqueCPValues.reserve(meshNode->GetControlPointsCount());
- std::vector<uint32_t> originalToNewCPMapping(meshNode->GetControlPointsCount(), ~0U);
-
- FbxVector4* vpos = meshNode->GetControlPoints();
- for (int32_t i = 0; i < meshNode->GetControlPointsCount(); ++i)
- {
- FbxVector4 worldVPos = nodeTransform.MultT(*vpos);
- bool found = false;
- for (size_t j = 0; j < uniqueCPValues.size(); j++)
- {
- if (uniqueCPValues[j] == worldVPos)
- {
- originalToNewCPMapping[i] = uint32_t(j);
- found = true;
- break;
- }
- }
- if (!found)
- {
- originalToNewCPMapping[i] = uint32_t(uniqueCPValues.size());
- uniqueCPValues.push_back(worldVPos);
- }
- vpos++;
- }
-
- chull.points = new PxVec3[uniqueCPValues.size()];
- chull.pointsCount = uint32_t(uniqueCPValues.size());
-
- physx::PxVec3 hullCentroid(0.0f);
-
- for (uint32_t i = 0; i < chull.pointsCount; ++i)
- {
- const FbxVector4& worldVPos = uniqueCPValues[i];
- chull.points[i].x = (float)worldVPos[0];
- chull.points[i].y = (float)worldVPos[1];
- chull.points[i].z = (float)worldVPos[2];
- hullCentroid += chull.points[i];
- }
-
- if (chull.pointsCount)
- {
- hullCentroid /= (float)chull.pointsCount;
- }
-
- uint32_t polyCount = meshNode->GetPolygonCount();
- chull.polygonData = new Nv::Blast::CollisionHull::HullPolygon[polyCount];
- chull.polygonDataCount = polyCount;
-
- chull.indicesCount = meshNode->GetPolygonVertexCount();
- chull.indices = new uint32_t[chull.indicesCount];
- uint32_t curIndexCount = 0;
-
- for (uint32_t poly = 0; poly < polyCount; ++poly)
- {
- int32_t vInPolyCount = meshNode->GetPolygonSize(poly);
- auto& pd = chull.polygonData[poly];
- pd.mIndexBase = (uint16_t)curIndexCount;
- pd.mNbVerts = (uint16_t)vInPolyCount;
- int32_t* ind = &meshNode->GetPolygonVertices()[meshNode->GetPolygonVertexIndex(poly)];
- uint32_t* destInd = chull.indices + curIndexCount;
- for (int32_t v = 0; v < vInPolyCount; v++)
- {
- destInd[v] = originalToNewCPMapping[ind[v]];
- }
- curIndexCount += vInPolyCount;
-
- //Don't depend on the normals to create the plane normal, they could be wrong
- PxVec3 lastThreeVerts[3] = {
- chull.points[chull.indices[curIndexCount - 1]],
- chull.points[chull.indices[curIndexCount - 2]],
- chull.points[chull.indices[curIndexCount - 3]]
- };
-
- physx::PxPlane plane(lastThreeVerts[0], lastThreeVerts[1], lastThreeVerts[2]);
- plane.normalize();
-
- const float s = plane.n.dot(lastThreeVerts[0] - hullCentroid) >= 0.0f ? 1.0f : -1.0f;
-
- pd.mPlane[0] = s*plane.n.x;
- pd.mPlane[1] = s*plane.n.y;
- pd.mPlane[2] = s*plane.n.z;
- pd.mPlane[3] = s*plane.d;
- }
- }
-
- //Set the end marker
- for (uint32_t m = prevParentIndex + 1; m <= mMeshCount; m++)
- {
- //copy these if there were no collision meshes
- mHullsOffset[m] = currentHullCount;
- }
-
- return false;
-}
-
-
-/**
- To work properly export tool should give bone names as bone_@chunkIndex (e.g. bone_1, bone_2)
-**/
-bool FbxFileReader::getBoneInfluencesInternal(FbxMesh* meshNode)
-{
- std::unordered_map<FbxNode*, uint32_t> boneToChunkIndex;
-
- if (meshNode->GetDeformerCount() != 1)
- {
- std::cout << "Can't create bone mapping: There is no mesh deformers...: " << std::endl;
- return false;
- }
- mVertexToContainingChunkMap.clear();
- mVertexToContainingChunkMap.resize(mVertexPositions.size());
- std::vector<uint32_t> controlToParentChunkMap;
- controlToParentChunkMap.resize(meshNode->GetControlPointsCount());
- FbxSkin* def = (FbxSkin *)meshNode->GetDeformer(0, FbxDeformer::EDeformerType::eSkin);
-
- if (def->GetClusterCount() == 0)
- {
- std::cout << "Can't create bone mapping: There is no vertex clusters...: " << std::endl;
- return false;
- }
- //We want the number of chunks not the bones in the FBX file
- mChunkCount = 0;
-
- for (int32_t i = 0; i < def->GetClusterCount(); ++i)
- {
- FbxCluster* cls = def->GetCluster(i);
- FbxNode* bone = cls->GetLink();
-
- uint32_t myChunkIndex;
- auto findIt = boneToChunkIndex.find(bone);
- if (findIt != boneToChunkIndex.end())
- {
- myChunkIndex = findIt->second;
- }
- else
- {
- myChunkIndex = FbxUtils::getChunkIndexForNode(bone);
- if (myChunkIndex == UINT32_MAX)
- {
- //maybe an old file?
- myChunkIndex = FbxUtils::getChunkIndexForNodeBackwardsCompatible(bone);
- }
-
- if (myChunkIndex == UINT32_MAX)
- {
- std::cerr << "Not sure what to do with node " << bone->GetName() << ". is this a chunk?" << std::endl;
- }
-
- boneToChunkIndex.emplace(bone, myChunkIndex);
- if (myChunkIndex >= mChunkCount)
- {
- mChunkCount = myChunkIndex + 1;
- }
- }
-
- int32_t* cpIndx = cls->GetControlPointIndices();
- for (int32_t j = 0; j < cls->GetControlPointIndicesCount(); ++j)
- {
- controlToParentChunkMap[*cpIndx] = myChunkIndex;
- ++cpIndx;
- }
- }
-
- int* polyVertices = meshNode->GetPolygonVertices();
- uint32_t lv = 0;
- for (int i = 0; i < meshNode->GetPolygonCount(); i++)
- {
- for (int vi = 0; vi < 3; vi++)
- {
- mVertexToContainingChunkMap[lv] = controlToParentChunkMap[*polyVertices];
- polyVertices++;
- lv++;
- }
- }
- return true;
-};
-
-physx::PxVec3* FbxFileReader::getPositionArray()
-{
- return mVertexPositions.data();
-};
-
-physx::PxVec3* FbxFileReader::getNormalsArray()
-{
- return mVertexNormals.data();
-};
-
-physx::PxVec2* FbxFileReader::getUvArray()
-{
- return mVertexUv.data();
-};
-
-uint32_t* FbxFileReader::getIndexArray()
-{
- return mIndices.data();
-};
-
-uint32_t FbxFileReader::getBoneInfluences(uint32_t*& out)
-{
- out = static_cast<uint32_t*>(NVBLAST_ALLOC(sizeof(uint32_t) * mVertexToContainingChunkMap.size()));
- memcpy(out, mVertexToContainingChunkMap.data(), sizeof(uint32_t) * mVertexToContainingChunkMap.size());
- return mVertexToContainingChunkMap.size();
-}
-
-uint32_t FbxFileReader::getBoneCount()
-{
- return mChunkCount;
-}
-
-const char* FbxFileReader::getMaterialName(int32_t id)
-{
- if (id < int32_t(mMaterialNames.size()) && id >= 0)
- {
- return mMaterialNames[id].c_str();
- }
- else
- {
- return nullptr;
- }
-}
-
-int32_t* FbxFileReader::getMaterialIds()
-{
- if (mMaterialIds.empty())
- {
- return nullptr;
- }
- return mMaterialIds.data();
-}
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+#include "NvBlastExtExporterFbxReader.h"
+#include "NvBlastExtExporterFbxUtils.h"
+#include "NvBlastGlobals.h"
+#include <fbxsdk.h>
+#include <iostream>
+#include <algorithm>
+#include <cctype>
+#include <sstream>
+#include <unordered_map>
+
+#include "PxVec3.h"
+#include "PxVec2.h"
+#include "PxPlane.h"
+#include "NvBlastExtAuthoringMesh.h"
+#include "NvBlastExtAuthoringBondGenerator.h"
+#include "NvBlastExtAuthoringCollisionBuilder.h"
+
+using physx::PxVec3;
+using physx::PxVec2;
+
+using namespace Nv::Blast;
+
+FbxFileReader::FbxFileReader()
+{
+ mMeshCount = 0;
+ mChunkCount = 0;
+}
+
+void FbxFileReader::release()
+{
+ delete this;
+}
+
+FbxAMatrix FbxFileReader::getTransformForNode(FbxNode* node)
+{
+ //The geometry transform contains the information about the pivots in the mesh node relative to the node's transform
+ FbxAMatrix geometryTransform(node->GetGeometricTranslation(FbxNode::eSourcePivot),
+ node->GetGeometricRotation(FbxNode::eSourcePivot),
+ node->GetGeometricScaling(FbxNode::eSourcePivot));
+ FbxAMatrix nodeTransform = node->EvaluateGlobalTransform();
+
+ return nodeTransform * geometryTransform;
+}
+
+void FbxFileReader::loadFromFile(const char* filename)
+{
+ // Wrap in a shared ptr so that when it deallocates we get an auto destroy and all of the other assets created don't leak.
+ std::shared_ptr<FbxManager> sdkManager = std::shared_ptr<FbxManager>(FbxManager::Create(), [=](FbxManager* manager)
+ {
+ manager->Destroy();
+ });
+
+ mChunkCount = 0;
+ mCollisionNodes.clear();
+ FbxIOSettings* ios = FbxIOSettings::Create(sdkManager.get(), IOSROOT);
+ // Set some properties on the io settings
+
+ sdkManager->SetIOSettings(ios);
+
+
+ FbxImporter* importer = FbxImporter::Create(sdkManager.get(), "");
+
+ bool importStatus = importer->Initialize(filename, -1, sdkManager->GetIOSettings());
+
+ if (!importStatus)
+ {
+ std::cerr << "Call to FbxImporter::Initialize failed." << std::endl;
+ std::cerr << "Error returned: " << importer->GetStatus().GetErrorString() << std::endl;
+
+ return;
+ }
+
+ FbxScene* scene = FbxScene::Create(sdkManager.get(), "importScene");
+
+
+
+
+ importStatus = importer->Import(scene);
+
+ if (!importStatus)
+ {
+ std::cerr << "Call to FbxImporter::Import failed." << std::endl;
+ std::cerr << "Error returned: " << importer->GetStatus().GetErrorString() << std::endl;
+
+ return;
+ }
+
+ int32_t matCount = scene->GetMaterialCount();
+
+ for (int32_t i = 0; i < matCount; ++i)
+ {
+ mMaterialNames.push_back(std::string(scene->GetMaterial(i)->GetName()));
+ }
+
+ //This removes axis and unit conversion nodes so it converts the entire scene to the header specified axis and units
+ FbxRootNodeUtility::RemoveAllFbxRoots(scene);
+
+ FbxAxisSystem blastAxisSystem = FbxUtils::getBlastFBXAxisSystem();
+ FbxAxisSystem sourceSetup = scene->GetGlobalSettings().GetAxisSystem();
+ if (sourceSetup != blastAxisSystem)
+ {
+ std::cout << "Converting to Blast coordinates" << std::endl;
+ std::cout << "Existing axis: " << FbxUtils::FbxAxisSystemToString(sourceSetup) << std::endl;
+ blastAxisSystem.ConvertScene(scene);
+ }
+
+ FbxSystemUnit blastUnits = FbxUtils::getBlastFBXUnit();
+ FbxSystemUnit sourceUnits = scene->GetGlobalSettings().GetSystemUnit();
+ if (sourceUnits != blastUnits)
+ {
+ std::cout << "Converting to Blast units" << std::endl;
+ std::cout << "Existing units: " << FbxUtils::FbxSystemUnitToString(sourceUnits) << std::endl;
+ blastUnits.ConvertScene(scene);
+ }
+
+ FbxGeometryConverter geoConverter(sdkManager.get());
+ FbxDisplayLayer* collisionDisplayLayer = scene->FindMember<FbxDisplayLayer>(FbxUtils::getCollisionGeometryLayerName().c_str());
+
+ // Recurse the fbx tree and find all meshes
+ std::vector<FbxNode*> meshNodes;
+ getFbxMeshes(collisionDisplayLayer, scene->GetRootNode(), meshNodes);
+
+ if (isCollisionLoaded())
+ {
+ std::cout << "Collision geometry is found.";
+ getCollisionInternal();
+ }
+
+ std::cout << "Found " << meshNodes.size() << " meshes." << std::endl;
+
+ if (meshNodes.size() > 1)
+ {
+ FbxArray<FbxNode*> tempMeshArray;
+ tempMeshArray.Resize((int)meshNodes.size());
+ for (size_t i = 0; i < meshNodes.size(); i++)
+ {
+ FbxMesh* mesh = meshNodes[i]->GetMesh();
+ if (mesh->GetDeformerCount(FbxDeformer::eSkin) != 0)
+ {
+ std::cerr << "Multi-part mesh " << meshNodes[i]->GetName() << " is already skinned, not sure what to do" << std::endl;
+ return;
+ }
+ //Add a one-bone skin so later when we merge meshes the connection to the chunk transform will stick, this handles the non-skinned layout of the FBX file
+ FbxSkin* skin = FbxSkin::Create(scene, (std::string(meshNodes[i]->GetName()) + "_skin").c_str());
+ mesh->AddDeformer(skin);
+ FbxCluster* cluster = FbxCluster::Create(skin, (std::string(meshNodes[i]->GetName()) + "_cluster").c_str());
+ skin->AddCluster(cluster);
+ cluster->SetLink(meshNodes[i]);
+ const int cpCount = mesh->GetControlPointsCount();
+ cluster->SetControlPointIWCount(cpCount);
+ //Fully weight to the one bone
+ int* cpIdx = cluster->GetControlPointIndices();
+ double* cpWeights = cluster->GetControlPointWeights();
+ for (int cp = 0; cp < cpCount; cp++)
+ {
+ cpIdx[cp] = cp;
+ cpWeights[cp] = 1.0;
+ }
+ tempMeshArray.SetAt(int(i), meshNodes[i]);
+ }
+ meshNodes.resize(1);
+ meshNodes[0] = geoConverter.MergeMeshes(tempMeshArray, "MergedMesh", scene);
+ }
+
+ if (meshNodes.empty())
+ {
+ return;
+ }
+
+ FbxNode* meshNode = meshNodes[0];
+ FbxMesh* mesh = meshNode->GetMesh();
+
+ // Verify that the mesh is triangulated.
+ bool bAllTriangles = mesh->IsTriangleMesh();
+ if (!bAllTriangles)
+ {
+ //try letting the FBX SDK triangulate it
+ geoConverter.Triangulate(mesh, true);
+ bAllTriangles = mesh->IsTriangleMesh();
+ }
+
+ int polyCount = mesh->GetPolygonCount();
+ if (!bAllTriangles)
+ {
+ std::cerr << "Mesh 0 has " << polyCount << " but not all polygons are triangles. Mesh must be triangulated." << std::endl;
+ return;
+ }
+
+ FbxStringList uvSetNames;
+
+ mesh->GetUVSetNames(uvSetNames);
+
+ const char * uvSetName = uvSetNames.GetStringAt(0);
+
+ std::vector<PxVec3> positions;
+ std::vector<PxVec3> normals;
+ std::vector<PxVec2> uv;
+ std::vector<uint32_t> indices;
+
+ int* polyVertices = mesh->GetPolygonVertices();
+
+ uint32_t vertIndex = 0;
+
+ FbxAMatrix trans = getTransformForNode(meshNode);
+ FbxAMatrix normalTransf = trans.Inverse().Transpose();
+
+ int32_t matElements = mesh->GetElementMaterialCount();
+ if (matElements > 1)
+ {
+ std::cerr << "Mesh has more than 1 material mappings, first one will be used. " << std::endl;
+ }
+ auto matLayer = mesh->GetElementMaterial(0);
+ auto smLayer = mesh->GetElementSmoothing();
+
+ const int triangleIndexMappingUnflipped[3] = { 0, 1, 2 };
+ const int triangleIndexMappingFlipped[3] = { 2, 1, 0 };
+ const int* triangleIndexMapping = trans.Determinant() < 0 ? triangleIndexMappingFlipped : triangleIndexMappingUnflipped;
+
+ for (int i = 0; i < polyCount; i++)
+ {
+ for (int vi = 0; vi < 3; vi++)
+ {
+ int polyCPIdx = polyVertices[i*3+ triangleIndexMapping[vi]];
+
+ FbxVector4 vert = mesh->GetControlPointAt(polyCPIdx);
+ FbxVector4 normVec;
+ FbxVector2 uvVec;
+
+ bool bUnmapped;
+ mesh->GetPolygonVertexNormal(i, vi, normVec);
+ mesh->GetPolygonVertexUV(i, vi, uvSetName, uvVec, bUnmapped);
+ vert = trans.MultT(vert);
+ normVec = normalTransf.MultT(normVec);
+
+ positions.push_back(PxVec3((float) vert[0], (float)vert[1], (float)vert[2]));
+ normals.push_back(PxVec3((float)normVec[0], (float)normVec[1], (float)normVec[2]));
+ uv.push_back(PxVec2((float)uvVec[0], (float)uvVec[1]));
+ indices.push_back(vertIndex++);
+ }
+ if (matLayer != nullptr)
+ {
+ mMaterialIds.push_back(matLayer->GetIndexArray().GetAt(i));
+ }
+ if (smLayer != nullptr)
+ {
+ mSmoothingGroups.push_back(smLayer->GetDirectArray().GetAt(i));
+ }
+ }
+
+ mVertexPositions = positions;
+ mVertexNormals = normals;
+ mVertexUv = uv;
+ mIndices = indices;
+
+ getBoneInfluencesInternal(mesh);
+}
+
+int32_t* FbxFileReader::getSmoothingGroups()
+{
+ if (!mSmoothingGroups.empty())
+ {
+ return mSmoothingGroups.data();
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+int32_t FbxFileReader::getMaterialCount()
+{
+ return mMaterialNames.size();
+}
+
+void FbxFileReader::getFbxMeshes(FbxDisplayLayer* collisionDisplayLayer, FbxNode* node, std::vector<FbxNode*>& meshNodes)
+{
+ FbxMesh* mesh = node->GetMesh();
+
+ if (mesh != nullptr)
+ {
+ if (collisionDisplayLayer == nullptr && node->FindProperty("ParentalChunkIndex").IsValid())
+ {
+ //Old-style file
+ uint32_t chunkIndex = node->FindProperty("ParentalChunkIndex").Get<int32_t>();
+ mCollisionNodes.emplace(chunkIndex, node);
+ }
+ else if (collisionDisplayLayer != nullptr && collisionDisplayLayer->IsMember(node))
+ {
+ uint32_t chunkIndex = FbxUtils::getChunkIndexForNode(node);
+ if (chunkIndex != UINT32_MAX)
+ {
+ mCollisionNodes.emplace(chunkIndex, node);
+ }
+ else
+ {
+ std::cerr << "Warning: Not sure what to do about collision geo " << node->GetName() << ". No corresponding chunk." << std::endl;
+ }
+ }
+ else
+ {
+ meshNodes.push_back(node);
+ }
+ }
+ int childCount = node->GetChildCount();
+
+ for (int i = 0; i < childCount; i++)
+ {
+ FbxNode * childNode = node->GetChild(i);
+
+ getFbxMeshes(collisionDisplayLayer, childNode, meshNodes);
+ }
+}
+
+bool FbxFileReader::isCollisionLoaded()
+{
+ return !mCollisionNodes.empty();
+}
+
+uint32_t FbxFileReader::getCollision(uint32_t*& hullsOffset, Nv::Blast::CollisionHull**& hulls)
+{
+ if (!isCollisionLoaded())
+ {
+ hullsOffset = nullptr;
+ hulls = nullptr;
+ return 0;
+ }
+ hullsOffset = (uint32_t*)NVBLAST_ALLOC(sizeof(uint32_t) * mHullsOffset.size());
+ memcpy(hullsOffset, mHullsOffset.data(), sizeof(uint32_t) * mHullsOffset.size());
+
+
+ hulls = (Nv::Blast::CollisionHull**)NVBLAST_ALLOC(sizeof(Nv::Blast::CollisionHull*) * mHulls.size());
+ for (size_t i = 0; i < mHulls.size(); i++)
+ {
+ //This deep-copies the data inside
+ hulls[i] = new CollisionHullImpl(mHulls[i]);
+ }
+ return mMeshCount;
+}
+
+bool FbxFileReader::getCollisionInternal()
+{
+ mHulls.clear();
+ int32_t maxParentIndex = 0;
+
+ for (auto p : mCollisionNodes)
+ {
+ int32_t parentIndex = p.first;
+ maxParentIndex = std::max(maxParentIndex, parentIndex);
+ }
+ mMeshCount = maxParentIndex + 1;
+ mHullsOffset.resize(mMeshCount + 1);
+ mHulls.resize(mCollisionNodes.size());
+
+ uint32_t currentHullCount = 0;
+ uint32_t prevParentIndex = 0;
+ mHullsOffset[0] = currentHullCount;
+
+ for (auto p : mCollisionNodes) // it should be sorted by chunk id
+ {
+ uint32_t parentIndex = p.first;
+ if (prevParentIndex != parentIndex)
+ {
+ for (uint32_t m = prevParentIndex + 1; m < parentIndex; m++)
+ {
+ //copy these if there were no collision meshes
+ mHullsOffset[m] = mHullsOffset[prevParentIndex];
+ }
+ mHullsOffset[parentIndex] = currentHullCount;
+ prevParentIndex = parentIndex;
+ }
+ Nv::Blast::CollisionHull& chull = mHulls[currentHullCount];
+ currentHullCount++;
+
+ FbxMesh* meshNode = p.second->GetMesh();
+
+ FbxAMatrix nodeTransform = getTransformForNode(p.second);
+ FbxAMatrix nodeTransformNormal = nodeTransform.Inverse().Transpose();
+
+ //PhysX seems to care about having welding verticies.
+ //Probably doing a dumb search is fast enough since how big could the convex hulls possibly be?
+ std::vector<FbxVector4> uniqueCPValues;
+ uniqueCPValues.reserve(meshNode->GetControlPointsCount());
+ std::vector<uint32_t> originalToNewCPMapping(meshNode->GetControlPointsCount(), ~0U);
+
+ FbxVector4* vpos = meshNode->GetControlPoints();
+ for (int32_t i = 0; i < meshNode->GetControlPointsCount(); ++i)
+ {
+ FbxVector4 worldVPos = nodeTransform.MultT(*vpos);
+ bool found = false;
+ for (size_t j = 0; j < uniqueCPValues.size(); j++)
+ {
+ if (uniqueCPValues[j] == worldVPos)
+ {
+ originalToNewCPMapping[i] = uint32_t(j);
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ originalToNewCPMapping[i] = uint32_t(uniqueCPValues.size());
+ uniqueCPValues.push_back(worldVPos);
+ }
+ vpos++;
+ }
+
+ chull.points = new PxVec3[uniqueCPValues.size()];
+ chull.pointsCount = uint32_t(uniqueCPValues.size());
+
+ physx::PxVec3 hullCentroid(0.0f);
+
+ for (uint32_t i = 0; i < chull.pointsCount; ++i)
+ {
+ const FbxVector4& worldVPos = uniqueCPValues[i];
+ chull.points[i].x = (float)worldVPos[0];
+ chull.points[i].y = (float)worldVPos[1];
+ chull.points[i].z = (float)worldVPos[2];
+ hullCentroid += chull.points[i];
+ }
+
+ if (chull.pointsCount)
+ {
+ hullCentroid /= (float)chull.pointsCount;
+ }
+
+ uint32_t polyCount = meshNode->GetPolygonCount();
+ chull.polygonData = new Nv::Blast::CollisionHull::HullPolygon[polyCount];
+ chull.polygonDataCount = polyCount;
+
+ chull.indicesCount = meshNode->GetPolygonVertexCount();
+ chull.indices = new uint32_t[chull.indicesCount];
+ uint32_t curIndexCount = 0;
+
+ for (uint32_t poly = 0; poly < polyCount; ++poly)
+ {
+ int32_t vInPolyCount = meshNode->GetPolygonSize(poly);
+ auto& pd = chull.polygonData[poly];
+ pd.mIndexBase = (uint16_t)curIndexCount;
+ pd.mNbVerts = (uint16_t)vInPolyCount;
+ int32_t* ind = &meshNode->GetPolygonVertices()[meshNode->GetPolygonVertexIndex(poly)];
+ uint32_t* destInd = chull.indices + curIndexCount;
+ for (int32_t v = 0; v < vInPolyCount; v++)
+ {
+ destInd[v] = originalToNewCPMapping[ind[v]];
+ }
+ curIndexCount += vInPolyCount;
+
+ //Don't depend on the normals to create the plane normal, they could be wrong
+ PxVec3 lastThreeVerts[3] = {
+ chull.points[chull.indices[curIndexCount - 1]],
+ chull.points[chull.indices[curIndexCount - 2]],
+ chull.points[chull.indices[curIndexCount - 3]]
+ };
+
+ physx::PxPlane plane(lastThreeVerts[0], lastThreeVerts[1], lastThreeVerts[2]);
+ plane.normalize();
+
+ const float s = plane.n.dot(lastThreeVerts[0] - hullCentroid) >= 0.0f ? 1.0f : -1.0f;
+
+ pd.mPlane[0] = s*plane.n.x;
+ pd.mPlane[1] = s*plane.n.y;
+ pd.mPlane[2] = s*plane.n.z;
+ pd.mPlane[3] = s*plane.d;
+ }
+ }
+
+ //Set the end marker
+ for (uint32_t m = prevParentIndex + 1; m <= mMeshCount; m++)
+ {
+ //copy these if there were no collision meshes
+ mHullsOffset[m] = currentHullCount;
+ }
+
+ return false;
+}
+
+
+/**
+ To work properly export tool should give bone names as bone_@chunkIndex (e.g. bone_1, bone_2)
+**/
+bool FbxFileReader::getBoneInfluencesInternal(FbxMesh* meshNode)
+{
+ std::unordered_map<FbxNode*, uint32_t> boneToChunkIndex;
+
+ if (meshNode->GetDeformerCount() != 1)
+ {
+ std::cout << "Can't create bone mapping: There is no mesh deformers...: " << std::endl;
+ return false;
+ }
+ mVertexToContainingChunkMap.clear();
+ mVertexToContainingChunkMap.resize(mVertexPositions.size());
+ std::vector<uint32_t> controlToParentChunkMap;
+ controlToParentChunkMap.resize(meshNode->GetControlPointsCount());
+ FbxSkin* def = (FbxSkin *)meshNode->GetDeformer(0, FbxDeformer::EDeformerType::eSkin);
+
+ if (def->GetClusterCount() == 0)
+ {
+ std::cout << "Can't create bone mapping: There is no vertex clusters...: " << std::endl;
+ return false;
+ }
+ //We want the number of chunks not the bones in the FBX file
+ mChunkCount = 0;
+
+ for (int32_t i = 0; i < def->GetClusterCount(); ++i)
+ {
+ FbxCluster* cls = def->GetCluster(i);
+ FbxNode* bone = cls->GetLink();
+
+ uint32_t myChunkIndex;
+ auto findIt = boneToChunkIndex.find(bone);
+ if (findIt != boneToChunkIndex.end())
+ {
+ myChunkIndex = findIt->second;
+ }
+ else
+ {
+ myChunkIndex = FbxUtils::getChunkIndexForNode(bone);
+ if (myChunkIndex == UINT32_MAX)
+ {
+ //maybe an old file?
+ myChunkIndex = FbxUtils::getChunkIndexForNodeBackwardsCompatible(bone);
+ }
+
+ if (myChunkIndex == UINT32_MAX)
+ {
+ std::cerr << "Not sure what to do with node " << bone->GetName() << ". is this a chunk?" << std::endl;
+ }
+
+ boneToChunkIndex.emplace(bone, myChunkIndex);
+ if (myChunkIndex >= mChunkCount)
+ {
+ mChunkCount = myChunkIndex + 1;
+ }
+ }
+
+ int32_t* cpIndx = cls->GetControlPointIndices();
+ for (int32_t j = 0; j < cls->GetControlPointIndicesCount(); ++j)
+ {
+ controlToParentChunkMap[*cpIndx] = myChunkIndex;
+ ++cpIndx;
+ }
+ }
+
+ int* polyVertices = meshNode->GetPolygonVertices();
+ uint32_t lv = 0;
+ for (int i = 0; i < meshNode->GetPolygonCount(); i++)
+ {
+ for (int vi = 0; vi < 3; vi++)
+ {
+ mVertexToContainingChunkMap[lv] = controlToParentChunkMap[*polyVertices];
+ polyVertices++;
+ lv++;
+ }
+ }
+ return true;
+};
+
+physx::PxVec3* FbxFileReader::getPositionArray()
+{
+ return mVertexPositions.data();
+};
+
+physx::PxVec3* FbxFileReader::getNormalsArray()
+{
+ return mVertexNormals.data();
+};
+
+physx::PxVec2* FbxFileReader::getUvArray()
+{
+ return mVertexUv.data();
+};
+
+uint32_t* FbxFileReader::getIndexArray()
+{
+ return mIndices.data();
+};
+
+uint32_t FbxFileReader::getBoneInfluences(uint32_t*& out)
+{
+ out = static_cast<uint32_t*>(NVBLAST_ALLOC(sizeof(uint32_t) * mVertexToContainingChunkMap.size()));
+ memcpy(out, mVertexToContainingChunkMap.data(), sizeof(uint32_t) * mVertexToContainingChunkMap.size());
+ return mVertexToContainingChunkMap.size();
+}
+
+uint32_t FbxFileReader::getBoneCount()
+{
+ return mChunkCount;
+}
+
+const char* FbxFileReader::getMaterialName(int32_t id)
+{
+ if (id < int32_t(mMaterialNames.size()) && id >= 0)
+ {
+ return mMaterialNames[id].c_str();
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+int32_t* FbxFileReader::getMaterialIds()
+{
+ if (mMaterialIds.empty())
+ {
+ return nullptr;
+ }
+ return mMaterialIds.data();
+}
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.h b/sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.h
index ce1d008..0509700 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.h
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterFbxReader.h
@@ -1,224 +1,224 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#ifndef NVBLASTEXTEXPORTERFBXREADER_H
-#define NVBLASTEXTEXPORTERFBXREADER_H
-
-#include <memory>
-#include "fbxsdk.h"
-#include <vector>
-#include <map>
-#include "NvBlastExtExporter.h"
-#include "NvBlastExtAuthoringTypes.h"
-
-namespace Nv
-{
-namespace Blast
-{
-class Mesh;
-
-class FbxFileReader : public IFbxFileReader
-{
- struct CollisionHullImpl : public Nv::Blast::CollisionHull
- {
- void release() override
- {
- delete this;
- }
-
- //copy from existing
- CollisionHullImpl(const CollisionHullImpl& other) : CollisionHullImpl()
- {
- copyFrom(other);
- }
-
- CollisionHullImpl()
- {
- pointsCount = 0;
- indicesCount = 0;
- polygonDataCount = 0;
- points = nullptr;
- indices = nullptr;
- polygonData = nullptr;
- }
-
- CollisionHullImpl(CollisionHullImpl&& other)
- {
- operator=(std::move(other));
- }
-
- CollisionHullImpl& operator=(const CollisionHullImpl& other)
- {
- if (&other != this)
- {
- release();
- copyFrom(other);
- }
- return *this;
- }
-
- CollisionHullImpl& operator=(CollisionHullImpl&& other)
- {
- if (&other != this)
- {
- pointsCount = other.pointsCount;
- indicesCount = other.indicesCount;
- polygonDataCount = other.polygonDataCount;
- points = other.points;
- indices = other.indices;
- polygonData = other.polygonData;
-
- other.pointsCount = 0;
- other.indicesCount = 0;
- other.polygonDataCount = 0;
- other.points = nullptr;
- other.indices = nullptr;
- other.polygonData = nullptr;
- }
- return *this;
- }
-
- virtual ~CollisionHullImpl()
- {
- delete[] points;
- delete[] indices;
- delete[] polygonData;
- }
- private:
-
- void copyFrom(const CollisionHullImpl& other)
- {
- pointsCount = other.pointsCount;
- indicesCount = other.indicesCount;
- polygonDataCount = other.polygonDataCount;
- points = new physx::PxVec3[pointsCount];
- indices = new uint32_t[indicesCount];
- polygonData = new Nv::Blast::CollisionHull::HullPolygon[polygonDataCount];
- memcpy(points, other.points, sizeof(points[0]) * pointsCount);
- memcpy(indices, other.indices, sizeof(indices[0]) * indicesCount);
- memcpy(polygonData, other.polygonData, sizeof(polygonData[0]) * polygonDataCount);
- }
- };
-
-public:
- FbxFileReader();
- ~FbxFileReader() = default;
-
- virtual void release() override;
-
- /*
- Load from the specified file path, returning a mesh or nullptr if failed
- */
- virtual void loadFromFile(const char* filename) override;
-
- virtual uint32_t getVerticesCount() const override
- {
- return mVertexPositions.size();
- }
-
- virtual uint32_t getIndicesCount() const override
- {
- return mIndices.size();
- }
-
- /**
- Check whether file contained an collision geometry
- */
- virtual bool isCollisionLoaded() override;
-
- /**
- Retrieve collision geometry if it exist
- */
- virtual uint32_t getCollision(uint32_t*& hullsOffset, Nv::Blast::CollisionHull**& hulls) override;
-
- virtual uint32_t getBoneInfluences(uint32_t*& out) override;
-
- virtual uint32_t getBoneCount() override;
-
- /**
- Get loaded vertex positions
- */
- virtual physx::PxVec3* getPositionArray() override;
- /**
- Get loaded vertex normals
- */
- virtual physx::PxVec3* getNormalsArray() override;
- /**
- Get loaded vertex uv-coordinates
- */
- virtual physx::PxVec2* getUvArray() override;
- /**
- Get loaded triangle indices
- */
- virtual uint32_t* getIndexArray() override;
-
- /**
- Get loaded per triangle material ids.
- */
- int32_t* getMaterialIds() override;
-
- /**
- Get loaded per triangle smoothing groups. Currently not supported.
- */
- int32_t* getSmoothingGroups() override;
-
- /**
- Get material name.
- */
- const char* getMaterialName(int32_t id) override;
-
-
- int32_t getMaterialCount() override;
-
-private:
-
- uint32_t mMeshCount;
- uint32_t mChunkCount;
- std::vector<uint32_t> mHullsOffset;
- std::vector<CollisionHullImpl> mHulls;
- std::vector<uint32_t> mVertexToContainingChunkMap;
- std::multimap<uint32_t, FbxNode*> mCollisionNodes;
- std::vector<physx::PxVec3> mVertexPositions;
- std::vector<physx::PxVec3> mVertexNormals;
- std::vector<physx::PxVec2> mVertexUv;
- std::vector<uint32_t> mIndices;
- std::vector<int32_t> mSmoothingGroups;
- std::vector<int32_t> mMaterialIds;
- std::vector<std::string> mMaterialNames;
-
- FbxAMatrix getTransformForNode(FbxNode* node);
- void getFbxMeshes(FbxDisplayLayer* collisionDisplayLayer, FbxNode* node, std::vector<FbxNode*>& meshNodes);
- bool getCollisionInternal();
- bool getBoneInfluencesInternal(FbxMesh* meshNode);
-
-};
-
-}
-}
-
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTEXTEXPORTERFBXREADER_H
+#define NVBLASTEXTEXPORTERFBXREADER_H
+
+#include <memory>
+#include "fbxsdk.h"
+#include <vector>
+#include <map>
+#include "NvBlastExtExporter.h"
+#include "NvBlastExtAuthoringTypes.h"
+
+namespace Nv
+{
+namespace Blast
+{
+class Mesh;
+
+class FbxFileReader : public IFbxFileReader
+{
+ struct CollisionHullImpl : public Nv::Blast::CollisionHull
+ {
+ void release() override
+ {
+ delete this;
+ }
+
+ //copy from existing
+ CollisionHullImpl(const CollisionHullImpl& other) : CollisionHullImpl()
+ {
+ copyFrom(other);
+ }
+
+ CollisionHullImpl()
+ {
+ pointsCount = 0;
+ indicesCount = 0;
+ polygonDataCount = 0;
+ points = nullptr;
+ indices = nullptr;
+ polygonData = nullptr;
+ }
+
+ CollisionHullImpl(CollisionHullImpl&& other)
+ {
+ operator=(std::move(other));
+ }
+
+ CollisionHullImpl& operator=(const CollisionHullImpl& other)
+ {
+ if (&other != this)
+ {
+ release();
+ copyFrom(other);
+ }
+ return *this;
+ }
+
+ CollisionHullImpl& operator=(CollisionHullImpl&& other)
+ {
+ if (&other != this)
+ {
+ pointsCount = other.pointsCount;
+ indicesCount = other.indicesCount;
+ polygonDataCount = other.polygonDataCount;
+ points = other.points;
+ indices = other.indices;
+ polygonData = other.polygonData;
+
+ other.pointsCount = 0;
+ other.indicesCount = 0;
+ other.polygonDataCount = 0;
+ other.points = nullptr;
+ other.indices = nullptr;
+ other.polygonData = nullptr;
+ }
+ return *this;
+ }
+
+ virtual ~CollisionHullImpl()
+ {
+ delete[] points;
+ delete[] indices;
+ delete[] polygonData;
+ }
+ private:
+
+ void copyFrom(const CollisionHullImpl& other)
+ {
+ pointsCount = other.pointsCount;
+ indicesCount = other.indicesCount;
+ polygonDataCount = other.polygonDataCount;
+ points = new physx::PxVec3[pointsCount];
+ indices = new uint32_t[indicesCount];
+ polygonData = new Nv::Blast::CollisionHull::HullPolygon[polygonDataCount];
+ memcpy(points, other.points, sizeof(points[0]) * pointsCount);
+ memcpy(indices, other.indices, sizeof(indices[0]) * indicesCount);
+ memcpy(polygonData, other.polygonData, sizeof(polygonData[0]) * polygonDataCount);
+ }
+ };
+
+public:
+ FbxFileReader();
+ ~FbxFileReader() = default;
+
+ virtual void release() override;
+
+ /*
+ Load from the specified file path, returning a mesh or nullptr if failed
+ */
+ virtual void loadFromFile(const char* filename) override;
+
+ virtual uint32_t getVerticesCount() const override
+ {
+ return mVertexPositions.size();
+ }
+
+ virtual uint32_t getIndicesCount() const override
+ {
+ return mIndices.size();
+ }
+
+ /**
+ Check whether file contained an collision geometry
+ */
+ virtual bool isCollisionLoaded() override;
+
+ /**
+ Retrieve collision geometry if it exist
+ */
+ virtual uint32_t getCollision(uint32_t*& hullsOffset, Nv::Blast::CollisionHull**& hulls) override;
+
+ virtual uint32_t getBoneInfluences(uint32_t*& out) override;
+
+ virtual uint32_t getBoneCount() override;
+
+ /**
+ Get loaded vertex positions
+ */
+ virtual physx::PxVec3* getPositionArray() override;
+ /**
+ Get loaded vertex normals
+ */
+ virtual physx::PxVec3* getNormalsArray() override;
+ /**
+ Get loaded vertex uv-coordinates
+ */
+ virtual physx::PxVec2* getUvArray() override;
+ /**
+ Get loaded triangle indices
+ */
+ virtual uint32_t* getIndexArray() override;
+
+ /**
+ Get loaded per triangle material ids.
+ */
+ int32_t* getMaterialIds() override;
+
+ /**
+ Get loaded per triangle smoothing groups. Currently not supported.
+ */
+ int32_t* getSmoothingGroups() override;
+
+ /**
+ Get material name.
+ */
+ const char* getMaterialName(int32_t id) override;
+
+
+ int32_t getMaterialCount() override;
+
+private:
+
+ uint32_t mMeshCount;
+ uint32_t mChunkCount;
+ std::vector<uint32_t> mHullsOffset;
+ std::vector<CollisionHullImpl> mHulls;
+ std::vector<uint32_t> mVertexToContainingChunkMap;
+ std::multimap<uint32_t, FbxNode*> mCollisionNodes;
+ std::vector<physx::PxVec3> mVertexPositions;
+ std::vector<physx::PxVec3> mVertexNormals;
+ std::vector<physx::PxVec2> mVertexUv;
+ std::vector<uint32_t> mIndices;
+ std::vector<int32_t> mSmoothingGroups;
+ std::vector<int32_t> mMaterialIds;
+ std::vector<std::string> mMaterialNames;
+
+ FbxAMatrix getTransformForNode(FbxNode* node);
+ void getFbxMeshes(FbxDisplayLayer* collisionDisplayLayer, FbxNode* node, std::vector<FbxNode*>& meshNodes);
+ bool getCollisionInternal();
+ bool getBoneInfluencesInternal(FbxMesh* meshNode);
+
+};
+
+}
+}
+
#endif \ No newline at end of file
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.cpp b/sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.cpp
index adf4092..f135436 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.cpp
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.cpp
@@ -1,208 +1,208 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "fbxsdk.h"
-#include "NvBlastExtExporterFbxUtils.h"
-#include "PxVec3.h"
-#include "PxVec2.h"
-#include "NvBlastExtAuthoringTypes.h"
-#include <sstream>
-#include <cctype>
-
-using physx::PxVec3;
-using physx::PxVec2;
-
-
-void FbxUtils::VertexToFbx(const Nv::Blast::Vertex& vert, FbxVector4& outVertex, FbxVector4& outNormal, FbxVector2& outUV)
-{
- PxVec3ToFbx(vert.p, outVertex);
- PxVec3ToFbx(vert.n, outNormal);
- PxVec2ToFbx(vert.uv[0], outUV);
-}
-
-void FbxUtils::PxVec3ToFbx(const physx::PxVec3& inVector, FbxVector4& outVector)
-{
- outVector[0] = inVector.x;
- outVector[1] = inVector.y;
- outVector[2] = inVector.z;
- outVector[3] = 0;
-}
-
-void FbxUtils::PxVec2ToFbx(const physx::PxVec2& inVector, FbxVector2& outVector)
-{
- outVector[0] = inVector.x;
- outVector[1] = inVector.y;
-}
-
-FbxAxisSystem FbxUtils::getBlastFBXAxisSystem()
-{
- const FbxAxisSystem::EUpVector upVector = FbxAxisSystem::eZAxis;
- //From the documentation: If the up axis is Z, the remain two axes will X And Y, so the ParityEven is X, and the ParityOdd is Y
- const FbxAxisSystem::EFrontVector frontVector = FbxAxisSystem::eParityOdd;
- const FbxAxisSystem::ECoordSystem rightVector = FbxAxisSystem::eRightHanded;
- return FbxAxisSystem(upVector, frontVector, rightVector);
-}
-
-FbxSystemUnit FbxUtils::getBlastFBXUnit()
-{
- return FbxSystemUnit::cm;
-}
-
-std::string FbxUtils::FbxAxisSystemToString(const FbxAxisSystem& axisSystem)
-{
- std::stringstream ss;
- int upSign, frontSign;
- FbxAxisSystem::EUpVector upVector = axisSystem.GetUpVector(upSign);
- FbxAxisSystem::EFrontVector frontVector = axisSystem.GetFrontVector(frontSign);
- FbxAxisSystem::ECoordSystem coordSystem = axisSystem.GetCoorSystem();
- ss << "Predefined Type: ";
- if (axisSystem == FbxAxisSystem::MayaZUp)
- {
- ss << "MayaZUP";
- }
- else if (axisSystem == FbxAxisSystem::MayaYUp)
- {
- ss << "MayaYUp";
- }
- else if (axisSystem == FbxAxisSystem::Max)
- {
- ss << "Max";
- }
- else if (axisSystem == FbxAxisSystem::Motionbuilder)
- {
- ss << "Motionbuilder";
- }
- else if (axisSystem == FbxAxisSystem::OpenGL)
- {
- ss << "OpenGL";
- }
- else if (axisSystem == FbxAxisSystem::DirectX)
- {
- ss << "OpenGL";
- }
- else if (axisSystem == FbxAxisSystem::Lightwave)
- {
- ss << "OpenGL";
- }
- else
- {
- ss << "<Other>";
- }
- ss << " UpVector: " << (upSign > 0 ? "+" : "-");
- switch (upVector)
- {
- case FbxAxisSystem::eXAxis: ss << "eXAxis"; break;
- case FbxAxisSystem::eYAxis: ss << "eYAxis"; break;
- case FbxAxisSystem::eZAxis: ss << "eZAxis"; break;
- default: ss << "<unknown>"; break;
- }
-
- ss << " FrontVector: " << (frontSign > 0 ? "+" : "-");
- switch (frontVector)
- {
- case FbxAxisSystem::eParityEven: ss << "eParityEven"; break;
- case FbxAxisSystem::eParityOdd: ss << "eParityOdd"; break;
- default: ss << "<unknown>"; break;
- }
-
- ss << " CoordSystem: ";
- switch (coordSystem)
- {
- case FbxAxisSystem::eLeftHanded: ss << "eLeftHanded"; break;
- case FbxAxisSystem::eRightHanded: ss << "eRightHanded"; break;
- default: ss << "<unknown>"; break;
- }
-
- return ss.str();
-}
-
-std::string FbxUtils::FbxSystemUnitToString(const FbxSystemUnit& systemUnit)
-{
- return std::string(systemUnit.GetScaleFactorAsString());
-}
-
-const static std::string currentChunkPrefix = "chunk_";
-const static std::string oldChunkPrefix = "bone_";
-
-static uint32_t getChunkIndexForNodeInternal(const std::string& chunkPrefix, FbxNode* node, uint32_t* outParentChunkIndex /*=nullptr*/)
-{
- if (!node)
- {
- //Found nothing
- return UINT32_MAX;
- }
-
- std::string nodeName(node->GetNameOnly());
- for (char& c : nodeName)
- c = (char)std::tolower(c);
-
- if (nodeName.substr(0, chunkPrefix.size()) == chunkPrefix)
- {
- std::istringstream iss(nodeName.substr(chunkPrefix.size()));
- uint32_t ret = UINT32_MAX;
- iss >> ret;
- if (!iss.fail())
- {
- if (outParentChunkIndex)
- {
- *outParentChunkIndex = getChunkIndexForNodeInternal(chunkPrefix, node->GetParent(), nullptr);
- }
- return ret;
- }
- }
-
- return getChunkIndexForNodeInternal(chunkPrefix, node->GetParent(), outParentChunkIndex);
-}
-
-uint32_t FbxUtils::getChunkIndexForNode(FbxNode* node, uint32_t* outParentChunkIndex /*=nullptr*/)
-{
- return getChunkIndexForNodeInternal(currentChunkPrefix, node, outParentChunkIndex);
-}
-
-uint32_t FbxUtils::getChunkIndexForNodeBackwardsCompatible(FbxNode* node, uint32_t* outParentChunkIndex /*= nullptr*/)
-{
- return getChunkIndexForNodeInternal(oldChunkPrefix, node, outParentChunkIndex);
-}
-
-std::string FbxUtils::getChunkNodeName(uint32_t chunkIndex)
-{
- //This naming is required for the UE4 plugin to find them
- std::ostringstream namestream;
- namestream << currentChunkPrefix << chunkIndex;
- return namestream.str();
-}
-
-std::string FbxUtils::getCollisionGeometryLayerName()
-{
- return "Collision";
-}
-
-std::string FbxUtils::getRenderGeometryLayerName()
-{
- return "Render";
-}
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "fbxsdk.h"
+#include "NvBlastExtExporterFbxUtils.h"
+#include "PxVec3.h"
+#include "PxVec2.h"
+#include "NvBlastExtAuthoringTypes.h"
+#include <sstream>
+#include <cctype>
+
+using physx::PxVec3;
+using physx::PxVec2;
+
+
+void FbxUtils::VertexToFbx(const Nv::Blast::Vertex& vert, FbxVector4& outVertex, FbxVector4& outNormal, FbxVector2& outUV)
+{
+ PxVec3ToFbx(vert.p, outVertex);
+ PxVec3ToFbx(vert.n, outNormal);
+ PxVec2ToFbx(vert.uv[0], outUV);
+}
+
+void FbxUtils::PxVec3ToFbx(const physx::PxVec3& inVector, FbxVector4& outVector)
+{
+ outVector[0] = inVector.x;
+ outVector[1] = inVector.y;
+ outVector[2] = inVector.z;
+ outVector[3] = 0;
+}
+
+void FbxUtils::PxVec2ToFbx(const physx::PxVec2& inVector, FbxVector2& outVector)
+{
+ outVector[0] = inVector.x;
+ outVector[1] = inVector.y;
+}
+
+FbxAxisSystem FbxUtils::getBlastFBXAxisSystem()
+{
+ const FbxAxisSystem::EUpVector upVector = FbxAxisSystem::eZAxis;
+ //From the documentation: If the up axis is Z, the remain two axes will X And Y, so the ParityEven is X, and the ParityOdd is Y
+ const FbxAxisSystem::EFrontVector frontVector = FbxAxisSystem::eParityOdd;
+ const FbxAxisSystem::ECoordSystem rightVector = FbxAxisSystem::eRightHanded;
+ return FbxAxisSystem(upVector, frontVector, rightVector);
+}
+
+FbxSystemUnit FbxUtils::getBlastFBXUnit()
+{
+ return FbxSystemUnit::cm;
+}
+
+std::string FbxUtils::FbxAxisSystemToString(const FbxAxisSystem& axisSystem)
+{
+ std::stringstream ss;
+ int upSign, frontSign;
+ FbxAxisSystem::EUpVector upVector = axisSystem.GetUpVector(upSign);
+ FbxAxisSystem::EFrontVector frontVector = axisSystem.GetFrontVector(frontSign);
+ FbxAxisSystem::ECoordSystem coordSystem = axisSystem.GetCoorSystem();
+ ss << "Predefined Type: ";
+ if (axisSystem == FbxAxisSystem::MayaZUp)
+ {
+ ss << "MayaZUP";
+ }
+ else if (axisSystem == FbxAxisSystem::MayaYUp)
+ {
+ ss << "MayaYUp";
+ }
+ else if (axisSystem == FbxAxisSystem::Max)
+ {
+ ss << "Max";
+ }
+ else if (axisSystem == FbxAxisSystem::Motionbuilder)
+ {
+ ss << "Motionbuilder";
+ }
+ else if (axisSystem == FbxAxisSystem::OpenGL)
+ {
+ ss << "OpenGL";
+ }
+ else if (axisSystem == FbxAxisSystem::DirectX)
+ {
+ ss << "OpenGL";
+ }
+ else if (axisSystem == FbxAxisSystem::Lightwave)
+ {
+ ss << "OpenGL";
+ }
+ else
+ {
+ ss << "<Other>";
+ }
+ ss << " UpVector: " << (upSign > 0 ? "+" : "-");
+ switch (upVector)
+ {
+ case FbxAxisSystem::eXAxis: ss << "eXAxis"; break;
+ case FbxAxisSystem::eYAxis: ss << "eYAxis"; break;
+ case FbxAxisSystem::eZAxis: ss << "eZAxis"; break;
+ default: ss << "<unknown>"; break;
+ }
+
+ ss << " FrontVector: " << (frontSign > 0 ? "+" : "-");
+ switch (frontVector)
+ {
+ case FbxAxisSystem::eParityEven: ss << "eParityEven"; break;
+ case FbxAxisSystem::eParityOdd: ss << "eParityOdd"; break;
+ default: ss << "<unknown>"; break;
+ }
+
+ ss << " CoordSystem: ";
+ switch (coordSystem)
+ {
+ case FbxAxisSystem::eLeftHanded: ss << "eLeftHanded"; break;
+ case FbxAxisSystem::eRightHanded: ss << "eRightHanded"; break;
+ default: ss << "<unknown>"; break;
+ }
+
+ return ss.str();
+}
+
+std::string FbxUtils::FbxSystemUnitToString(const FbxSystemUnit& systemUnit)
+{
+ return std::string(systemUnit.GetScaleFactorAsString());
+}
+
+const static std::string currentChunkPrefix = "chunk_";
+const static std::string oldChunkPrefix = "bone_";
+
+static uint32_t getChunkIndexForNodeInternal(const std::string& chunkPrefix, FbxNode* node, uint32_t* outParentChunkIndex /*=nullptr*/)
+{
+ if (!node)
+ {
+ //Found nothing
+ return UINT32_MAX;
+ }
+
+ std::string nodeName(node->GetNameOnly());
+ for (char& c : nodeName)
+ c = (char)std::tolower(c);
+
+ if (nodeName.substr(0, chunkPrefix.size()) == chunkPrefix)
+ {
+ std::istringstream iss(nodeName.substr(chunkPrefix.size()));
+ uint32_t ret = UINT32_MAX;
+ iss >> ret;
+ if (!iss.fail())
+ {
+ if (outParentChunkIndex)
+ {
+ *outParentChunkIndex = getChunkIndexForNodeInternal(chunkPrefix, node->GetParent(), nullptr);
+ }
+ return ret;
+ }
+ }
+
+ return getChunkIndexForNodeInternal(chunkPrefix, node->GetParent(), outParentChunkIndex);
+}
+
+uint32_t FbxUtils::getChunkIndexForNode(FbxNode* node, uint32_t* outParentChunkIndex /*=nullptr*/)
+{
+ return getChunkIndexForNodeInternal(currentChunkPrefix, node, outParentChunkIndex);
+}
+
+uint32_t FbxUtils::getChunkIndexForNodeBackwardsCompatible(FbxNode* node, uint32_t* outParentChunkIndex /*= nullptr*/)
+{
+ return getChunkIndexForNodeInternal(oldChunkPrefix, node, outParentChunkIndex);
+}
+
+std::string FbxUtils::getChunkNodeName(uint32_t chunkIndex)
+{
+ //This naming is required for the UE4 plugin to find them
+ std::ostringstream namestream;
+ namestream << currentChunkPrefix << chunkIndex;
+ return namestream.str();
+}
+
+std::string FbxUtils::getCollisionGeometryLayerName()
+{
+ return "Collision";
+}
+
+std::string FbxUtils::getRenderGeometryLayerName()
+{
+ return "Render";
+}
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.h b/sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.h
index 47cedd7..431d63a 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.h
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterFbxUtils.h
@@ -1,69 +1,69 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#ifndef NVBLASTEXTEXPORTERFBXUTILS_H
-#define NVBLASTEXTEXPORTERFBXUTILS_H
-
-#include "fbxsdk.h"
-#include "PxVec3.h"
-#include "PxVec2.h"
-#include <string>
-
-namespace Nv
-{
- namespace Blast
- {
- struct Vertex;
- }
-}
-
-class FbxUtils
-{
-public:
- static void VertexToFbx(const Nv::Blast::Vertex& vert, FbxVector4& outVertex, FbxVector4& outNormal, FbxVector2& outUV);
-
- static void PxVec3ToFbx(const physx::PxVec3& inVector, FbxVector4& outVector);
- static void PxVec2ToFbx(const physx::PxVec2& inVector, FbxVector2& outVector);
-
- static FbxAxisSystem getBlastFBXAxisSystem();
- static FbxSystemUnit getBlastFBXUnit();
-
- static std::string FbxAxisSystemToString(const FbxAxisSystem& axisSystem);
- static std::string FbxSystemUnitToString(const FbxSystemUnit& systemUnit);
-
- //returns UINT32_MAX if not a chunk
- static uint32_t getChunkIndexForNode(FbxNode* node, uint32_t* outParentChunkIndex = nullptr);
- //Search using the old naming
- static uint32_t getChunkIndexForNodeBackwardsCompatible(FbxNode* node, uint32_t* outParentChunkIndex = nullptr);
- static std::string getChunkNodeName(uint32_t chunkIndex);
-
- static std::string getCollisionGeometryLayerName();
- static std::string getRenderGeometryLayerName();
-};
-
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTEXTEXPORTERFBXUTILS_H
+#define NVBLASTEXTEXPORTERFBXUTILS_H
+
+#include "fbxsdk.h"
+#include "PxVec3.h"
+#include "PxVec2.h"
+#include <string>
+
+namespace Nv
+{
+ namespace Blast
+ {
+ struct Vertex;
+ }
+}
+
+class FbxUtils
+{
+public:
+ static void VertexToFbx(const Nv::Blast::Vertex& vert, FbxVector4& outVertex, FbxVector4& outNormal, FbxVector2& outUV);
+
+ static void PxVec3ToFbx(const physx::PxVec3& inVector, FbxVector4& outVector);
+ static void PxVec2ToFbx(const physx::PxVec2& inVector, FbxVector2& outVector);
+
+ static FbxAxisSystem getBlastFBXAxisSystem();
+ static FbxSystemUnit getBlastFBXUnit();
+
+ static std::string FbxAxisSystemToString(const FbxAxisSystem& axisSystem);
+ static std::string FbxSystemUnitToString(const FbxSystemUnit& systemUnit);
+
+ //returns UINT32_MAX if not a chunk
+ static uint32_t getChunkIndexForNode(FbxNode* node, uint32_t* outParentChunkIndex = nullptr);
+ //Search using the old naming
+ static uint32_t getChunkIndexForNodeBackwardsCompatible(FbxNode* node, uint32_t* outParentChunkIndex = nullptr);
+ static std::string getChunkNodeName(uint32_t chunkIndex);
+
+ static std::string getCollisionGeometryLayerName();
+ static std::string getRenderGeometryLayerName();
+};
+
#endif //NVBLASTEXTEXPORTERFBXUTILS_H \ No newline at end of file
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.cpp b/sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.cpp
index c3c4b37..a0de9d5 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.cpp
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.cpp
@@ -1,1441 +1,1441 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "fbxsdk.h"
-#include <iostream>
-#include <sstream>
-#include <iomanip>
-#include <map>
-#include <algorithm>
-#include <set>
-#include "NvBlastTypes.h"
-#include "NvBlastGlobals.h"
-#include "NvBlastTkFramework.h"
-#include "NvBlast.h"
-#include "PxVec3.h"
-#include "NvBlastAssert.h"
-#include <unordered_set>
-#include <functional>
-#include "NvBlastExtExporterFbxWriter.h"
-#include "NvBlastExtExporterFbxUtils.h"
-#include "NvBlastExtAuthoringCollisionBuilder.h"
-#include "NvBlastExtAuthoring.h"
-#include "NvBlastExtAuthoringMesh.h"
-
-using namespace Nv::Blast;
-
-FbxFileWriter::FbxFileWriter():
- bOutputFBXAscii(false)
-{
- // Wrap in a shared ptr so that when it deallocates we get an auto destroy and all of the other assets created don't leak.
- sdkManager = std::shared_ptr<FbxManager>(FbxManager::Create(), [=](FbxManager* manager)
- {
- manager->Destroy();
- });
-
- mScene = FbxScene::Create(sdkManager.get(), "Export Scene");
-
- mScene->GetGlobalSettings().SetAxisSystem(FbxUtils::getBlastFBXAxisSystem());
- mScene->GetGlobalSettings().SetSystemUnit(FbxUtils::getBlastFBXUnit());
- mScene->GetGlobalSettings().SetOriginalUpAxis(FbxUtils::getBlastFBXAxisSystem());
- mScene->GetGlobalSettings().SetOriginalSystemUnit(FbxUtils::getBlastFBXUnit());
-
- //We don't actually check for membership in this layer, but it's useful to show and hide the geo to look at the collision geo
- mRenderLayer = FbxDisplayLayer::Create(mScene, FbxUtils::getRenderGeometryLayerName().c_str());
- mRenderLayer->Show.Set(true);
- mRenderLayer->Color.Set(FbxDouble3(0.0f, 1.0f, 0.0f));
-
- mInteriorIndex = -1;
-}
-
-void FbxFileWriter::release()
-{
- //sdkManager->Destroy();
- delete this;
-}
-
-FbxScene* FbxFileWriter::getScene()
-{
- return mScene;
-}
-
-
-void FbxFileWriter::createMaterials(const ExporterMeshData& aResult)
-{
- mMaterials.clear();
-
- for (uint32_t i = 0; i < aResult.submeshCount; ++i)
- {
- FbxSurfacePhong* material = FbxSurfacePhong::Create(sdkManager.get(), aResult.submeshMats[i].name);
- material->Diffuse.Set(FbxDouble3(float(rand()) / RAND_MAX , float(rand()) / RAND_MAX, float(rand()) / RAND_MAX));
- material->DiffuseFactor.Set(1.0);
- mMaterials.push_back(material);
- }
-}
-
-void FbxFileWriter::setInteriorIndex(int32_t index)
-{
- mInteriorIndex = index;
-}
-
-
-void FbxFileWriter::createMaterials(const AuthoringResult& aResult)
-{
- mMaterials.clear();
- for (uint32_t i = 0; i < aResult.materialCount; ++i)
- {
- FbxSurfacePhong* material = FbxSurfacePhong::Create(sdkManager.get(), aResult.materialNames[i]);
- material->Diffuse.Set(FbxDouble3(float(rand()) / RAND_MAX, float(rand()) / RAND_MAX, float(rand()) / RAND_MAX));
- material->DiffuseFactor.Set(1.0);
- mMaterials.push_back(material);
- }
- if (mMaterials.size() == 0)
- {
- FbxSurfacePhong* material = FbxSurfacePhong::Create(sdkManager.get(), "Base_mat");
- material->Diffuse.Set(FbxDouble3(0.3, 1.0, 0));
- material->DiffuseFactor.Set(1.0);
- mMaterials.push_back(material);
- }
- if (mInteriorIndex == -1) // No material setted. Create new one.
- {
- FbxSurfacePhong* interiorMat = FbxSurfacePhong::Create(sdkManager.get(), "Interior_Material");
- interiorMat->Diffuse.Set(FbxDouble3(1.0, 0.0, 0.5));
- interiorMat->DiffuseFactor.Set(1.0);
- mMaterials.push_back(interiorMat);
- }
- else
- {
- if (mInteriorIndex < 0) mInteriorIndex = 0;
- if (static_cast<size_t>(mInteriorIndex) >= mMaterials.size()) mInteriorIndex = 0;
- }
-
-}
-
-
-bool FbxFileWriter::appendMesh(const AuthoringResult& aResult, const char* assetName, bool nonSkinned)
-{
- createMaterials(aResult);
-
- if (nonSkinned)
- {
- return appendNonSkinnedMesh(aResult, assetName);
- }
- std::string meshName(assetName); meshName.append("_rendermesh");
-
- FbxMesh* mesh = FbxMesh::Create(sdkManager.get(), meshName.c_str());
-
- FbxGeometryElementNormal* geNormal = mesh->CreateElementNormal();
- geNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
- geNormal->SetReferenceMode(FbxGeometryElement::eDirect);
-
- FbxGeometryElementUV* geUV = mesh->CreateElementUV("diffuseElement");
- geUV->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
- geUV->SetReferenceMode(FbxGeometryElement::eDirect);
-
- FbxGeometryElementSmoothing* smElement = nullptr;
- size_t triangleCount = aResult.geometryOffset[aResult.chunkCount];
-
- for (size_t triangle = 0; triangle < triangleCount; triangle++)
- {
- if (aResult.geometry[triangle].smoothingGroup >= 0)
- {
- //Found a valid smoothing group
- smElement = mesh->CreateElementSmoothing();
- smElement->SetMappingMode(FbxGeometryElement::eByPolygon);
- smElement->SetReferenceMode(FbxGeometryElement::eDirect);
- break;
- }
- }
-
- mesh->InitControlPoints((int)triangleCount * 3);
-
-
- FbxNode* meshNode = FbxNode::Create(mScene, assetName);
- meshNode->SetNodeAttribute(mesh);
- meshNode->SetShadingMode(FbxNode::eTextureShading);
-
- mRenderLayer->AddMember(meshNode);
-
- for (uint32_t i = 0; i < mMaterials.size(); ++i)
- {
- meshNode->AddMaterial(mMaterials[i]);
- }
-
- FbxNode* lRootNode = mScene->GetRootNode();
-
- //In order for Maya to correctly convert the axis of a skinned model there must be a common root node between the skeleton and the model
- FbxNode* sceneRootNode = FbxNode::Create(sdkManager.get(), "sceneRoot");
- lRootNode->AddChild(sceneRootNode);
- sceneRootNode->AddChild(meshNode);
-
- //UE4 cannot hide the root bone, so add a dummy chunk so chunk0 is not the root
- FbxNode* skelRootNode = FbxNode::Create(sdkManager.get(), "root");
- FbxSkeleton* skelAttrib = FbxSkeleton::Create(sdkManager.get(), "SkelRootAttrib");
- skelAttrib->SetSkeletonType(FbxSkeleton::eRoot);
- skelRootNode->SetNodeAttribute(skelAttrib);
-
- sceneRootNode->AddChild(skelRootNode);
-
- FbxSkin* skin = FbxSkin::Create(sdkManager.get(), "Skin of the thing");
- skin->SetGeometry(mesh);
- mesh->AddDeformer(skin);
-
- // Add a material otherwise UE4 freaks out on import
-
- FbxGeometryElementMaterial* matElement = mesh->CreateElementMaterial();
- matElement->SetMappingMode(FbxGeometryElement::eByPolygon);
- matElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
-
- // Now walk the tree and create a skeleton with geometry at the same time
- // Find a "root" chunk and walk the tree from there.
- uint32_t chunkCount = NvBlastAssetGetChunkCount(aResult.asset, Nv::Blast::logLL);
- auto chunks = NvBlastAssetGetChunks(aResult.asset, Nv::Blast::logLL);
-
- uint32_t cpIdx = 0;
- for (uint32_t i = 0; i < chunkCount; i++)
- {
- auto& chunk = chunks[i];
-
- if (chunk.parentChunkIndex == UINT32_MAX)
- {
- uint32_t addedCps = createChunkRecursive(cpIdx, i, meshNode, skelRootNode, skin, aResult);
- cpIdx += addedCps;
- }
- }
-
- if (!smElement)
- {
- //If no smoothing groups, generate them
- generateSmoothingGroups(mesh, skin);
- }
-
- removeDuplicateControlPoints(mesh, skin);
-
- if (aResult.collisionHull != nullptr)
- {
- return appendCollisionMesh(chunkCount, aResult.collisionHullOffset, aResult.collisionHull, assetName);
- }
-
- return true;
-};
-
-
-bool FbxFileWriter::appendNonSkinnedMesh(const AuthoringResult& aResult, const char* assetName)
-{
- FbxNode* lRootNode = mScene->GetRootNode();
-
- //UE4 cannot hide the root bone, so add a dummy chunk so chunk0 is not the root
- FbxNode* skelRootNode = FbxNode::Create(sdkManager.get(), "root");
- //UE4 needs this to be a skeleton node, null node, or mesh node to get used
- FbxNull* nullAttr = FbxNull::Create(sdkManager.get(), "SkelRootAttrib");
- skelRootNode->SetNodeAttribute(nullAttr);
- lRootNode->AddChild(skelRootNode);
-
- // Now walk the tree and create a skeleton with geometry at the same time
- // Find a "root" chunk and walk the tree from there.
- uint32_t chunkCount = NvBlastAssetGetChunkCount(aResult.asset, Nv::Blast::logLL);
- auto chunks = NvBlastAssetGetChunks(aResult.asset, Nv::Blast::logLL);
-
- for (uint32_t i = 0; i < chunkCount; i++)
- {
- auto& chunk = chunks[i];
-
- if (chunk.parentChunkIndex == UINT32_MAX)
- {
- createChunkRecursiveNonSkinned(assetName, i, skelRootNode, mMaterials, aResult);
- }
- }
-
- if (aResult.collisionHull != nullptr)
- {
- return appendCollisionMesh(chunkCount, aResult.collisionHullOffset, aResult.collisionHull, assetName);
- }
-
- return true;
-}
-
-
-bool FbxFileWriter::appendNonSkinnedMesh(const ExporterMeshData& meshData, const char* assetName)
-{
- FbxNode* lRootNode = mScene->GetRootNode();
-
- //UE4 cannot hide the root bone, so add a dummy chunk so chunk0 is not the root
- FbxNode* skelRootNode = FbxNode::Create(sdkManager.get(), "root");
- //UE4 needs this to be a skeleton node, null node, or mesh node to get used
- FbxNull* nullAttr = FbxNull::Create(sdkManager.get(), "SkelRootAttrib");
- skelRootNode->SetNodeAttribute(nullAttr);
- lRootNode->AddChild(skelRootNode);
-
- // Now walk the tree and create a skeleton with geometry at the same time
- // Find a "root" chunk and walk the tree from there.
- uint32_t chunkCount = NvBlastAssetGetChunkCount(meshData.asset, Nv::Blast::logLL);
-
- auto chunks = NvBlastAssetGetChunks(meshData.asset, Nv::Blast::logLL);
-
- for (uint32_t i = 0; i < chunkCount; i++)
- {
- const NvBlastChunk* chunk = &chunks[i];
-
- if (chunk->parentChunkIndex == UINT32_MAX)
- {
- createChunkRecursiveNonSkinned("chunk", i, skelRootNode, mMaterials, meshData);
- }
- }
- if (meshData.hulls != nullptr)
- {
- return appendCollisionMesh(chunkCount, meshData.hullsOffsets, meshData.hulls, assetName);
- }
- return true;
-}
-
-bool FbxFileWriter::appendCollisionMesh(uint32_t meshCount, uint32_t* offsets, CollisionHull** hulls, const char* assetName)
-{
- FbxDisplayLayer* displayLayer = FbxDisplayLayer::Create(mScene, FbxUtils::getCollisionGeometryLayerName().c_str());
- //Hide by default
- displayLayer->Show.Set(false);
- displayLayer->Color.Set(FbxDouble3(0.0f, 0.0f, 1.0f));
-
- // Now walk the tree and create a skeleton with geometry at the same time
- // Find a "root" chunk and walk the tree from there.
-
- for (uint32_t i = 0; i < meshCount; i++)
- {
- auto findIt = chunkNodes.find(i);
- if (findIt == chunkNodes.end())
- {
- std::cerr << "Warning: No chunk node for chunk " << i << ". Ignoring collision geo" << std::endl;
- continue;
- }
- addCollisionHulls(i, displayLayer, findIt->second, offsets[i+1] - offsets[i], hulls + offsets[i]);
- }
- return true;
-}
-
-/*
- Recursive method that creates this chunk and all it's children.
-
- This creates a FbxNode with an FbxCluster, and all of the geometry for this chunk.
-
- Returns the number of added control points
-*/
-uint32_t FbxFileWriter::createChunkRecursive(uint32_t currentCpIdx, uint32_t chunkIndex, FbxNode *meshNode, FbxNode* parentNode, FbxSkin* skin, const AuthoringResult& aResult)
-{
-
- auto chunks = NvBlastAssetGetChunks(aResult.asset, Nv::Blast::logLL);
- const NvBlastChunk* chunk = &chunks[chunkIndex];
- physx::PxVec3 centroid = physx::PxVec3(chunk->centroid[0], chunk->centroid[1], chunk->centroid[2]);
-
- //mesh->InitTextureUV(triangles.size() * 3);
-
- std::string boneName = FbxUtils::getChunkNodeName(chunkIndex);
-
- FbxSkeleton* skelAttrib = FbxSkeleton::Create(sdkManager.get(), boneName.c_str());
- if (chunk->parentChunkIndex == UINT32_MAX)
- {
- skelAttrib->SetSkeletonType(FbxSkeleton::eRoot);
-
- // Change the centroid to origin
- centroid = physx::PxVec3(0.0f);
- }
- else
- {
- skelAttrib->SetSkeletonType(FbxSkeleton::eLimbNode);
- worldChunkPivots[chunkIndex] = centroid;
- }
-
- skelAttrib->Size.Set(1.0); // What's this for?
-
-
- FbxNode* boneNode = FbxNode::Create(sdkManager.get(), boneName.c_str());
- boneNode->SetNodeAttribute(skelAttrib);
-
- chunkNodes[chunkIndex] = boneNode;
-
- auto mat = parentNode->EvaluateGlobalTransform().Inverse();
-
- FbxVector4 vec(0, 0, 0, 0);
- FbxVector4 c2 = mat.MultT(vec);
-
- boneNode->LclTranslation.Set(c2);
-
- parentNode->AddChild(boneNode);
-
- std::ostringstream namestream;
- namestream << "cluster_" << std::setw(5) << std::setfill('0') << chunkIndex;
- std::string clusterName = namestream.str();
-
- FbxCluster* cluster = FbxCluster::Create(sdkManager.get(), clusterName.c_str());
- cluster->SetTransformMatrix(FbxAMatrix());
- cluster->SetLink(boneNode);
- cluster->SetLinkMode(FbxCluster::eTotalOne);
-
- skin->AddCluster(cluster);
-
- FbxMesh* mesh = static_cast<FbxMesh*>(meshNode->GetNodeAttribute());
-
- FbxVector4* controlPoints = mesh->GetControlPoints();
- auto geNormal = mesh->GetElementNormal();
- auto geUV = mesh->GetElementUV("diffuseElement");
- FbxGeometryElementMaterial* matElement = mesh->GetElementMaterial();
- FbxGeometryElementSmoothing* smElement = mesh->GetElementSmoothing();
-
- auto addVert = [&](Nv::Blast::Vertex vert, int controlPointIdx)
- {
- FbxVector4 vertex;
- FbxVector4 normal;
- FbxVector2 uv;
-
- FbxUtils::VertexToFbx(vert, vertex, normal, uv);
-
- controlPoints[controlPointIdx] = vertex;
- geNormal->GetDirectArray().Add(normal);
- geUV->GetDirectArray().Add(uv);
- // Add this control point to the bone with weight 1.0
- cluster->AddControlPointIndex(controlPointIdx, 1.0);
- };
-
- uint32_t cpIdx = 0;
- uint32_t polyCount = mesh->GetPolygonCount();
- for (uint32_t i = aResult.geometryOffset[chunkIndex]; i < aResult.geometryOffset[chunkIndex + 1]; i++)
- {
- Triangle& tri = aResult.geometry[i];
- addVert(tri.a, currentCpIdx + cpIdx + 0);
- addVert(tri.b, currentCpIdx + cpIdx + 1);
- addVert(tri.c, currentCpIdx + cpIdx + 2);
-
- mesh->BeginPolygon();
- mesh->AddPolygon(currentCpIdx + cpIdx + 0);
- mesh->AddPolygon(currentCpIdx + cpIdx + 1);
- mesh->AddPolygon(currentCpIdx + cpIdx + 2);
- mesh->EndPolygon();
- int32_t material = (tri.materialId != MATERIAL_INTERIOR) ? ((tri.materialId < int32_t(mMaterials.size())) ? tri.materialId : 0) : ((mInteriorIndex == -1) ? int32_t(mMaterials.size() - 1): mInteriorIndex);
- matElement->GetIndexArray().SetAt(polyCount, material);
- if (smElement)
- {
- if (tri.userData == 0)
- {
- smElement->GetDirectArray().Add(tri.smoothingGroup);
- }
- else
- {
- smElement->GetDirectArray().Add(SMOOTHING_GROUP_INTERIOR);
- }
- }
-
- polyCount++;
- cpIdx += 3;
- }
-
- mat = meshNode->EvaluateGlobalTransform();
- cluster->SetTransformMatrix(mat);
-
- mat = boneNode->EvaluateGlobalTransform();
- cluster->SetTransformLinkMatrix(mat);
-
- uint32_t addedCps = static_cast<uint32_t>((aResult.geometryOffset[chunkIndex + 1] - aResult.geometryOffset[chunkIndex]) * 3);
-
- for (uint32_t i = chunk->firstChildIndex; i < chunk->childIndexStop; i++)
- {
- addedCps += createChunkRecursive(currentCpIdx + addedCps, i, meshNode, boneNode, skin, aResult);
- }
-
- return addedCps;
-}
-
-
-void FbxFileWriter::createChunkRecursiveNonSkinned(const std::string& meshName, uint32_t chunkIndex, FbxNode* parentNode,
- const std::vector<FbxSurfaceMaterial*>& materials, const ExporterMeshData& meshData)
-{
- auto chunks = NvBlastAssetGetChunks(meshData.asset, Nv::Blast::logLL);
- const NvBlastChunk* chunk = &chunks[chunkIndex];
- physx::PxVec3 centroid = physx::PxVec3(chunk->centroid[0], chunk->centroid[1], chunk->centroid[2]);
-
- std::string chunkName = FbxUtils::getChunkNodeName(chunkIndex);
-
- FbxMesh* mesh = FbxMesh::Create(sdkManager.get(), (chunkName + "_mesh").c_str());
-
- FbxNode* meshNode = FbxNode::Create(mScene, chunkName.c_str());
- meshNode->SetNodeAttribute(mesh);
- meshNode->SetShadingMode(FbxNode::eTextureShading);
- mRenderLayer->AddMember(meshNode);
-
- chunkNodes[chunkIndex] = meshNode;
-
- auto mat = parentNode->EvaluateGlobalTransform().Inverse();
-
- FbxVector4 c2 = mat.MultT(FbxVector4(centroid.x, centroid.y, centroid.z, 1.0f));
- if (chunk->parentChunkIndex != UINT32_MAX)
- {
- //Don't mess with the root chunk pivot
- meshNode->LclTranslation.Set(c2);
- worldChunkPivots[chunkIndex] = centroid;
- }
-
- parentNode->AddChild(meshNode);
- FbxAMatrix finalXForm = meshNode->EvaluateGlobalTransform();
-
- //Set the geo transform to inverse so we can use the world mesh coordinates
- FbxAMatrix invFinalXForm = finalXForm.Inverse();
- meshNode->SetGeometricTranslation(FbxNode::eSourcePivot, invFinalXForm.GetT());
- meshNode->SetGeometricRotation(FbxNode::eSourcePivot, invFinalXForm.GetR());
- meshNode->SetGeometricScaling(FbxNode::eSourcePivot, invFinalXForm.GetS());
-
- auto geNormal = mesh->CreateElementNormal();
- auto geUV = mesh->CreateElementUV("diffuseElement");
- auto matr = mesh->CreateElementMaterial();
-
- uint32_t* firstIdx = meshData.submeshOffsets + chunkIndex * meshData.submeshCount;
- uint32_t* lastIdx = meshData.submeshOffsets + (chunkIndex + 1) * meshData.submeshCount;
- uint32_t cpCount = *lastIdx - *firstIdx;
- mesh->InitControlPoints(cpCount);
-
- geNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
- geNormal->SetReferenceMode(FbxGeometryElement::eDirect);
-
- geUV->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
- geUV->SetReferenceMode(FbxGeometryElement::eDirect);
-
- matr->SetMappingMode(FbxGeometryElement::eByPolygon);
- matr->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
-
- for (auto m : materials)
- {
- meshNode->AddMaterial(m);
- }
-
- uint32_t cPolygCount = 0;
- int32_t addedVertices = 0;
-
- for (uint32_t subMesh = 0; subMesh < meshData.submeshCount; ++subMesh)
- {
- for (uint32_t tr = *(firstIdx + subMesh); tr < *(firstIdx + subMesh + 1); tr += 3)
- {
- mesh->BeginPolygon(subMesh);
- for (uint32_t k = 0; k < 3; ++k)
- {
- mesh->AddPolygon(tr - *firstIdx + k);
-
- FbxVector4 temp;
- FbxUtils::PxVec3ToFbx(meshData.positions[meshData.posIndex[tr + k]], temp);
- mesh->SetControlPointAt(temp, tr - *firstIdx + k);
-
- FbxUtils::PxVec3ToFbx(meshData.normals[meshData.normIndex[tr + k]], temp);
- geNormal->GetDirectArray().Add(temp);
-
- FbxVector2 temp2;
- FbxUtils::PxVec2ToFbx(meshData.uvs[meshData.texIndex[tr + k]], temp2);
- geUV->GetDirectArray().Add(temp2);
- }
- mesh->EndPolygon();
- cPolygCount++;
- addedVertices += 3;
- }
- }
-
- if (!mesh->GetElementSmoothing())
- {
- //If no smoothing groups, generate them
- generateSmoothingGroups(mesh, nullptr);
- }
-
- removeDuplicateControlPoints(mesh, nullptr);
-
- for (uint32_t i = chunk->firstChildIndex; i < chunk->childIndexStop; i++)
- {
- createChunkRecursiveNonSkinned(meshName, i, meshNode, materials, meshData);
- }
-}
-
-
-void FbxFileWriter::createChunkRecursiveNonSkinned(const std::string& meshName, uint32_t chunkIndex, FbxNode* parentNode, const std::vector<FbxSurfaceMaterial*>& materials, const AuthoringResult& aResult)
-{
- auto chunks = NvBlastAssetGetChunks(aResult.asset, Nv::Blast::logLL);
- const NvBlastChunk* chunk = &chunks[chunkIndex];
- physx::PxVec3 centroid = physx::PxVec3(chunk->centroid[0], chunk->centroid[1], chunk->centroid[2]);
-
- std::string chunkName = FbxUtils::getChunkNodeName(chunkIndex).c_str();
-
- FbxMesh* mesh = FbxMesh::Create(sdkManager.get(), (chunkName + "_mesh").c_str());
-
- FbxNode* meshNode = FbxNode::Create(mScene, chunkName.c_str());
- meshNode->SetNodeAttribute(mesh);
- meshNode->SetShadingMode(FbxNode::eTextureShading);
- mRenderLayer->AddMember(meshNode);
-
- chunkNodes[chunkIndex] = meshNode;
-
- auto mat = parentNode->EvaluateGlobalTransform().Inverse();
-
- FbxVector4 c2 = mat.MultT(FbxVector4(centroid.x, centroid.y, centroid.z, 1.0f));
-
- if (chunk->parentChunkIndex != UINT32_MAX)
- {
- //Don't mess with the root chunk pivot
- meshNode->LclTranslation.Set(c2);
- worldChunkPivots[chunkIndex] = centroid;
- }
-
- parentNode->AddChild(meshNode);
- FbxAMatrix finalXForm = meshNode->EvaluateGlobalTransform();
-
- //Set the geo transform to inverse so we can use the world mesh coordinates
- FbxAMatrix invFinalXForm = finalXForm.Inverse();
- meshNode->SetGeometricTranslation(FbxNode::eSourcePivot, invFinalXForm.GetT());
- meshNode->SetGeometricRotation(FbxNode::eSourcePivot, invFinalXForm.GetR());
- meshNode->SetGeometricScaling(FbxNode::eSourcePivot, invFinalXForm.GetS());
-
-
- auto geNormal = mesh->CreateElementNormal();
- auto geUV = mesh->CreateElementUV("diffuseElement");
- auto matr = mesh->CreateElementMaterial();
-
- uint32_t firstIdx = aResult.geometryOffset[chunkIndex];
- uint32_t lastIdx = aResult.geometryOffset[chunkIndex + 1];
-
- FbxGeometryElementSmoothing* smElement = nullptr;
- for (uint32_t triangle = firstIdx; triangle < lastIdx; triangle++)
- {
- if (aResult.geometry[triangle].smoothingGroup >= 0)
- {
- //Found a valid smoothing group
- smElement = mesh->CreateElementSmoothing();
- smElement->SetMappingMode(FbxGeometryElement::eByPolygon);
- smElement->SetReferenceMode(FbxGeometryElement::eDirect);
- break;
- }
- }
-
- mesh->InitControlPoints((int)(lastIdx - firstIdx) * 3);
-
- geNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
- geNormal->SetReferenceMode(FbxGeometryElement::eDirect);
-
- geUV->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
- geUV->SetReferenceMode(FbxGeometryElement::eDirect);
-
- matr->SetMappingMode(FbxGeometryElement::eByPolygon);
- matr->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
-
- for (auto m : materials)
- {
- meshNode->AddMaterial(m);
- }
-
- FbxGeometryElementMaterial* matElement = mesh->GetElementMaterial();
- int32_t polyCount = 0;
- for (uint32_t tr = firstIdx; tr < lastIdx; tr++)
- {
- auto& geo = aResult.geometry[tr];
- const Nv::Blast::Vertex triVerts[3] = { geo.a, geo.b, geo.c };
- mesh->BeginPolygon();
- for (uint32_t k = 0; k < 3; ++k)
- {
- mesh->AddPolygon(tr * 3 + k);
- FbxVector4 v, n;
- FbxVector2 uv;
- FbxUtils::VertexToFbx(triVerts[k], v, n, uv);
- mesh->SetControlPointAt(v, tr * 3 + k);
-
- geNormal->GetDirectArray().Add(n);
- geUV->GetDirectArray().Add(uv);
- }
- mesh->EndPolygon();
- int32_t material = (geo.materialId != MATERIAL_INTERIOR) ? ((geo.materialId < int32_t(mMaterials.size()))? geo.materialId : 0) : ((mInteriorIndex == -1)? int32_t(mMaterials.size() - 1) : mInteriorIndex);
- matElement->GetIndexArray().SetAt(polyCount, material);
-
- if (smElement)
- {
- if (geo.userData == 0)
- {
- smElement->GetDirectArray().Add(geo.smoothingGroup);
- }
- else
- {
- smElement->GetDirectArray().Add(SMOOTHING_GROUP_INTERIOR);
- }
- }
-
- polyCount++;
-
- }
-
- if (!smElement)
- {
- //If no smoothing groups, generate them
- generateSmoothingGroups(mesh, nullptr);
-
- }
-
- removeDuplicateControlPoints(mesh, nullptr);
-
- for (uint32_t i = chunk->firstChildIndex; i < chunk->childIndexStop; i++)
- {
- createChunkRecursiveNonSkinned(meshName, i, meshNode, materials, aResult);
- }
-}
-
-uint32_t FbxFileWriter::addCollisionHulls(uint32_t chunkIndex, FbxDisplayLayer* displayLayer, FbxNode* parentNode, uint32_t hullsCount, CollisionHull** hulls)
-{
- for (uint32_t hullId = 0; hullId < hullsCount; ++hullId)
- {
- std::stringstream namestream;
- namestream.clear();
- namestream << "collisionHull_" << chunkIndex << "_" << hullId;
-
- FbxNode* collisionNode = FbxNode::Create(sdkManager.get(), namestream.str().c_str());
-
- displayLayer->AddMember(collisionNode);
-
- //TODO: Remove this when tools are converted over
- FbxProperty::Create(collisionNode, FbxIntDT, "ParentalChunkIndex");
- collisionNode->FindProperty("ParentalChunkIndex").Set(chunkIndex);
- //
-
- namestream.clear();
- namestream << "collisionHullGeom_" << chunkIndex << "_" << hullId;
- FbxMesh* meshAttr = FbxMesh::Create(sdkManager.get(), namestream.str().c_str());
- collisionNode->SetNodeAttribute(meshAttr);
- parentNode->AddChild(collisionNode);
-
- auto mat = parentNode->EvaluateGlobalTransform().Inverse();
- auto centroid = worldChunkPivots.find(chunkIndex);
-
- if (centroid != worldChunkPivots.end())
- {
- FbxVector4 c2 = mat.MultT(FbxVector4(centroid->second.x, centroid->second.y, centroid->second.z, 1.0f));
- //Don't mess with the root chunk pivot
- collisionNode->LclTranslation.Set(c2);
- }
- parentNode->AddChild(collisionNode);
- FbxAMatrix finalXForm = collisionNode->EvaluateGlobalTransform();
-
- //Set the geo transform to inverse so we can use the world mesh coordinates
- FbxAMatrix invFinalXForm = finalXForm.Inverse();
- collisionNode->SetGeometricTranslation(FbxNode::eSourcePivot, invFinalXForm.GetT());
- collisionNode->SetGeometricRotation(FbxNode::eSourcePivot, invFinalXForm.GetR());
- collisionNode->SetGeometricScaling(FbxNode::eSourcePivot, invFinalXForm.GetS());
-
-
- meshAttr->InitControlPoints(hulls[hullId]->pointsCount);
- meshAttr->CreateElementNormal();
- FbxVector4* controlPoints = meshAttr->GetControlPoints();
- auto geNormal = meshAttr->GetElementNormal();
- geNormal->SetMappingMode(FbxGeometryElement::eByPolygon);
- geNormal->SetReferenceMode(FbxGeometryElement::eDirect);
- for (uint32_t i = 0; i < hulls[hullId]->pointsCount; ++i)
- {
- auto& pnts = hulls[hullId]->points[i];
- controlPoints->Set(pnts.x, pnts.y, pnts.z, 0.0);
- controlPoints++;
- }
-
- for (uint32_t i = 0; i < hulls[hullId]->polygonDataCount; ++i)
- {
- auto& poly = hulls[hullId]->polygonData[i];
- meshAttr->BeginPolygon();
- for (uint32_t j = 0; j < poly.mNbVerts; ++j)
- {
- meshAttr->AddPolygon(hulls[hullId]->indices[poly.mIndexBase + j]);
- }
- meshAttr->EndPolygon();
- FbxVector4 plane(poly.mPlane[0], poly.mPlane[1], poly.mPlane[2], 0);
- geNormal->GetDirectArray().Add(plane);
- }
- }
- return 1;
-}
-
-uint32_t FbxFileWriter::createChunkRecursive(uint32_t currentCpIdx, uint32_t chunkIndex, FbxNode *meshNode, FbxNode* parentNode, FbxSkin* skin, const ExporterMeshData& meshData)
-{
- auto chunks = NvBlastAssetGetChunks(meshData.asset, Nv::Blast::logLL);
- const NvBlastChunk* chunk = &chunks[chunkIndex];
- physx::PxVec3 centroid = physx::PxVec3(chunk->centroid[0], chunk->centroid[1], chunk->centroid[2]);
-
- std::string boneName = FbxUtils::getChunkNodeName(chunkIndex).c_str();
-
- FbxSkeleton* skelAttrib = FbxSkeleton::Create(sdkManager.get(), boneName.c_str());
- if (chunk->parentChunkIndex == UINT32_MAX)
- {
- skelAttrib->SetSkeletonType(FbxSkeleton::eRoot);
-
- // Change the centroid to origin
- centroid = physx::PxVec3(0.0f);
- }
- else
- {
- skelAttrib->SetSkeletonType(FbxSkeleton::eLimbNode);
- worldChunkPivots[chunkIndex] = centroid;
- }
-
- FbxNode* boneNode = FbxNode::Create(sdkManager.get(), boneName.c_str());
- boneNode->SetNodeAttribute(skelAttrib);
-
- chunkNodes[chunkIndex] = boneNode;
-
- auto mat = parentNode->EvaluateGlobalTransform().Inverse();
-
- FbxVector4 vec(0, 0, 0, 0);
- FbxVector4 c2 = mat.MultT(vec);
-
- boneNode->LclTranslation.Set(c2);
-
- parentNode->AddChild(boneNode);
-
- std::ostringstream namestream;
- namestream << "cluster_" << std::setw(5) << std::setfill('0') << chunkIndex;
- std::string clusterName = namestream.str();
-
- FbxCluster* cluster = FbxCluster::Create(sdkManager.get(), clusterName.c_str());
- cluster->SetTransformMatrix(FbxAMatrix());
- cluster->SetLink(boneNode);
- cluster->SetLinkMode(FbxCluster::eTotalOne);
-
- skin->AddCluster(cluster);
-
- FbxMesh* mesh = static_cast<FbxMesh*>(meshNode->GetNodeAttribute());
-
- auto geNormal = mesh->GetElementNormal();
- auto geUV = mesh->GetElementUV("diffuseElement");
- auto matr = mesh->GetElementMaterial();
-
- std::vector<bool> addedVerticesFlag(mesh->GetControlPointsCount(), false);
-
- uint32_t* firstIdx = meshData.submeshOffsets + chunkIndex * meshData.submeshCount;
- uint32_t cPolygCount = mesh->GetPolygonCount();
- int32_t addedVertices = 0;
- for (uint32_t subMesh = 0; subMesh < meshData.submeshCount; ++subMesh)
- {
- for (uint32_t tr = *(firstIdx + subMesh); tr < *(firstIdx + subMesh + 1); tr += 3)
- {
- mesh->BeginPolygon(subMesh);
- mesh->AddPolygon(meshData.posIndex[tr + 0]);
- mesh->AddPolygon(meshData.posIndex[tr + 1]);
- mesh->AddPolygon(meshData.posIndex[tr + 2]);
- mesh->EndPolygon();
- for (uint32_t k = 0; k < 3; ++k)
- {
- geNormal->GetIndexArray().SetAt(currentCpIdx + addedVertices + k, meshData.normIndex[tr + k]);
- geUV->GetIndexArray().SetAt(currentCpIdx + addedVertices + k, meshData.texIndex[tr + k]);
- }
- if (subMesh == 0)
- {
- matr->GetIndexArray().SetAt(cPolygCount, 0);
- }
- else
- {
- matr->GetIndexArray().SetAt(cPolygCount, 1);
- }
- cPolygCount++;
- addedVertices += 3;
- for (uint32_t k = 0; k < 3; ++k)
- {
- if (!addedVerticesFlag[meshData.posIndex[tr + k]])
- {
- cluster->AddControlPointIndex(meshData.posIndex[tr + k], 1.0);
- addedVerticesFlag[meshData.posIndex[tr + k]] = true;
- }
- }
- }
- }
- mat = meshNode->EvaluateGlobalTransform();
- cluster->SetTransformMatrix(mat);
-
- mat = boneNode->EvaluateGlobalTransform();
- cluster->SetTransformLinkMatrix(mat);
-
-
- for (uint32_t i = chunk->firstChildIndex; i < chunk->childIndexStop; i++)
- {
- addedVertices += createChunkRecursive(currentCpIdx + addedVertices, i, meshNode, boneNode, skin, meshData);
- }
-
- return addedVertices;
-
-}
-
-void FbxFileWriter::addControlPoints(FbxMesh* mesh, const ExporterMeshData& meshData)
-{
- std::vector<uint32_t> vertices;
- std::cout << "Adding control points" << std::endl;
- std::vector<int32_t> mapping(meshData.positionsCount, -1);
- for (uint32_t ch = 0; ch < meshData.meshCount; ++ch)
- {
- mapping.assign(meshData.positionsCount, -1);
- for (uint32_t sb = 0; sb < meshData.submeshCount; ++sb)
- {
- uint32_t* first = meshData.submeshOffsets + ch * meshData.submeshCount + sb;
- for (uint32_t pi = *first; pi < *(first+1); ++pi)
- {
- uint32_t p = meshData.posIndex[pi];
- if (mapping[p] == -1)
- {
- mapping[p] = (int)vertices.size();
- vertices.push_back(p);
- meshData.posIndex[pi] = mapping[p];
- }
- else
- {
- meshData.posIndex[pi] = mapping[p];
- }
- }
- }
- }
- mesh->InitControlPoints((int)vertices.size());
- FbxVector4* controlPoints = mesh->GetControlPoints();
- for (auto v : vertices)
- {
- auto& p = meshData.positions[v];
- *controlPoints = FbxVector4(p.x, p.y, p.z, 0);
- ++controlPoints;
- }
- std::cout << "Adding control points: done" << std::endl;
-}
-
-void FbxFileWriter::addBindPose()
-{
- // Store the bind pose
- //Just add all the nodes, it doesn't seem to do any harm and it stops Maya complaining about incomplete bind poses
- FbxPose* pose = FbxPose::Create(sdkManager.get(), "BindPose");
- pose->SetIsBindPose(true);
-
- int nodeCount = mScene->GetNodeCount();
- for (int i = 0; i < nodeCount; i++)
- {
- FbxNode* node = mScene->GetNode(i);
- FbxMatrix bindMat = node->EvaluateGlobalTransform();
-
- pose->Add(node, bindMat);
- }
-
- mScene->AddPose(pose);
-}
-
-bool FbxFileWriter::saveToFile(const char* assetName, const char* outputPath)
-{
-
- addBindPose();
-
- FbxIOSettings* ios = FbxIOSettings::Create(sdkManager.get(), IOSROOT);
- // Set some properties on the io settings
-
- sdkManager->SetIOSettings(ios);
-
- sdkManager->GetIOSettings()->SetBoolProp(EXP_ASCIIFBX, bOutputFBXAscii);
-
-
- FbxExporter* exporter = FbxExporter::Create(sdkManager.get(), "Scene Exporter");
- exporter->SetFileExportVersion(FBX_2012_00_COMPATIBLE);
-
- int lFormat;
-
- if (bOutputFBXAscii)
- {
- lFormat = sdkManager->GetIOPluginRegistry()->FindWriterIDByDescription("FBX ascii (*.fbx)");
- }
- else
- {
- lFormat = sdkManager->GetIOPluginRegistry()->FindWriterIDByDescription("FBX binary (*.fbx)");
- }
-
- auto path = std::string(outputPath) + "\\" + assetName + ".fbx";
- bool exportStatus = exporter->Initialize(path.c_str(), lFormat, sdkManager->GetIOSettings());
-
- if (!exportStatus)
- {
- std::cerr << "Call to FbxExporter::Initialize failed" << std::endl;
- std::cerr << "Error returned: " << exporter->GetStatus().GetErrorString() << std::endl;
- return false;
- }
-
- exportStatus = exporter->Export(mScene);
-
- if (!exportStatus)
- {
- auto fbxStatus = exporter->GetStatus();
-
- std::cerr << "Call to FbxExporter::Export failed" << std::endl;
- std::cerr << "Error returned: " << fbxStatus.GetErrorString() << std::endl;
- return false;
- }
- return true;
-}
-
-
-
-bool FbxFileWriter::appendMesh(const ExporterMeshData& meshData, const char* assetName, bool nonSkinned)
-{
- createMaterials(meshData);
-
- if (nonSkinned)
- {
- return appendNonSkinnedMesh(meshData, assetName);
- }
-
- /**
- Get polygon count
- */
- uint32_t polygCount = meshData.submeshOffsets[meshData.meshCount * meshData.submeshCount] / 3;
-
- FbxMesh* mesh = FbxMesh::Create(sdkManager.get(), "meshgeo");
-
- FbxGeometryElementNormal* geNormal = mesh->CreateElementNormal();
- geNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
- geNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
-
- FbxGeometryElementUV* geUV = mesh->CreateElementUV("diffuseElement");
- geUV->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
- geUV->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
-
-
- FbxNode* meshNode = FbxNode::Create(mScene, "meshnode");
- meshNode->SetNodeAttribute(mesh);
- meshNode->SetShadingMode(FbxNode::eTextureShading);
-
- FbxNode* lRootNode = mScene->GetRootNode();
-
- mRenderLayer->AddMember(meshNode);
-
- for (uint32_t i = 0; i < mMaterials.size(); ++i)
- {
- meshNode->AddMaterial(mMaterials[i]);
- }
-
- FbxSkin* skin = FbxSkin::Create(sdkManager.get(), "Skin of the thing");
- skin->SetGeometry(mesh);
-
- mesh->AddDeformer(skin);
-
- /**
- Create control points, copy data to buffers
- */
- addControlPoints(mesh, meshData);
-
- auto normalsElem = mesh->GetElementNormal();
- for (uint32_t i = 0; i < meshData.normalsCount; ++i)
- {
- auto& n = meshData.normals[i];
- normalsElem->GetDirectArray().Add(FbxVector4(n.x, n.y, n.z, 0));
- }
- auto uvsElem = mesh->GetElementUV("diffuseElement");
- for (uint32_t i = 0; i < meshData.uvsCount; ++i)
- {
- auto& uvs = meshData.uvs[i];
- uvsElem->GetDirectArray().Add(FbxVector2(uvs.x, uvs.y));
- }
-
- FbxGeometryElementMaterial* matElement = mesh->CreateElementMaterial();
- matElement->SetMappingMode(FbxGeometryElement::eByPolygon);
- matElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
-
-
- matElement->GetIndexArray().SetCount(polygCount);
- normalsElem->GetIndexArray().SetCount(polygCount * 3);
- uvsElem->GetIndexArray().SetCount(polygCount * 3);
-
-
- std::cout << "Create chunks recursive" << std::endl;
-
- //In order for Maya to correctly convert the axis of a skinned model there must be a common root node between the skeleton and the model
- FbxNode* sceneRootNode = FbxNode::Create(sdkManager.get(), "sceneRoot");
- lRootNode->AddChild(sceneRootNode);
- sceneRootNode->AddChild(meshNode);
-
- //UE4 cannot hide the root bone, so add a dummy chunk so chunk0 is not the root
- FbxNode* skelRootNode = FbxNode::Create(sdkManager.get(), "root");
- FbxSkeleton* skelAttrib = FbxSkeleton::Create(sdkManager.get(), "SkelRootAttrib");
- skelAttrib->SetSkeletonType(FbxSkeleton::eRoot);
- skelRootNode->SetNodeAttribute(skelAttrib);
-
- sceneRootNode->AddChild(skelRootNode);
-
- // Now walk the tree and create a skeleton with geometry at the same time
- // Find a "root" chunk and walk the tree from there.
- uint32_t chunkCount = NvBlastAssetGetChunkCount(meshData.asset, Nv::Blast::logLL);
- auto chunks = NvBlastAssetGetChunks(meshData.asset, Nv::Blast::logLL);
- uint32_t cpIdx = 0;
- for (uint32_t i = 0; i < chunkCount; i++)
- {
- const NvBlastChunk* chunk = &chunks[i];
-
- if (chunk->parentChunkIndex == UINT32_MAX)
- {
- uint32_t addedCps = createChunkRecursive(cpIdx, i, meshNode, skelRootNode, skin, meshData);
- cpIdx += addedCps;
- }
- }
-
- if (!mesh->GetElementSmoothing())
- {
- //If no smoothing groups, generate them
- generateSmoothingGroups(mesh, skin);
- }
-
- removeDuplicateControlPoints(mesh, skin);
-
- if (meshData.hulls != nullptr)
- {
- return appendCollisionMesh(chunkCount, meshData.hullsOffsets, meshData.hulls, assetName);
- }
- return true;
-}
-
-void FbxFileWriter::generateSmoothingGroups(fbxsdk::FbxMesh* mesh, FbxSkin* skin)
-{
- if (mesh->GetElementSmoothing(0) || !mesh->IsTriangleMesh())
- {
- //they already exist or we can't make it
- return;
- }
-
- const FbxGeometryElementNormal* geNormal = mesh->GetElementNormal();
- if (!geNormal || geNormal->GetMappingMode() != FbxGeometryElement::eByPolygonVertex || geNormal->GetReferenceMode() != FbxGeometryElement::eDirect)
- {
- //We just set this up, but just incase
- return;
- }
-
- int clusterCount = 0;
- std::vector<std::vector<int>> cpsPerCluster;
- if (skin)
- {
- clusterCount = skin->GetClusterCount();
- cpsPerCluster.resize(clusterCount);
- for (int c = 0; c < clusterCount; c++)
- {
- FbxCluster* cluster = skin->GetCluster(c);
- int* clusterCPList = cluster->GetControlPointIndices();
- const int clusterCPListLength = cluster->GetControlPointIndicesCount();
-
- cpsPerCluster[c].resize(clusterCPListLength);
- memcpy(cpsPerCluster[c].data(), clusterCPList, sizeof(int) * clusterCPListLength);
- std::sort(cpsPerCluster[c].begin(), cpsPerCluster[c].end());
- }
- }
-
- auto smElement = mesh->CreateElementSmoothing();
- smElement->SetMappingMode(FbxGeometryElement::eByPolygon);
- smElement->SetReferenceMode(FbxGeometryElement::eDirect);
-
- FbxVector4* cpList = mesh->GetControlPoints();
- const int cpCount = mesh->GetControlPointsCount();
-
- const int triangleCount = mesh->GetPolygonCount();
- const int cornerCount = triangleCount * 3;
-
- int* polygonCPList = mesh->GetPolygonVertices();
- const auto& normalByCornerList = geNormal->GetDirectArray();
-
- std::multimap<int, int> overlappingCorners;
- //sort them by z for faster overlap checking
- std::vector<std::pair<double, int>> cornerIndexesByZ(cornerCount);
- for (int c = 0; c < cornerCount; c++)
- {
- cornerIndexesByZ[c] = std::pair<double, int>(cpList[polygonCPList[c]][2], c);
- }
- std::sort(cornerIndexesByZ.begin(), cornerIndexesByZ.end());
-
- for (int i = 0; i < cornerCount; i++)
- {
- const int cornerA = cornerIndexesByZ[i].second;
- const int cpiA = polygonCPList[cornerA];
- FbxVector4 cpA = cpList[cpiA];
- cpA[3] = 0;
-
- int clusterIndexA = -1;
- for (int c = 0; c < clusterCount; c++)
- {
- if (std::binary_search(cpsPerCluster[c].begin(), cpsPerCluster[c].end(), cpiA))
- {
- clusterIndexA = c;
- break;
- }
- }
-
- for (int j = i + 1; j < cornerCount; j++)
- {
- if (std::abs(cornerIndexesByZ[j].first - cornerIndexesByZ[i].first) > FBXSDK_TOLERANCE)
- {
- break; // if the z's don't match other values don't matter
- }
- const int cornerB = cornerIndexesByZ[j].second;
- const int cpiB = polygonCPList[cornerB];
- FbxVector4 cpB = cpList[cpiB];
-
- cpB[3] = 0;
-
- //uses FBXSDK_TOLERANCE
- if (cpA == cpB)
- {
- int clusterIndexB = -1;
- for (int c = 0; c < clusterCount; c++)
- {
- if (std::binary_search(cpsPerCluster[c].begin(), cpsPerCluster[c].end(), cpiB))
- {
- clusterIndexB = c;
- break;
- }
- }
-
- if (clusterIndexA == clusterIndexB)
- {
- overlappingCorners.emplace(cornerA, cornerB);
- overlappingCorners.emplace(cornerB, cornerA);
- }
- }
- }
- }
-
- auto& smoothingGroupByTri = smElement->GetDirectArray();
- for (int i = 0; i < triangleCount; i++)
- {
- smoothingGroupByTri.Add(0);
- }
- //first one
- smoothingGroupByTri.SetAt(0, 1);
-
- for (int i = 1; i < triangleCount; i++)
- {
- int sharedMask = 0, unsharedMask = 0;
- for (int c = 0; c < 3; c++)
- {
- int myCorner = i * 3 + c;
- FbxVector4 myNormal = normalByCornerList.GetAt(myCorner);
- myNormal.Normalize();
- myNormal[3] = 0;
-
- auto otherCornersRangeBegin = overlappingCorners.lower_bound(myCorner);
- auto otherCornersRangeEnd = overlappingCorners.upper_bound(myCorner);
- for (auto it = otherCornersRangeBegin; it != otherCornersRangeEnd; it++)
- {
- int otherCorner = it->second;
- FbxVector4 otherNormal = normalByCornerList.GetAt(otherCorner);
- otherNormal.Normalize();
- otherNormal[3] = 0;
- if (otherNormal == myNormal)
- {
- sharedMask |= smoothingGroupByTri[otherCorner / 3];
- }
- else
- {
- unsharedMask |= smoothingGroupByTri[otherCorner / 3];
- }
- }
- }
-
- //Easy case, no overlap
- if ((sharedMask & unsharedMask) == 0 && sharedMask != 0)
- {
- smoothingGroupByTri.SetAt(i, sharedMask);
- }
- else
- {
- for (int sm = 0; sm < 32; sm++)
- {
- int val = 1 << sm;
- if (((val & sharedMask) == sharedMask) && !(val & unsharedMask))
- {
- smoothingGroupByTri.SetAt(i, val);
- break;
- }
- }
- }
- }
-
-}
-
-namespace
-{
- //These methods have different names for some reason
- inline double* getControlPointBlendWeights(FbxSkin* skin)
- {
- return skin->GetControlPointBlendWeights();
- }
-
- inline double* getControlPointBlendWeights(FbxCluster* cluster)
- {
- return cluster->GetControlPointWeights();
- }
-
- template <typename T>
- void remapCPsAndRemoveDuplicates(const int newCPCount, const std::vector<int>& oldToNewCPMapping, T* skinOrCluster)
- {
- //Need to avoid duplicate entires since UE doesn't seem to normalize this correctly
- std::vector<bool> addedCP(newCPCount, false);
- std::vector<std::pair<int, double>> newCPsAndWeights;
- newCPsAndWeights.reserve(newCPCount);
-
- int* skinCPList = skinOrCluster->GetControlPointIndices();
- double* skinCPWeights = getControlPointBlendWeights(skinOrCluster);
- const int skinCPListLength = skinOrCluster->GetControlPointIndicesCount();
-
- for (int bw = 0; bw < skinCPListLength; bw++)
- {
- int newCPIdx = oldToNewCPMapping[skinCPList[bw]];
- if (!addedCP[newCPIdx])
- {
- addedCP[newCPIdx] = true;
- newCPsAndWeights.emplace_back(newCPIdx, skinCPWeights[bw]);
- }
- }
- skinOrCluster->SetControlPointIWCount(newCPsAndWeights.size());
- skinCPList = skinOrCluster->GetControlPointIndices();
- skinCPWeights = getControlPointBlendWeights(skinOrCluster);
- for (size_t bw = 0; bw < newCPsAndWeights.size(); bw++)
- {
- skinCPList[bw] = newCPsAndWeights[bw].first;
- skinCPWeights[bw] = newCPsAndWeights[bw].second;
- }
- }
-}
-
-//Do this otherwise Maya shows the mesh as faceted due to not being welded
-void FbxFileWriter::removeDuplicateControlPoints(fbxsdk::FbxMesh* mesh, FbxSkin* skin)
-{
- FbxVector4* cpList = mesh->GetControlPoints();
- const int cpCount = mesh->GetControlPointsCount();
-
- std::vector<int> oldToNewCPMapping(cpCount, -1);
- //sort them by z for faster overlap checking
- std::vector<std::pair<double, int>> cpIndexesByZ(cpCount);
- for (int cp = 0; cp < cpCount; cp++)
- {
- cpIndexesByZ[cp] = std::pair<double, int>(cpList[cp][2], cp);
- }
- std::sort(cpIndexesByZ.begin(), cpIndexesByZ.end());
-
- int clusterCount = 0;
- std::vector<std::vector<int>> cpsPerCluster;
- if (skin)
- {
- clusterCount = skin->GetClusterCount();
- cpsPerCluster.resize(clusterCount);
- for (int c = 0; c < clusterCount; c++)
- {
- FbxCluster* cluster = skin->GetCluster(c);
- int* clusterCPList = cluster->GetControlPointIndices();
- const int clusterCPListLength = cluster->GetControlPointIndicesCount();
-
- cpsPerCluster[c].resize(clusterCPListLength);
- memcpy(cpsPerCluster[c].data(), clusterCPList, sizeof(int) * clusterCPListLength);
- std::sort(cpsPerCluster[c].begin(), cpsPerCluster[c].end());
- }
- }
-
- std::vector<FbxVector4> uniqueCPs;
- uniqueCPs.reserve(cpCount);
-
- for (int i = 0; i < cpCount; i++)
- {
- const int cpiA = cpIndexesByZ[i].second;
- FbxVector4 cpA = cpList[cpiA];
- if (!(oldToNewCPMapping[cpiA] < 0))
- {
- //already culled this one
- continue;
- }
- const int newIdx = int(uniqueCPs.size());
- oldToNewCPMapping[cpiA] = newIdx;
- uniqueCPs.push_back(cpA);
-
- int clusterIndexA = -1;
- for (int c = 0; c < clusterCount; c++)
- {
- if (std::binary_search(cpsPerCluster[c].begin(), cpsPerCluster[c].end(), cpiA))
- {
- clusterIndexA = c;
- break;
- }
- }
-
- for (int j = i + 1; j < cpCount; j++)
- {
- if (std::abs(cpIndexesByZ[j].first - cpIndexesByZ[i].first) > FBXSDK_TOLERANCE)
- {
- break; // if the z's don't match other values don't matter
- }
-
- const int cpiB = cpIndexesByZ[j].second;
- FbxVector4 cpB = cpList[cpiB];
-
- //uses FBXSDK_TOLERANCE
- if (cpA == cpB)
- {
- int clusterIndexB = -1;
- for (int c = 0; c < clusterCount; c++)
- {
- if (std::binary_search(cpsPerCluster[c].begin(), cpsPerCluster[c].end(), cpiB))
- {
- clusterIndexB = c;
- break;
- }
- }
-
- //don't merge unless they share the same clusters
- if (clusterIndexA == clusterIndexB)
- {
- oldToNewCPMapping[cpiB] = newIdx;
- }
- }
- }
- }
-
- const int originalCPCount = cpCount;
- const int newCPCount = int(uniqueCPs.size());
-
- if (newCPCount == cpCount)
- {
- //don't bother, it will just scramble it for no reason
- return;
- }
-
- mesh->InitControlPoints(newCPCount);
- cpList = mesh->GetControlPoints();
-
- for (int cp = 0; cp < newCPCount; cp++)
- {
- cpList[cp] = uniqueCPs[cp];
- }
-
- int* polygonCPList = mesh->GetPolygonVertices();
- const int polygonCPListLength = mesh->GetPolygonVertexCount();
- for (int pv = 0; pv < polygonCPListLength; pv++)
- {
- polygonCPList[pv] = oldToNewCPMapping[polygonCPList[pv]];
- }
-
- if (skin)
- {
- remapCPsAndRemoveDuplicates(newCPCount, oldToNewCPMapping, skin);
- for (int c = 0; c < skin->GetClusterCount(); c++)
- {
- FbxCluster* cluster = skin->GetCluster(c);
- remapCPsAndRemoveDuplicates(newCPCount, oldToNewCPMapping, cluster);
- }
-
- }
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "fbxsdk.h"
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <map>
+#include <algorithm>
+#include <set>
+#include "NvBlastTypes.h"
+#include "NvBlastGlobals.h"
+#include "NvBlastTkFramework.h"
+#include "NvBlast.h"
+#include "PxVec3.h"
+#include "NvBlastAssert.h"
+#include <unordered_set>
+#include <functional>
+#include "NvBlastExtExporterFbxWriter.h"
+#include "NvBlastExtExporterFbxUtils.h"
+#include "NvBlastExtAuthoringCollisionBuilder.h"
+#include "NvBlastExtAuthoring.h"
+#include "NvBlastExtAuthoringMesh.h"
+
+using namespace Nv::Blast;
+
+FbxFileWriter::FbxFileWriter():
+ bOutputFBXAscii(false)
+{
+ // Wrap in a shared ptr so that when it deallocates we get an auto destroy and all of the other assets created don't leak.
+ sdkManager = std::shared_ptr<FbxManager>(FbxManager::Create(), [=](FbxManager* manager)
+ {
+ manager->Destroy();
+ });
+
+ mScene = FbxScene::Create(sdkManager.get(), "Export Scene");
+
+ mScene->GetGlobalSettings().SetAxisSystem(FbxUtils::getBlastFBXAxisSystem());
+ mScene->GetGlobalSettings().SetSystemUnit(FbxUtils::getBlastFBXUnit());
+ mScene->GetGlobalSettings().SetOriginalUpAxis(FbxUtils::getBlastFBXAxisSystem());
+ mScene->GetGlobalSettings().SetOriginalSystemUnit(FbxUtils::getBlastFBXUnit());
+
+ //We don't actually check for membership in this layer, but it's useful to show and hide the geo to look at the collision geo
+ mRenderLayer = FbxDisplayLayer::Create(mScene, FbxUtils::getRenderGeometryLayerName().c_str());
+ mRenderLayer->Show.Set(true);
+ mRenderLayer->Color.Set(FbxDouble3(0.0f, 1.0f, 0.0f));
+
+ mInteriorIndex = -1;
+}
+
+void FbxFileWriter::release()
+{
+ //sdkManager->Destroy();
+ delete this;
+}
+
+FbxScene* FbxFileWriter::getScene()
+{
+ return mScene;
+}
+
+
+void FbxFileWriter::createMaterials(const ExporterMeshData& aResult)
+{
+ mMaterials.clear();
+
+ for (uint32_t i = 0; i < aResult.submeshCount; ++i)
+ {
+ FbxSurfacePhong* material = FbxSurfacePhong::Create(sdkManager.get(), aResult.submeshMats[i].name);
+ material->Diffuse.Set(FbxDouble3(float(rand()) / RAND_MAX , float(rand()) / RAND_MAX, float(rand()) / RAND_MAX));
+ material->DiffuseFactor.Set(1.0);
+ mMaterials.push_back(material);
+ }
+}
+
+void FbxFileWriter::setInteriorIndex(int32_t index)
+{
+ mInteriorIndex = index;
+}
+
+
+void FbxFileWriter::createMaterials(const AuthoringResult& aResult)
+{
+ mMaterials.clear();
+ for (uint32_t i = 0; i < aResult.materialCount; ++i)
+ {
+ FbxSurfacePhong* material = FbxSurfacePhong::Create(sdkManager.get(), aResult.materialNames[i]);
+ material->Diffuse.Set(FbxDouble3(float(rand()) / RAND_MAX, float(rand()) / RAND_MAX, float(rand()) / RAND_MAX));
+ material->DiffuseFactor.Set(1.0);
+ mMaterials.push_back(material);
+ }
+ if (mMaterials.size() == 0)
+ {
+ FbxSurfacePhong* material = FbxSurfacePhong::Create(sdkManager.get(), "Base_mat");
+ material->Diffuse.Set(FbxDouble3(0.3, 1.0, 0));
+ material->DiffuseFactor.Set(1.0);
+ mMaterials.push_back(material);
+ }
+ if (mInteriorIndex == -1) // No material setted. Create new one.
+ {
+ FbxSurfacePhong* interiorMat = FbxSurfacePhong::Create(sdkManager.get(), "Interior_Material");
+ interiorMat->Diffuse.Set(FbxDouble3(1.0, 0.0, 0.5));
+ interiorMat->DiffuseFactor.Set(1.0);
+ mMaterials.push_back(interiorMat);
+ }
+ else
+ {
+ if (mInteriorIndex < 0) mInteriorIndex = 0;
+ if (static_cast<size_t>(mInteriorIndex) >= mMaterials.size()) mInteriorIndex = 0;
+ }
+
+}
+
+
+bool FbxFileWriter::appendMesh(const AuthoringResult& aResult, const char* assetName, bool nonSkinned)
+{
+ createMaterials(aResult);
+
+ if (nonSkinned)
+ {
+ return appendNonSkinnedMesh(aResult, assetName);
+ }
+ std::string meshName(assetName); meshName.append("_rendermesh");
+
+ FbxMesh* mesh = FbxMesh::Create(sdkManager.get(), meshName.c_str());
+
+ FbxGeometryElementNormal* geNormal = mesh->CreateElementNormal();
+ geNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
+ geNormal->SetReferenceMode(FbxGeometryElement::eDirect);
+
+ FbxGeometryElementUV* geUV = mesh->CreateElementUV("diffuseElement");
+ geUV->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
+ geUV->SetReferenceMode(FbxGeometryElement::eDirect);
+
+ FbxGeometryElementSmoothing* smElement = nullptr;
+ size_t triangleCount = aResult.geometryOffset[aResult.chunkCount];
+
+ for (size_t triangle = 0; triangle < triangleCount; triangle++)
+ {
+ if (aResult.geometry[triangle].smoothingGroup >= 0)
+ {
+ //Found a valid smoothing group
+ smElement = mesh->CreateElementSmoothing();
+ smElement->SetMappingMode(FbxGeometryElement::eByPolygon);
+ smElement->SetReferenceMode(FbxGeometryElement::eDirect);
+ break;
+ }
+ }
+
+ mesh->InitControlPoints((int)triangleCount * 3);
+
+
+ FbxNode* meshNode = FbxNode::Create(mScene, assetName);
+ meshNode->SetNodeAttribute(mesh);
+ meshNode->SetShadingMode(FbxNode::eTextureShading);
+
+ mRenderLayer->AddMember(meshNode);
+
+ for (uint32_t i = 0; i < mMaterials.size(); ++i)
+ {
+ meshNode->AddMaterial(mMaterials[i]);
+ }
+
+ FbxNode* lRootNode = mScene->GetRootNode();
+
+ //In order for Maya to correctly convert the axis of a skinned model there must be a common root node between the skeleton and the model
+ FbxNode* sceneRootNode = FbxNode::Create(sdkManager.get(), "sceneRoot");
+ lRootNode->AddChild(sceneRootNode);
+ sceneRootNode->AddChild(meshNode);
+
+ //UE4 cannot hide the root bone, so add a dummy chunk so chunk0 is not the root
+ FbxNode* skelRootNode = FbxNode::Create(sdkManager.get(), "root");
+ FbxSkeleton* skelAttrib = FbxSkeleton::Create(sdkManager.get(), "SkelRootAttrib");
+ skelAttrib->SetSkeletonType(FbxSkeleton::eRoot);
+ skelRootNode->SetNodeAttribute(skelAttrib);
+
+ sceneRootNode->AddChild(skelRootNode);
+
+ FbxSkin* skin = FbxSkin::Create(sdkManager.get(), "Skin of the thing");
+ skin->SetGeometry(mesh);
+ mesh->AddDeformer(skin);
+
+ // Add a material otherwise UE4 freaks out on import
+
+ FbxGeometryElementMaterial* matElement = mesh->CreateElementMaterial();
+ matElement->SetMappingMode(FbxGeometryElement::eByPolygon);
+ matElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
+
+ // Now walk the tree and create a skeleton with geometry at the same time
+ // Find a "root" chunk and walk the tree from there.
+ uint32_t chunkCount = NvBlastAssetGetChunkCount(aResult.asset, Nv::Blast::logLL);
+ auto chunks = NvBlastAssetGetChunks(aResult.asset, Nv::Blast::logLL);
+
+ uint32_t cpIdx = 0;
+ for (uint32_t i = 0; i < chunkCount; i++)
+ {
+ auto& chunk = chunks[i];
+
+ if (chunk.parentChunkIndex == UINT32_MAX)
+ {
+ uint32_t addedCps = createChunkRecursive(cpIdx, i, meshNode, skelRootNode, skin, aResult);
+ cpIdx += addedCps;
+ }
+ }
+
+ if (!smElement)
+ {
+ //If no smoothing groups, generate them
+ generateSmoothingGroups(mesh, skin);
+ }
+
+ removeDuplicateControlPoints(mesh, skin);
+
+ if (aResult.collisionHull != nullptr)
+ {
+ return appendCollisionMesh(chunkCount, aResult.collisionHullOffset, aResult.collisionHull, assetName);
+ }
+
+ return true;
+};
+
+
+bool FbxFileWriter::appendNonSkinnedMesh(const AuthoringResult& aResult, const char* assetName)
+{
+ FbxNode* lRootNode = mScene->GetRootNode();
+
+ //UE4 cannot hide the root bone, so add a dummy chunk so chunk0 is not the root
+ FbxNode* skelRootNode = FbxNode::Create(sdkManager.get(), "root");
+ //UE4 needs this to be a skeleton node, null node, or mesh node to get used
+ FbxNull* nullAttr = FbxNull::Create(sdkManager.get(), "SkelRootAttrib");
+ skelRootNode->SetNodeAttribute(nullAttr);
+ lRootNode->AddChild(skelRootNode);
+
+ // Now walk the tree and create a skeleton with geometry at the same time
+ // Find a "root" chunk and walk the tree from there.
+ uint32_t chunkCount = NvBlastAssetGetChunkCount(aResult.asset, Nv::Blast::logLL);
+ auto chunks = NvBlastAssetGetChunks(aResult.asset, Nv::Blast::logLL);
+
+ for (uint32_t i = 0; i < chunkCount; i++)
+ {
+ auto& chunk = chunks[i];
+
+ if (chunk.parentChunkIndex == UINT32_MAX)
+ {
+ createChunkRecursiveNonSkinned(assetName, i, skelRootNode, mMaterials, aResult);
+ }
+ }
+
+ if (aResult.collisionHull != nullptr)
+ {
+ return appendCollisionMesh(chunkCount, aResult.collisionHullOffset, aResult.collisionHull, assetName);
+ }
+
+ return true;
+}
+
+
+bool FbxFileWriter::appendNonSkinnedMesh(const ExporterMeshData& meshData, const char* assetName)
+{
+ FbxNode* lRootNode = mScene->GetRootNode();
+
+ //UE4 cannot hide the root bone, so add a dummy chunk so chunk0 is not the root
+ FbxNode* skelRootNode = FbxNode::Create(sdkManager.get(), "root");
+ //UE4 needs this to be a skeleton node, null node, or mesh node to get used
+ FbxNull* nullAttr = FbxNull::Create(sdkManager.get(), "SkelRootAttrib");
+ skelRootNode->SetNodeAttribute(nullAttr);
+ lRootNode->AddChild(skelRootNode);
+
+ // Now walk the tree and create a skeleton with geometry at the same time
+ // Find a "root" chunk and walk the tree from there.
+ uint32_t chunkCount = NvBlastAssetGetChunkCount(meshData.asset, Nv::Blast::logLL);
+
+ auto chunks = NvBlastAssetGetChunks(meshData.asset, Nv::Blast::logLL);
+
+ for (uint32_t i = 0; i < chunkCount; i++)
+ {
+ const NvBlastChunk* chunk = &chunks[i];
+
+ if (chunk->parentChunkIndex == UINT32_MAX)
+ {
+ createChunkRecursiveNonSkinned("chunk", i, skelRootNode, mMaterials, meshData);
+ }
+ }
+ if (meshData.hulls != nullptr)
+ {
+ return appendCollisionMesh(chunkCount, meshData.hullsOffsets, meshData.hulls, assetName);
+ }
+ return true;
+}
+
+bool FbxFileWriter::appendCollisionMesh(uint32_t meshCount, uint32_t* offsets, CollisionHull** hulls, const char* assetName)
+{
+ FbxDisplayLayer* displayLayer = FbxDisplayLayer::Create(mScene, FbxUtils::getCollisionGeometryLayerName().c_str());
+ //Hide by default
+ displayLayer->Show.Set(false);
+ displayLayer->Color.Set(FbxDouble3(0.0f, 0.0f, 1.0f));
+
+ // Now walk the tree and create a skeleton with geometry at the same time
+ // Find a "root" chunk and walk the tree from there.
+
+ for (uint32_t i = 0; i < meshCount; i++)
+ {
+ auto findIt = chunkNodes.find(i);
+ if (findIt == chunkNodes.end())
+ {
+ std::cerr << "Warning: No chunk node for chunk " << i << ". Ignoring collision geo" << std::endl;
+ continue;
+ }
+ addCollisionHulls(i, displayLayer, findIt->second, offsets[i+1] - offsets[i], hulls + offsets[i]);
+ }
+ return true;
+}
+
+/*
+ Recursive method that creates this chunk and all it's children.
+
+ This creates a FbxNode with an FbxCluster, and all of the geometry for this chunk.
+
+ Returns the number of added control points
+*/
+uint32_t FbxFileWriter::createChunkRecursive(uint32_t currentCpIdx, uint32_t chunkIndex, FbxNode *meshNode, FbxNode* parentNode, FbxSkin* skin, const AuthoringResult& aResult)
+{
+
+ auto chunks = NvBlastAssetGetChunks(aResult.asset, Nv::Blast::logLL);
+ const NvBlastChunk* chunk = &chunks[chunkIndex];
+ physx::PxVec3 centroid = physx::PxVec3(chunk->centroid[0], chunk->centroid[1], chunk->centroid[2]);
+
+ //mesh->InitTextureUV(triangles.size() * 3);
+
+ std::string boneName = FbxUtils::getChunkNodeName(chunkIndex);
+
+ FbxSkeleton* skelAttrib = FbxSkeleton::Create(sdkManager.get(), boneName.c_str());
+ if (chunk->parentChunkIndex == UINT32_MAX)
+ {
+ skelAttrib->SetSkeletonType(FbxSkeleton::eRoot);
+
+ // Change the centroid to origin
+ centroid = physx::PxVec3(0.0f);
+ }
+ else
+ {
+ skelAttrib->SetSkeletonType(FbxSkeleton::eLimbNode);
+ worldChunkPivots[chunkIndex] = centroid;
+ }
+
+ skelAttrib->Size.Set(1.0); // What's this for?
+
+
+ FbxNode* boneNode = FbxNode::Create(sdkManager.get(), boneName.c_str());
+ boneNode->SetNodeAttribute(skelAttrib);
+
+ chunkNodes[chunkIndex] = boneNode;
+
+ auto mat = parentNode->EvaluateGlobalTransform().Inverse();
+
+ FbxVector4 vec(0, 0, 0, 0);
+ FbxVector4 c2 = mat.MultT(vec);
+
+ boneNode->LclTranslation.Set(c2);
+
+ parentNode->AddChild(boneNode);
+
+ std::ostringstream namestream;
+ namestream << "cluster_" << std::setw(5) << std::setfill('0') << chunkIndex;
+ std::string clusterName = namestream.str();
+
+ FbxCluster* cluster = FbxCluster::Create(sdkManager.get(), clusterName.c_str());
+ cluster->SetTransformMatrix(FbxAMatrix());
+ cluster->SetLink(boneNode);
+ cluster->SetLinkMode(FbxCluster::eTotalOne);
+
+ skin->AddCluster(cluster);
+
+ FbxMesh* mesh = static_cast<FbxMesh*>(meshNode->GetNodeAttribute());
+
+ FbxVector4* controlPoints = mesh->GetControlPoints();
+ auto geNormal = mesh->GetElementNormal();
+ auto geUV = mesh->GetElementUV("diffuseElement");
+ FbxGeometryElementMaterial* matElement = mesh->GetElementMaterial();
+ FbxGeometryElementSmoothing* smElement = mesh->GetElementSmoothing();
+
+ auto addVert = [&](Nv::Blast::Vertex vert, int controlPointIdx)
+ {
+ FbxVector4 vertex;
+ FbxVector4 normal;
+ FbxVector2 uv;
+
+ FbxUtils::VertexToFbx(vert, vertex, normal, uv);
+
+ controlPoints[controlPointIdx] = vertex;
+ geNormal->GetDirectArray().Add(normal);
+ geUV->GetDirectArray().Add(uv);
+ // Add this control point to the bone with weight 1.0
+ cluster->AddControlPointIndex(controlPointIdx, 1.0);
+ };
+
+ uint32_t cpIdx = 0;
+ uint32_t polyCount = mesh->GetPolygonCount();
+ for (uint32_t i = aResult.geometryOffset[chunkIndex]; i < aResult.geometryOffset[chunkIndex + 1]; i++)
+ {
+ Triangle& tri = aResult.geometry[i];
+ addVert(tri.a, currentCpIdx + cpIdx + 0);
+ addVert(tri.b, currentCpIdx + cpIdx + 1);
+ addVert(tri.c, currentCpIdx + cpIdx + 2);
+
+ mesh->BeginPolygon();
+ mesh->AddPolygon(currentCpIdx + cpIdx + 0);
+ mesh->AddPolygon(currentCpIdx + cpIdx + 1);
+ mesh->AddPolygon(currentCpIdx + cpIdx + 2);
+ mesh->EndPolygon();
+ int32_t material = (tri.materialId != MATERIAL_INTERIOR) ? ((tri.materialId < int32_t(mMaterials.size())) ? tri.materialId : 0) : ((mInteriorIndex == -1) ? int32_t(mMaterials.size() - 1): mInteriorIndex);
+ matElement->GetIndexArray().SetAt(polyCount, material);
+ if (smElement)
+ {
+ if (tri.userData == 0)
+ {
+ smElement->GetDirectArray().Add(tri.smoothingGroup);
+ }
+ else
+ {
+ smElement->GetDirectArray().Add(SMOOTHING_GROUP_INTERIOR);
+ }
+ }
+
+ polyCount++;
+ cpIdx += 3;
+ }
+
+ mat = meshNode->EvaluateGlobalTransform();
+ cluster->SetTransformMatrix(mat);
+
+ mat = boneNode->EvaluateGlobalTransform();
+ cluster->SetTransformLinkMatrix(mat);
+
+ uint32_t addedCps = static_cast<uint32_t>((aResult.geometryOffset[chunkIndex + 1] - aResult.geometryOffset[chunkIndex]) * 3);
+
+ for (uint32_t i = chunk->firstChildIndex; i < chunk->childIndexStop; i++)
+ {
+ addedCps += createChunkRecursive(currentCpIdx + addedCps, i, meshNode, boneNode, skin, aResult);
+ }
+
+ return addedCps;
+}
+
+
+void FbxFileWriter::createChunkRecursiveNonSkinned(const std::string& meshName, uint32_t chunkIndex, FbxNode* parentNode,
+ const std::vector<FbxSurfaceMaterial*>& materials, const ExporterMeshData& meshData)
+{
+ auto chunks = NvBlastAssetGetChunks(meshData.asset, Nv::Blast::logLL);
+ const NvBlastChunk* chunk = &chunks[chunkIndex];
+ physx::PxVec3 centroid = physx::PxVec3(chunk->centroid[0], chunk->centroid[1], chunk->centroid[2]);
+
+ std::string chunkName = FbxUtils::getChunkNodeName(chunkIndex);
+
+ FbxMesh* mesh = FbxMesh::Create(sdkManager.get(), (chunkName + "_mesh").c_str());
+
+ FbxNode* meshNode = FbxNode::Create(mScene, chunkName.c_str());
+ meshNode->SetNodeAttribute(mesh);
+ meshNode->SetShadingMode(FbxNode::eTextureShading);
+ mRenderLayer->AddMember(meshNode);
+
+ chunkNodes[chunkIndex] = meshNode;
+
+ auto mat = parentNode->EvaluateGlobalTransform().Inverse();
+
+ FbxVector4 c2 = mat.MultT(FbxVector4(centroid.x, centroid.y, centroid.z, 1.0f));
+ if (chunk->parentChunkIndex != UINT32_MAX)
+ {
+ //Don't mess with the root chunk pivot
+ meshNode->LclTranslation.Set(c2);
+ worldChunkPivots[chunkIndex] = centroid;
+ }
+
+ parentNode->AddChild(meshNode);
+ FbxAMatrix finalXForm = meshNode->EvaluateGlobalTransform();
+
+ //Set the geo transform to inverse so we can use the world mesh coordinates
+ FbxAMatrix invFinalXForm = finalXForm.Inverse();
+ meshNode->SetGeometricTranslation(FbxNode::eSourcePivot, invFinalXForm.GetT());
+ meshNode->SetGeometricRotation(FbxNode::eSourcePivot, invFinalXForm.GetR());
+ meshNode->SetGeometricScaling(FbxNode::eSourcePivot, invFinalXForm.GetS());
+
+ auto geNormal = mesh->CreateElementNormal();
+ auto geUV = mesh->CreateElementUV("diffuseElement");
+ auto matr = mesh->CreateElementMaterial();
+
+ uint32_t* firstIdx = meshData.submeshOffsets + chunkIndex * meshData.submeshCount;
+ uint32_t* lastIdx = meshData.submeshOffsets + (chunkIndex + 1) * meshData.submeshCount;
+ uint32_t cpCount = *lastIdx - *firstIdx;
+ mesh->InitControlPoints(cpCount);
+
+ geNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
+ geNormal->SetReferenceMode(FbxGeometryElement::eDirect);
+
+ geUV->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
+ geUV->SetReferenceMode(FbxGeometryElement::eDirect);
+
+ matr->SetMappingMode(FbxGeometryElement::eByPolygon);
+ matr->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
+
+ for (auto m : materials)
+ {
+ meshNode->AddMaterial(m);
+ }
+
+ uint32_t cPolygCount = 0;
+ int32_t addedVertices = 0;
+
+ for (uint32_t subMesh = 0; subMesh < meshData.submeshCount; ++subMesh)
+ {
+ for (uint32_t tr = *(firstIdx + subMesh); tr < *(firstIdx + subMesh + 1); tr += 3)
+ {
+ mesh->BeginPolygon(subMesh);
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ mesh->AddPolygon(tr - *firstIdx + k);
+
+ FbxVector4 temp;
+ FbxUtils::PxVec3ToFbx(meshData.positions[meshData.posIndex[tr + k]], temp);
+ mesh->SetControlPointAt(temp, tr - *firstIdx + k);
+
+ FbxUtils::PxVec3ToFbx(meshData.normals[meshData.normIndex[tr + k]], temp);
+ geNormal->GetDirectArray().Add(temp);
+
+ FbxVector2 temp2;
+ FbxUtils::PxVec2ToFbx(meshData.uvs[meshData.texIndex[tr + k]], temp2);
+ geUV->GetDirectArray().Add(temp2);
+ }
+ mesh->EndPolygon();
+ cPolygCount++;
+ addedVertices += 3;
+ }
+ }
+
+ if (!mesh->GetElementSmoothing())
+ {
+ //If no smoothing groups, generate them
+ generateSmoothingGroups(mesh, nullptr);
+ }
+
+ removeDuplicateControlPoints(mesh, nullptr);
+
+ for (uint32_t i = chunk->firstChildIndex; i < chunk->childIndexStop; i++)
+ {
+ createChunkRecursiveNonSkinned(meshName, i, meshNode, materials, meshData);
+ }
+}
+
+
+void FbxFileWriter::createChunkRecursiveNonSkinned(const std::string& meshName, uint32_t chunkIndex, FbxNode* parentNode, const std::vector<FbxSurfaceMaterial*>& materials, const AuthoringResult& aResult)
+{
+ auto chunks = NvBlastAssetGetChunks(aResult.asset, Nv::Blast::logLL);
+ const NvBlastChunk* chunk = &chunks[chunkIndex];
+ physx::PxVec3 centroid = physx::PxVec3(chunk->centroid[0], chunk->centroid[1], chunk->centroid[2]);
+
+ std::string chunkName = FbxUtils::getChunkNodeName(chunkIndex).c_str();
+
+ FbxMesh* mesh = FbxMesh::Create(sdkManager.get(), (chunkName + "_mesh").c_str());
+
+ FbxNode* meshNode = FbxNode::Create(mScene, chunkName.c_str());
+ meshNode->SetNodeAttribute(mesh);
+ meshNode->SetShadingMode(FbxNode::eTextureShading);
+ mRenderLayer->AddMember(meshNode);
+
+ chunkNodes[chunkIndex] = meshNode;
+
+ auto mat = parentNode->EvaluateGlobalTransform().Inverse();
+
+ FbxVector4 c2 = mat.MultT(FbxVector4(centroid.x, centroid.y, centroid.z, 1.0f));
+
+ if (chunk->parentChunkIndex != UINT32_MAX)
+ {
+ //Don't mess with the root chunk pivot
+ meshNode->LclTranslation.Set(c2);
+ worldChunkPivots[chunkIndex] = centroid;
+ }
+
+ parentNode->AddChild(meshNode);
+ FbxAMatrix finalXForm = meshNode->EvaluateGlobalTransform();
+
+ //Set the geo transform to inverse so we can use the world mesh coordinates
+ FbxAMatrix invFinalXForm = finalXForm.Inverse();
+ meshNode->SetGeometricTranslation(FbxNode::eSourcePivot, invFinalXForm.GetT());
+ meshNode->SetGeometricRotation(FbxNode::eSourcePivot, invFinalXForm.GetR());
+ meshNode->SetGeometricScaling(FbxNode::eSourcePivot, invFinalXForm.GetS());
+
+
+ auto geNormal = mesh->CreateElementNormal();
+ auto geUV = mesh->CreateElementUV("diffuseElement");
+ auto matr = mesh->CreateElementMaterial();
+
+ uint32_t firstIdx = aResult.geometryOffset[chunkIndex];
+ uint32_t lastIdx = aResult.geometryOffset[chunkIndex + 1];
+
+ FbxGeometryElementSmoothing* smElement = nullptr;
+ for (uint32_t triangle = firstIdx; triangle < lastIdx; triangle++)
+ {
+ if (aResult.geometry[triangle].smoothingGroup >= 0)
+ {
+ //Found a valid smoothing group
+ smElement = mesh->CreateElementSmoothing();
+ smElement->SetMappingMode(FbxGeometryElement::eByPolygon);
+ smElement->SetReferenceMode(FbxGeometryElement::eDirect);
+ break;
+ }
+ }
+
+ mesh->InitControlPoints((int)(lastIdx - firstIdx) * 3);
+
+ geNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
+ geNormal->SetReferenceMode(FbxGeometryElement::eDirect);
+
+ geUV->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
+ geUV->SetReferenceMode(FbxGeometryElement::eDirect);
+
+ matr->SetMappingMode(FbxGeometryElement::eByPolygon);
+ matr->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
+
+ for (auto m : materials)
+ {
+ meshNode->AddMaterial(m);
+ }
+
+ FbxGeometryElementMaterial* matElement = mesh->GetElementMaterial();
+ int32_t polyCount = 0;
+ for (uint32_t tr = firstIdx; tr < lastIdx; tr++)
+ {
+ auto& geo = aResult.geometry[tr];
+ const Nv::Blast::Vertex triVerts[3] = { geo.a, geo.b, geo.c };
+ mesh->BeginPolygon();
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ mesh->AddPolygon(tr * 3 + k);
+ FbxVector4 v, n;
+ FbxVector2 uv;
+ FbxUtils::VertexToFbx(triVerts[k], v, n, uv);
+ mesh->SetControlPointAt(v, tr * 3 + k);
+
+ geNormal->GetDirectArray().Add(n);
+ geUV->GetDirectArray().Add(uv);
+ }
+ mesh->EndPolygon();
+ int32_t material = (geo.materialId != MATERIAL_INTERIOR) ? ((geo.materialId < int32_t(mMaterials.size()))? geo.materialId : 0) : ((mInteriorIndex == -1)? int32_t(mMaterials.size() - 1) : mInteriorIndex);
+ matElement->GetIndexArray().SetAt(polyCount, material);
+
+ if (smElement)
+ {
+ if (geo.userData == 0)
+ {
+ smElement->GetDirectArray().Add(geo.smoothingGroup);
+ }
+ else
+ {
+ smElement->GetDirectArray().Add(SMOOTHING_GROUP_INTERIOR);
+ }
+ }
+
+ polyCount++;
+
+ }
+
+ if (!smElement)
+ {
+ //If no smoothing groups, generate them
+ generateSmoothingGroups(mesh, nullptr);
+
+ }
+
+ removeDuplicateControlPoints(mesh, nullptr);
+
+ for (uint32_t i = chunk->firstChildIndex; i < chunk->childIndexStop; i++)
+ {
+ createChunkRecursiveNonSkinned(meshName, i, meshNode, materials, aResult);
+ }
+}
+
+uint32_t FbxFileWriter::addCollisionHulls(uint32_t chunkIndex, FbxDisplayLayer* displayLayer, FbxNode* parentNode, uint32_t hullsCount, CollisionHull** hulls)
+{
+ for (uint32_t hullId = 0; hullId < hullsCount; ++hullId)
+ {
+ std::stringstream namestream;
+ namestream.clear();
+ namestream << "collisionHull_" << chunkIndex << "_" << hullId;
+
+ FbxNode* collisionNode = FbxNode::Create(sdkManager.get(), namestream.str().c_str());
+
+ displayLayer->AddMember(collisionNode);
+
+ //TODO: Remove this when tools are converted over
+ FbxProperty::Create(collisionNode, FbxIntDT, "ParentalChunkIndex");
+ collisionNode->FindProperty("ParentalChunkIndex").Set(chunkIndex);
+ //
+
+ namestream.clear();
+ namestream << "collisionHullGeom_" << chunkIndex << "_" << hullId;
+ FbxMesh* meshAttr = FbxMesh::Create(sdkManager.get(), namestream.str().c_str());
+ collisionNode->SetNodeAttribute(meshAttr);
+ parentNode->AddChild(collisionNode);
+
+ auto mat = parentNode->EvaluateGlobalTransform().Inverse();
+ auto centroid = worldChunkPivots.find(chunkIndex);
+
+ if (centroid != worldChunkPivots.end())
+ {
+ FbxVector4 c2 = mat.MultT(FbxVector4(centroid->second.x, centroid->second.y, centroid->second.z, 1.0f));
+ //Don't mess with the root chunk pivot
+ collisionNode->LclTranslation.Set(c2);
+ }
+ parentNode->AddChild(collisionNode);
+ FbxAMatrix finalXForm = collisionNode->EvaluateGlobalTransform();
+
+ //Set the geo transform to inverse so we can use the world mesh coordinates
+ FbxAMatrix invFinalXForm = finalXForm.Inverse();
+ collisionNode->SetGeometricTranslation(FbxNode::eSourcePivot, invFinalXForm.GetT());
+ collisionNode->SetGeometricRotation(FbxNode::eSourcePivot, invFinalXForm.GetR());
+ collisionNode->SetGeometricScaling(FbxNode::eSourcePivot, invFinalXForm.GetS());
+
+
+ meshAttr->InitControlPoints(hulls[hullId]->pointsCount);
+ meshAttr->CreateElementNormal();
+ FbxVector4* controlPoints = meshAttr->GetControlPoints();
+ auto geNormal = meshAttr->GetElementNormal();
+ geNormal->SetMappingMode(FbxGeometryElement::eByPolygon);
+ geNormal->SetReferenceMode(FbxGeometryElement::eDirect);
+ for (uint32_t i = 0; i < hulls[hullId]->pointsCount; ++i)
+ {
+ auto& pnts = hulls[hullId]->points[i];
+ controlPoints->Set(pnts.x, pnts.y, pnts.z, 0.0);
+ controlPoints++;
+ }
+
+ for (uint32_t i = 0; i < hulls[hullId]->polygonDataCount; ++i)
+ {
+ auto& poly = hulls[hullId]->polygonData[i];
+ meshAttr->BeginPolygon();
+ for (uint32_t j = 0; j < poly.mNbVerts; ++j)
+ {
+ meshAttr->AddPolygon(hulls[hullId]->indices[poly.mIndexBase + j]);
+ }
+ meshAttr->EndPolygon();
+ FbxVector4 plane(poly.mPlane[0], poly.mPlane[1], poly.mPlane[2], 0);
+ geNormal->GetDirectArray().Add(plane);
+ }
+ }
+ return 1;
+}
+
+uint32_t FbxFileWriter::createChunkRecursive(uint32_t currentCpIdx, uint32_t chunkIndex, FbxNode *meshNode, FbxNode* parentNode, FbxSkin* skin, const ExporterMeshData& meshData)
+{
+ auto chunks = NvBlastAssetGetChunks(meshData.asset, Nv::Blast::logLL);
+ const NvBlastChunk* chunk = &chunks[chunkIndex];
+ physx::PxVec3 centroid = physx::PxVec3(chunk->centroid[0], chunk->centroid[1], chunk->centroid[2]);
+
+ std::string boneName = FbxUtils::getChunkNodeName(chunkIndex).c_str();
+
+ FbxSkeleton* skelAttrib = FbxSkeleton::Create(sdkManager.get(), boneName.c_str());
+ if (chunk->parentChunkIndex == UINT32_MAX)
+ {
+ skelAttrib->SetSkeletonType(FbxSkeleton::eRoot);
+
+ // Change the centroid to origin
+ centroid = physx::PxVec3(0.0f);
+ }
+ else
+ {
+ skelAttrib->SetSkeletonType(FbxSkeleton::eLimbNode);
+ worldChunkPivots[chunkIndex] = centroid;
+ }
+
+ FbxNode* boneNode = FbxNode::Create(sdkManager.get(), boneName.c_str());
+ boneNode->SetNodeAttribute(skelAttrib);
+
+ chunkNodes[chunkIndex] = boneNode;
+
+ auto mat = parentNode->EvaluateGlobalTransform().Inverse();
+
+ FbxVector4 vec(0, 0, 0, 0);
+ FbxVector4 c2 = mat.MultT(vec);
+
+ boneNode->LclTranslation.Set(c2);
+
+ parentNode->AddChild(boneNode);
+
+ std::ostringstream namestream;
+ namestream << "cluster_" << std::setw(5) << std::setfill('0') << chunkIndex;
+ std::string clusterName = namestream.str();
+
+ FbxCluster* cluster = FbxCluster::Create(sdkManager.get(), clusterName.c_str());
+ cluster->SetTransformMatrix(FbxAMatrix());
+ cluster->SetLink(boneNode);
+ cluster->SetLinkMode(FbxCluster::eTotalOne);
+
+ skin->AddCluster(cluster);
+
+ FbxMesh* mesh = static_cast<FbxMesh*>(meshNode->GetNodeAttribute());
+
+ auto geNormal = mesh->GetElementNormal();
+ auto geUV = mesh->GetElementUV("diffuseElement");
+ auto matr = mesh->GetElementMaterial();
+
+ std::vector<bool> addedVerticesFlag(mesh->GetControlPointsCount(), false);
+
+ uint32_t* firstIdx = meshData.submeshOffsets + chunkIndex * meshData.submeshCount;
+ uint32_t cPolygCount = mesh->GetPolygonCount();
+ int32_t addedVertices = 0;
+ for (uint32_t subMesh = 0; subMesh < meshData.submeshCount; ++subMesh)
+ {
+ for (uint32_t tr = *(firstIdx + subMesh); tr < *(firstIdx + subMesh + 1); tr += 3)
+ {
+ mesh->BeginPolygon(subMesh);
+ mesh->AddPolygon(meshData.posIndex[tr + 0]);
+ mesh->AddPolygon(meshData.posIndex[tr + 1]);
+ mesh->AddPolygon(meshData.posIndex[tr + 2]);
+ mesh->EndPolygon();
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ geNormal->GetIndexArray().SetAt(currentCpIdx + addedVertices + k, meshData.normIndex[tr + k]);
+ geUV->GetIndexArray().SetAt(currentCpIdx + addedVertices + k, meshData.texIndex[tr + k]);
+ }
+ if (subMesh == 0)
+ {
+ matr->GetIndexArray().SetAt(cPolygCount, 0);
+ }
+ else
+ {
+ matr->GetIndexArray().SetAt(cPolygCount, 1);
+ }
+ cPolygCount++;
+ addedVertices += 3;
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ if (!addedVerticesFlag[meshData.posIndex[tr + k]])
+ {
+ cluster->AddControlPointIndex(meshData.posIndex[tr + k], 1.0);
+ addedVerticesFlag[meshData.posIndex[tr + k]] = true;
+ }
+ }
+ }
+ }
+ mat = meshNode->EvaluateGlobalTransform();
+ cluster->SetTransformMatrix(mat);
+
+ mat = boneNode->EvaluateGlobalTransform();
+ cluster->SetTransformLinkMatrix(mat);
+
+
+ for (uint32_t i = chunk->firstChildIndex; i < chunk->childIndexStop; i++)
+ {
+ addedVertices += createChunkRecursive(currentCpIdx + addedVertices, i, meshNode, boneNode, skin, meshData);
+ }
+
+ return addedVertices;
+
+}
+
+void FbxFileWriter::addControlPoints(FbxMesh* mesh, const ExporterMeshData& meshData)
+{
+ std::vector<uint32_t> vertices;
+ std::cout << "Adding control points" << std::endl;
+ std::vector<int32_t> mapping(meshData.positionsCount, -1);
+ for (uint32_t ch = 0; ch < meshData.meshCount; ++ch)
+ {
+ mapping.assign(meshData.positionsCount, -1);
+ for (uint32_t sb = 0; sb < meshData.submeshCount; ++sb)
+ {
+ uint32_t* first = meshData.submeshOffsets + ch * meshData.submeshCount + sb;
+ for (uint32_t pi = *first; pi < *(first+1); ++pi)
+ {
+ uint32_t p = meshData.posIndex[pi];
+ if (mapping[p] == -1)
+ {
+ mapping[p] = (int)vertices.size();
+ vertices.push_back(p);
+ meshData.posIndex[pi] = mapping[p];
+ }
+ else
+ {
+ meshData.posIndex[pi] = mapping[p];
+ }
+ }
+ }
+ }
+ mesh->InitControlPoints((int)vertices.size());
+ FbxVector4* controlPoints = mesh->GetControlPoints();
+ for (auto v : vertices)
+ {
+ auto& p = meshData.positions[v];
+ *controlPoints = FbxVector4(p.x, p.y, p.z, 0);
+ ++controlPoints;
+ }
+ std::cout << "Adding control points: done" << std::endl;
+}
+
+void FbxFileWriter::addBindPose()
+{
+ // Store the bind pose
+ //Just add all the nodes, it doesn't seem to do any harm and it stops Maya complaining about incomplete bind poses
+ FbxPose* pose = FbxPose::Create(sdkManager.get(), "BindPose");
+ pose->SetIsBindPose(true);
+
+ int nodeCount = mScene->GetNodeCount();
+ for (int i = 0; i < nodeCount; i++)
+ {
+ FbxNode* node = mScene->GetNode(i);
+ FbxMatrix bindMat = node->EvaluateGlobalTransform();
+
+ pose->Add(node, bindMat);
+ }
+
+ mScene->AddPose(pose);
+}
+
+bool FbxFileWriter::saveToFile(const char* assetName, const char* outputPath)
+{
+
+ addBindPose();
+
+ FbxIOSettings* ios = FbxIOSettings::Create(sdkManager.get(), IOSROOT);
+ // Set some properties on the io settings
+
+ sdkManager->SetIOSettings(ios);
+
+ sdkManager->GetIOSettings()->SetBoolProp(EXP_ASCIIFBX, bOutputFBXAscii);
+
+
+ FbxExporter* exporter = FbxExporter::Create(sdkManager.get(), "Scene Exporter");
+ exporter->SetFileExportVersion(FBX_2012_00_COMPATIBLE);
+
+ int lFormat;
+
+ if (bOutputFBXAscii)
+ {
+ lFormat = sdkManager->GetIOPluginRegistry()->FindWriterIDByDescription("FBX ascii (*.fbx)");
+ }
+ else
+ {
+ lFormat = sdkManager->GetIOPluginRegistry()->FindWriterIDByDescription("FBX binary (*.fbx)");
+ }
+
+ auto path = std::string(outputPath) + "\\" + assetName + ".fbx";
+ bool exportStatus = exporter->Initialize(path.c_str(), lFormat, sdkManager->GetIOSettings());
+
+ if (!exportStatus)
+ {
+ std::cerr << "Call to FbxExporter::Initialize failed" << std::endl;
+ std::cerr << "Error returned: " << exporter->GetStatus().GetErrorString() << std::endl;
+ return false;
+ }
+
+ exportStatus = exporter->Export(mScene);
+
+ if (!exportStatus)
+ {
+ auto fbxStatus = exporter->GetStatus();
+
+ std::cerr << "Call to FbxExporter::Export failed" << std::endl;
+ std::cerr << "Error returned: " << fbxStatus.GetErrorString() << std::endl;
+ return false;
+ }
+ return true;
+}
+
+
+
+bool FbxFileWriter::appendMesh(const ExporterMeshData& meshData, const char* assetName, bool nonSkinned)
+{
+ createMaterials(meshData);
+
+ if (nonSkinned)
+ {
+ return appendNonSkinnedMesh(meshData, assetName);
+ }
+
+ /**
+ Get polygon count
+ */
+ uint32_t polygCount = meshData.submeshOffsets[meshData.meshCount * meshData.submeshCount] / 3;
+
+ FbxMesh* mesh = FbxMesh::Create(sdkManager.get(), "meshgeo");
+
+ FbxGeometryElementNormal* geNormal = mesh->CreateElementNormal();
+ geNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
+ geNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
+
+ FbxGeometryElementUV* geUV = mesh->CreateElementUV("diffuseElement");
+ geUV->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
+ geUV->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
+
+
+ FbxNode* meshNode = FbxNode::Create(mScene, "meshnode");
+ meshNode->SetNodeAttribute(mesh);
+ meshNode->SetShadingMode(FbxNode::eTextureShading);
+
+ FbxNode* lRootNode = mScene->GetRootNode();
+
+ mRenderLayer->AddMember(meshNode);
+
+ for (uint32_t i = 0; i < mMaterials.size(); ++i)
+ {
+ meshNode->AddMaterial(mMaterials[i]);
+ }
+
+ FbxSkin* skin = FbxSkin::Create(sdkManager.get(), "Skin of the thing");
+ skin->SetGeometry(mesh);
+
+ mesh->AddDeformer(skin);
+
+ /**
+ Create control points, copy data to buffers
+ */
+ addControlPoints(mesh, meshData);
+
+ auto normalsElem = mesh->GetElementNormal();
+ for (uint32_t i = 0; i < meshData.normalsCount; ++i)
+ {
+ auto& n = meshData.normals[i];
+ normalsElem->GetDirectArray().Add(FbxVector4(n.x, n.y, n.z, 0));
+ }
+ auto uvsElem = mesh->GetElementUV("diffuseElement");
+ for (uint32_t i = 0; i < meshData.uvsCount; ++i)
+ {
+ auto& uvs = meshData.uvs[i];
+ uvsElem->GetDirectArray().Add(FbxVector2(uvs.x, uvs.y));
+ }
+
+ FbxGeometryElementMaterial* matElement = mesh->CreateElementMaterial();
+ matElement->SetMappingMode(FbxGeometryElement::eByPolygon);
+ matElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
+
+
+ matElement->GetIndexArray().SetCount(polygCount);
+ normalsElem->GetIndexArray().SetCount(polygCount * 3);
+ uvsElem->GetIndexArray().SetCount(polygCount * 3);
+
+
+ std::cout << "Create chunks recursive" << std::endl;
+
+ //In order for Maya to correctly convert the axis of a skinned model there must be a common root node between the skeleton and the model
+ FbxNode* sceneRootNode = FbxNode::Create(sdkManager.get(), "sceneRoot");
+ lRootNode->AddChild(sceneRootNode);
+ sceneRootNode->AddChild(meshNode);
+
+ //UE4 cannot hide the root bone, so add a dummy chunk so chunk0 is not the root
+ FbxNode* skelRootNode = FbxNode::Create(sdkManager.get(), "root");
+ FbxSkeleton* skelAttrib = FbxSkeleton::Create(sdkManager.get(), "SkelRootAttrib");
+ skelAttrib->SetSkeletonType(FbxSkeleton::eRoot);
+ skelRootNode->SetNodeAttribute(skelAttrib);
+
+ sceneRootNode->AddChild(skelRootNode);
+
+ // Now walk the tree and create a skeleton with geometry at the same time
+ // Find a "root" chunk and walk the tree from there.
+ uint32_t chunkCount = NvBlastAssetGetChunkCount(meshData.asset, Nv::Blast::logLL);
+ auto chunks = NvBlastAssetGetChunks(meshData.asset, Nv::Blast::logLL);
+ uint32_t cpIdx = 0;
+ for (uint32_t i = 0; i < chunkCount; i++)
+ {
+ const NvBlastChunk* chunk = &chunks[i];
+
+ if (chunk->parentChunkIndex == UINT32_MAX)
+ {
+ uint32_t addedCps = createChunkRecursive(cpIdx, i, meshNode, skelRootNode, skin, meshData);
+ cpIdx += addedCps;
+ }
+ }
+
+ if (!mesh->GetElementSmoothing())
+ {
+ //If no smoothing groups, generate them
+ generateSmoothingGroups(mesh, skin);
+ }
+
+ removeDuplicateControlPoints(mesh, skin);
+
+ if (meshData.hulls != nullptr)
+ {
+ return appendCollisionMesh(chunkCount, meshData.hullsOffsets, meshData.hulls, assetName);
+ }
+ return true;
+}
+
+void FbxFileWriter::generateSmoothingGroups(fbxsdk::FbxMesh* mesh, FbxSkin* skin)
+{
+ if (mesh->GetElementSmoothing(0) || !mesh->IsTriangleMesh())
+ {
+ //they already exist or we can't make it
+ return;
+ }
+
+ const FbxGeometryElementNormal* geNormal = mesh->GetElementNormal();
+ if (!geNormal || geNormal->GetMappingMode() != FbxGeometryElement::eByPolygonVertex || geNormal->GetReferenceMode() != FbxGeometryElement::eDirect)
+ {
+ //We just set this up, but just incase
+ return;
+ }
+
+ int clusterCount = 0;
+ std::vector<std::vector<int>> cpsPerCluster;
+ if (skin)
+ {
+ clusterCount = skin->GetClusterCount();
+ cpsPerCluster.resize(clusterCount);
+ for (int c = 0; c < clusterCount; c++)
+ {
+ FbxCluster* cluster = skin->GetCluster(c);
+ int* clusterCPList = cluster->GetControlPointIndices();
+ const int clusterCPListLength = cluster->GetControlPointIndicesCount();
+
+ cpsPerCluster[c].resize(clusterCPListLength);
+ memcpy(cpsPerCluster[c].data(), clusterCPList, sizeof(int) * clusterCPListLength);
+ std::sort(cpsPerCluster[c].begin(), cpsPerCluster[c].end());
+ }
+ }
+
+ auto smElement = mesh->CreateElementSmoothing();
+ smElement->SetMappingMode(FbxGeometryElement::eByPolygon);
+ smElement->SetReferenceMode(FbxGeometryElement::eDirect);
+
+ FbxVector4* cpList = mesh->GetControlPoints();
+ const int cpCount = mesh->GetControlPointsCount();
+
+ const int triangleCount = mesh->GetPolygonCount();
+ const int cornerCount = triangleCount * 3;
+
+ int* polygonCPList = mesh->GetPolygonVertices();
+ const auto& normalByCornerList = geNormal->GetDirectArray();
+
+ std::multimap<int, int> overlappingCorners;
+ //sort them by z for faster overlap checking
+ std::vector<std::pair<double, int>> cornerIndexesByZ(cornerCount);
+ for (int c = 0; c < cornerCount; c++)
+ {
+ cornerIndexesByZ[c] = std::pair<double, int>(cpList[polygonCPList[c]][2], c);
+ }
+ std::sort(cornerIndexesByZ.begin(), cornerIndexesByZ.end());
+
+ for (int i = 0; i < cornerCount; i++)
+ {
+ const int cornerA = cornerIndexesByZ[i].second;
+ const int cpiA = polygonCPList[cornerA];
+ FbxVector4 cpA = cpList[cpiA];
+ cpA[3] = 0;
+
+ int clusterIndexA = -1;
+ for (int c = 0; c < clusterCount; c++)
+ {
+ if (std::binary_search(cpsPerCluster[c].begin(), cpsPerCluster[c].end(), cpiA))
+ {
+ clusterIndexA = c;
+ break;
+ }
+ }
+
+ for (int j = i + 1; j < cornerCount; j++)
+ {
+ if (std::abs(cornerIndexesByZ[j].first - cornerIndexesByZ[i].first) > FBXSDK_TOLERANCE)
+ {
+ break; // if the z's don't match other values don't matter
+ }
+ const int cornerB = cornerIndexesByZ[j].second;
+ const int cpiB = polygonCPList[cornerB];
+ FbxVector4 cpB = cpList[cpiB];
+
+ cpB[3] = 0;
+
+ //uses FBXSDK_TOLERANCE
+ if (cpA == cpB)
+ {
+ int clusterIndexB = -1;
+ for (int c = 0; c < clusterCount; c++)
+ {
+ if (std::binary_search(cpsPerCluster[c].begin(), cpsPerCluster[c].end(), cpiB))
+ {
+ clusterIndexB = c;
+ break;
+ }
+ }
+
+ if (clusterIndexA == clusterIndexB)
+ {
+ overlappingCorners.emplace(cornerA, cornerB);
+ overlappingCorners.emplace(cornerB, cornerA);
+ }
+ }
+ }
+ }
+
+ auto& smoothingGroupByTri = smElement->GetDirectArray();
+ for (int i = 0; i < triangleCount; i++)
+ {
+ smoothingGroupByTri.Add(0);
+ }
+ //first one
+ smoothingGroupByTri.SetAt(0, 1);
+
+ for (int i = 1; i < triangleCount; i++)
+ {
+ int sharedMask = 0, unsharedMask = 0;
+ for (int c = 0; c < 3; c++)
+ {
+ int myCorner = i * 3 + c;
+ FbxVector4 myNormal = normalByCornerList.GetAt(myCorner);
+ myNormal.Normalize();
+ myNormal[3] = 0;
+
+ auto otherCornersRangeBegin = overlappingCorners.lower_bound(myCorner);
+ auto otherCornersRangeEnd = overlappingCorners.upper_bound(myCorner);
+ for (auto it = otherCornersRangeBegin; it != otherCornersRangeEnd; it++)
+ {
+ int otherCorner = it->second;
+ FbxVector4 otherNormal = normalByCornerList.GetAt(otherCorner);
+ otherNormal.Normalize();
+ otherNormal[3] = 0;
+ if (otherNormal == myNormal)
+ {
+ sharedMask |= smoothingGroupByTri[otherCorner / 3];
+ }
+ else
+ {
+ unsharedMask |= smoothingGroupByTri[otherCorner / 3];
+ }
+ }
+ }
+
+ //Easy case, no overlap
+ if ((sharedMask & unsharedMask) == 0 && sharedMask != 0)
+ {
+ smoothingGroupByTri.SetAt(i, sharedMask);
+ }
+ else
+ {
+ for (int sm = 0; sm < 32; sm++)
+ {
+ int val = 1 << sm;
+ if (((val & sharedMask) == sharedMask) && !(val & unsharedMask))
+ {
+ smoothingGroupByTri.SetAt(i, val);
+ break;
+ }
+ }
+ }
+ }
+
+}
+
+namespace
+{
+ //These methods have different names for some reason
+ inline double* getControlPointBlendWeights(FbxSkin* skin)
+ {
+ return skin->GetControlPointBlendWeights();
+ }
+
+ inline double* getControlPointBlendWeights(FbxCluster* cluster)
+ {
+ return cluster->GetControlPointWeights();
+ }
+
+ template <typename T>
+ void remapCPsAndRemoveDuplicates(const int newCPCount, const std::vector<int>& oldToNewCPMapping, T* skinOrCluster)
+ {
+ //Need to avoid duplicate entires since UE doesn't seem to normalize this correctly
+ std::vector<bool> addedCP(newCPCount, false);
+ std::vector<std::pair<int, double>> newCPsAndWeights;
+ newCPsAndWeights.reserve(newCPCount);
+
+ int* skinCPList = skinOrCluster->GetControlPointIndices();
+ double* skinCPWeights = getControlPointBlendWeights(skinOrCluster);
+ const int skinCPListLength = skinOrCluster->GetControlPointIndicesCount();
+
+ for (int bw = 0; bw < skinCPListLength; bw++)
+ {
+ int newCPIdx = oldToNewCPMapping[skinCPList[bw]];
+ if (!addedCP[newCPIdx])
+ {
+ addedCP[newCPIdx] = true;
+ newCPsAndWeights.emplace_back(newCPIdx, skinCPWeights[bw]);
+ }
+ }
+ skinOrCluster->SetControlPointIWCount(newCPsAndWeights.size());
+ skinCPList = skinOrCluster->GetControlPointIndices();
+ skinCPWeights = getControlPointBlendWeights(skinOrCluster);
+ for (size_t bw = 0; bw < newCPsAndWeights.size(); bw++)
+ {
+ skinCPList[bw] = newCPsAndWeights[bw].first;
+ skinCPWeights[bw] = newCPsAndWeights[bw].second;
+ }
+ }
+}
+
+//Do this otherwise Maya shows the mesh as faceted due to not being welded
+void FbxFileWriter::removeDuplicateControlPoints(fbxsdk::FbxMesh* mesh, FbxSkin* skin)
+{
+ FbxVector4* cpList = mesh->GetControlPoints();
+ const int cpCount = mesh->GetControlPointsCount();
+
+ std::vector<int> oldToNewCPMapping(cpCount, -1);
+ //sort them by z for faster overlap checking
+ std::vector<std::pair<double, int>> cpIndexesByZ(cpCount);
+ for (int cp = 0; cp < cpCount; cp++)
+ {
+ cpIndexesByZ[cp] = std::pair<double, int>(cpList[cp][2], cp);
+ }
+ std::sort(cpIndexesByZ.begin(), cpIndexesByZ.end());
+
+ int clusterCount = 0;
+ std::vector<std::vector<int>> cpsPerCluster;
+ if (skin)
+ {
+ clusterCount = skin->GetClusterCount();
+ cpsPerCluster.resize(clusterCount);
+ for (int c = 0; c < clusterCount; c++)
+ {
+ FbxCluster* cluster = skin->GetCluster(c);
+ int* clusterCPList = cluster->GetControlPointIndices();
+ const int clusterCPListLength = cluster->GetControlPointIndicesCount();
+
+ cpsPerCluster[c].resize(clusterCPListLength);
+ memcpy(cpsPerCluster[c].data(), clusterCPList, sizeof(int) * clusterCPListLength);
+ std::sort(cpsPerCluster[c].begin(), cpsPerCluster[c].end());
+ }
+ }
+
+ std::vector<FbxVector4> uniqueCPs;
+ uniqueCPs.reserve(cpCount);
+
+ for (int i = 0; i < cpCount; i++)
+ {
+ const int cpiA = cpIndexesByZ[i].second;
+ FbxVector4 cpA = cpList[cpiA];
+ if (!(oldToNewCPMapping[cpiA] < 0))
+ {
+ //already culled this one
+ continue;
+ }
+ const int newIdx = int(uniqueCPs.size());
+ oldToNewCPMapping[cpiA] = newIdx;
+ uniqueCPs.push_back(cpA);
+
+ int clusterIndexA = -1;
+ for (int c = 0; c < clusterCount; c++)
+ {
+ if (std::binary_search(cpsPerCluster[c].begin(), cpsPerCluster[c].end(), cpiA))
+ {
+ clusterIndexA = c;
+ break;
+ }
+ }
+
+ for (int j = i + 1; j < cpCount; j++)
+ {
+ if (std::abs(cpIndexesByZ[j].first - cpIndexesByZ[i].first) > FBXSDK_TOLERANCE)
+ {
+ break; // if the z's don't match other values don't matter
+ }
+
+ const int cpiB = cpIndexesByZ[j].second;
+ FbxVector4 cpB = cpList[cpiB];
+
+ //uses FBXSDK_TOLERANCE
+ if (cpA == cpB)
+ {
+ int clusterIndexB = -1;
+ for (int c = 0; c < clusterCount; c++)
+ {
+ if (std::binary_search(cpsPerCluster[c].begin(), cpsPerCluster[c].end(), cpiB))
+ {
+ clusterIndexB = c;
+ break;
+ }
+ }
+
+ //don't merge unless they share the same clusters
+ if (clusterIndexA == clusterIndexB)
+ {
+ oldToNewCPMapping[cpiB] = newIdx;
+ }
+ }
+ }
+ }
+
+ const int originalCPCount = cpCount;
+ const int newCPCount = int(uniqueCPs.size());
+
+ if (newCPCount == cpCount)
+ {
+ //don't bother, it will just scramble it for no reason
+ return;
+ }
+
+ mesh->InitControlPoints(newCPCount);
+ cpList = mesh->GetControlPoints();
+
+ for (int cp = 0; cp < newCPCount; cp++)
+ {
+ cpList[cp] = uniqueCPs[cp];
+ }
+
+ int* polygonCPList = mesh->GetPolygonVertices();
+ const int polygonCPListLength = mesh->GetPolygonVertexCount();
+ for (int pv = 0; pv < polygonCPListLength; pv++)
+ {
+ polygonCPList[pv] = oldToNewCPMapping[polygonCPList[pv]];
+ }
+
+ if (skin)
+ {
+ remapCPsAndRemoveDuplicates(newCPCount, oldToNewCPMapping, skin);
+ for (int c = 0; c < skin->GetClusterCount(); c++)
+ {
+ FbxCluster* cluster = skin->GetCluster(c);
+ remapCPsAndRemoveDuplicates(newCPCount, oldToNewCPMapping, cluster);
+ }
+
+ }
} \ No newline at end of file
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.h b/sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.h
index f66ce6b..75b4843 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.h
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterFbxWriter.h
@@ -1,144 +1,144 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#ifndef NVBLASTEXTEXPORTERFBXWRITER_H
-#define NVBLASTEXTEXPORTERFBXWRITER_H
-
-#include "NvBlastExtExporter.h"
-#include <memory>
-#include <vector>
-#include <map>
-
-namespace fbxsdk
-{
- class FbxScene;
- class FbxNode;
- class FbxMesh;
- class FbxSkin;
- class FbxManager;
- class FbxSurfaceMaterial;
- class FbxDisplayLayer;
-}
-
-struct NvBlastAsset;
-
-namespace Nv
-{
-namespace Blast
-{
-class Mesh;
-struct Triangle;
-struct CollisionHull;
-
-class FbxFileWriter : public IMeshFileWriter
-{
-public:
-
- /**
- Initialize FBX sdk and create scene.
- */
- FbxFileWriter();
- //~FbxFileWriter() = default;
-
- virtual void release() override;
-
- /**
- Get current scene;
- */
- fbxsdk::FbxScene* getScene();
-
- /**
- Append rendermesh to scene. Meshes constructed from arrays of triangles.
- */
- virtual bool appendMesh(const AuthoringResult& aResult, const char* assetName, bool nonSkinned) override;
-
- /**
- Append rendermesh to scene. Meshes constructed from arrays of vertex data (position, normal, uvs) and indices.
- Position, normal and uv has separate index arrays.
- */
- virtual bool appendMesh(const ExporterMeshData& meshData, const char* assetName, bool nonSkinned) override;
-
- /**
- Save scene to file.
- */
- virtual bool saveToFile(const char* assetName, const char* outputPath) override;
-
- /**
- Set interior material index.
- */
- virtual void setInteriorIndex(int32_t index) override;
-
- /**
- Set true if FBX should be saved in ASCII mode.
- */
- bool bOutputFBXAscii;
-
-private:
- std::vector<fbxsdk::FbxSurfaceMaterial*> mMaterials;
- fbxsdk::FbxScene* mScene;
- fbxsdk::FbxDisplayLayer* mRenderLayer;
-
- //TODO we should track for every memory allocation and deallocate it not only for sdkManager
- std::shared_ptr<fbxsdk::FbxManager> sdkManager;
- std::map<uint32_t, fbxsdk::FbxNode*> chunkNodes;
- std::map<uint32_t, physx::PxVec3> worldChunkPivots;
-
- bool appendNonSkinnedMesh(const AuthoringResult& aResult, const char* assetName);
- bool appendNonSkinnedMesh(const ExporterMeshData& meshData, const char* assetName);
- void createMaterials(const ExporterMeshData& meshData);
- void createMaterials(const AuthoringResult& aResult);
-
- /**
- Append collision geometry to scene. Each node with collision geometry has "ParentalChunkIndex" property, which contain index of chunk
- which this collision geometry belongs to.
- */
- bool appendCollisionMesh(uint32_t meshCount, uint32_t* offsets, CollisionHull** hulls, const char* assetName);
-
- uint32_t addCollisionHulls(uint32_t chunkIndex, fbxsdk::FbxDisplayLayer* displayLayer, fbxsdk::FbxNode* parentNode, uint32_t hullsCount, CollisionHull** hulls);
- uint32_t createChunkRecursive(uint32_t currentCpIdx, uint32_t chunkIndex, fbxsdk::FbxNode *meshNode, fbxsdk::FbxNode* parentNode, fbxsdk::FbxSkin* skin, const AuthoringResult& aResult);
- uint32_t createChunkRecursive(uint32_t currentCpIdx, uint32_t chunkIndex, fbxsdk::FbxNode *meshNode, fbxsdk::FbxNode* parentNode, fbxsdk::FbxSkin* skin, const ExporterMeshData& meshData);
-
- void createChunkRecursiveNonSkinned(const std::string& meshName, uint32_t chunkIndex, fbxsdk::FbxNode* parentNode,
- const std::vector<fbxsdk::FbxSurfaceMaterial*>& materials, const AuthoringResult& aResult);
-
- void createChunkRecursiveNonSkinned(const std::string& meshName, uint32_t chunkIndex, fbxsdk::FbxNode* parentNode,
- const std::vector<fbxsdk::FbxSurfaceMaterial*>& materials, const ExporterMeshData& meshData);
-
- void addControlPoints(fbxsdk::FbxMesh* mesh, const ExporterMeshData& meshData);
- void addBindPose();
-
- void generateSmoothingGroups(fbxsdk::FbxMesh* mesh, FbxSkin* skin);
- void removeDuplicateControlPoints(fbxsdk::FbxMesh* mesh, FbxSkin* skin);
-
- int32_t mInteriorIndex;
-};
-
-}
-}
-
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTEXTEXPORTERFBXWRITER_H
+#define NVBLASTEXTEXPORTERFBXWRITER_H
+
+#include "NvBlastExtExporter.h"
+#include <memory>
+#include <vector>
+#include <map>
+
+namespace fbxsdk
+{
+ class FbxScene;
+ class FbxNode;
+ class FbxMesh;
+ class FbxSkin;
+ class FbxManager;
+ class FbxSurfaceMaterial;
+ class FbxDisplayLayer;
+}
+
+struct NvBlastAsset;
+
+namespace Nv
+{
+namespace Blast
+{
+class Mesh;
+struct Triangle;
+struct CollisionHull;
+
+class FbxFileWriter : public IMeshFileWriter
+{
+public:
+
+ /**
+ Initialize FBX sdk and create scene.
+ */
+ FbxFileWriter();
+ //~FbxFileWriter() = default;
+
+ virtual void release() override;
+
+ /**
+ Get current scene;
+ */
+ fbxsdk::FbxScene* getScene();
+
+ /**
+ Append rendermesh to scene. Meshes constructed from arrays of triangles.
+ */
+ virtual bool appendMesh(const AuthoringResult& aResult, const char* assetName, bool nonSkinned) override;
+
+ /**
+ Append rendermesh to scene. Meshes constructed from arrays of vertex data (position, normal, uvs) and indices.
+ Position, normal and uv has separate index arrays.
+ */
+ virtual bool appendMesh(const ExporterMeshData& meshData, const char* assetName, bool nonSkinned) override;
+
+ /**
+ Save scene to file.
+ */
+ virtual bool saveToFile(const char* assetName, const char* outputPath) override;
+
+ /**
+ Set interior material index.
+ */
+ virtual void setInteriorIndex(int32_t index) override;
+
+ /**
+ Set true if FBX should be saved in ASCII mode.
+ */
+ bool bOutputFBXAscii;
+
+private:
+ std::vector<fbxsdk::FbxSurfaceMaterial*> mMaterials;
+ fbxsdk::FbxScene* mScene;
+ fbxsdk::FbxDisplayLayer* mRenderLayer;
+
+ //TODO we should track for every memory allocation and deallocate it not only for sdkManager
+ std::shared_ptr<fbxsdk::FbxManager> sdkManager;
+ std::map<uint32_t, fbxsdk::FbxNode*> chunkNodes;
+ std::map<uint32_t, physx::PxVec3> worldChunkPivots;
+
+ bool appendNonSkinnedMesh(const AuthoringResult& aResult, const char* assetName);
+ bool appendNonSkinnedMesh(const ExporterMeshData& meshData, const char* assetName);
+ void createMaterials(const ExporterMeshData& meshData);
+ void createMaterials(const AuthoringResult& aResult);
+
+ /**
+ Append collision geometry to scene. Each node with collision geometry has "ParentalChunkIndex" property, which contain index of chunk
+ which this collision geometry belongs to.
+ */
+ bool appendCollisionMesh(uint32_t meshCount, uint32_t* offsets, CollisionHull** hulls, const char* assetName);
+
+ uint32_t addCollisionHulls(uint32_t chunkIndex, fbxsdk::FbxDisplayLayer* displayLayer, fbxsdk::FbxNode* parentNode, uint32_t hullsCount, CollisionHull** hulls);
+ uint32_t createChunkRecursive(uint32_t currentCpIdx, uint32_t chunkIndex, fbxsdk::FbxNode *meshNode, fbxsdk::FbxNode* parentNode, fbxsdk::FbxSkin* skin, const AuthoringResult& aResult);
+ uint32_t createChunkRecursive(uint32_t currentCpIdx, uint32_t chunkIndex, fbxsdk::FbxNode *meshNode, fbxsdk::FbxNode* parentNode, fbxsdk::FbxSkin* skin, const ExporterMeshData& meshData);
+
+ void createChunkRecursiveNonSkinned(const std::string& meshName, uint32_t chunkIndex, fbxsdk::FbxNode* parentNode,
+ const std::vector<fbxsdk::FbxSurfaceMaterial*>& materials, const AuthoringResult& aResult);
+
+ void createChunkRecursiveNonSkinned(const std::string& meshName, uint32_t chunkIndex, fbxsdk::FbxNode* parentNode,
+ const std::vector<fbxsdk::FbxSurfaceMaterial*>& materials, const ExporterMeshData& meshData);
+
+ void addControlPoints(fbxsdk::FbxMesh* mesh, const ExporterMeshData& meshData);
+ void addBindPose();
+
+ void generateSmoothingGroups(fbxsdk::FbxMesh* mesh, FbxSkin* skin);
+ void removeDuplicateControlPoints(fbxsdk::FbxMesh* mesh, FbxSkin* skin);
+
+ int32_t mInteriorIndex;
+};
+
+}
+}
+
#endif // NVBLASTEXTEXPORTERFBXWRITER_H \ No newline at end of file
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterJsonCollision.cpp b/sdk/extensions/exporter/source/NvBlastExtExporterJsonCollision.cpp
index e4e2746..7b63461 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterJsonCollision.cpp
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterJsonCollision.cpp
@@ -1,107 +1,137 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "NvBlastExtExporterJsonCollision.h"
-#include "NvBlastExtAuthoringTypes.h"
-#include <PxVec3.h>
-#include <iostream>
-#include <sstream>
-#include <fstream>
-#include <iomanip>
-
-#define JS_NAME(name) "\"" << name << "\": "
-
-using namespace Nv::Blast;
-
-
-void serializaHullPolygon(std::ofstream& stream, const CollisionHull::HullPolygon& p, uint32_t indent)
-{
- std::string sindent(indent, '\t');
- std::string bindent(indent + 1, '\t');
- stream << sindent << "{\n" <<
- bindent << JS_NAME("mIndexBase") << p.mIndexBase << ",\n" <<
- bindent << JS_NAME("mPlane") << "[" << p.mPlane[0] << ", " << p.mPlane[1] << ", " << p.mPlane[2] << ", " << p.mPlane[3] << "],\n" <<
- bindent << JS_NAME("mNbVerts") << p.mNbVerts << "\n" <<
- sindent << "}";
-}
-void serializeCollisionHull(std::ofstream& stream, const CollisionHull& hl, uint32_t indent)
-{
- std::string sindent(indent, '\t');
- std::string bindent(indent + 1, '\t');
-
- stream << sindent << "{\n" << bindent << JS_NAME("indices") << "[";
- for (uint32_t i = 0; i < hl.indicesCount; ++i)
- {
- stream << hl.indices[i];
- if (i < hl.indicesCount - 1) stream << ", ";
- }
- stream << "],\n";
- stream << bindent << JS_NAME("points") << "[";
- for (uint32_t i = 0; i < hl.pointsCount; ++i)
- {
- auto& p = hl.points[i];
- stream << p.x << ", " << p.y << ", " << p.z;
- if (i < hl.pointsCount - 1) stream << ", ";
- }
- stream << "],\n";
- stream << bindent << JS_NAME("polygonData") << "[\n";
- for (uint32_t i = 0; i < hl.polygonDataCount; ++i)
- {
- serializaHullPolygon(stream, hl.polygonData[i], indent + 1);
- if (i < hl.polygonDataCount - 1) stream << ", ";
- stream << "\n";
- }
- stream << bindent << "]\n";
- stream << sindent << "}";
-}
-
-bool JsonCollisionExporter::writeCollision(const char* path, uint32_t meshCount, const uint32_t* meshOffsets, const CollisionHull* hulls)
-{
- std::ofstream stream(path, std::ios::out);
- stream << std::fixed << std::setprecision(8);
- if (!stream.is_open())
- {
- std::cout << "Can't open output stream" << std::endl;
- return false;
- }
-
- stream << "{\n" << "\t" << JS_NAME("CollisionData") << "[\n";
- for (uint32_t i = 0; i < meshCount; ++i)
- {
- stream << "\t\t" << "[\n";
- for (uint32_t j = meshOffsets[i]; j < meshOffsets[i + 1]; ++j)
- {
- serializeCollisionHull(stream, hulls[j], 3);
- stream << ((j < meshOffsets[i + 1] - 1) ? ",\n" : "\n");
- }
- stream << "\t\t" << ((i < meshCount - 1) ? "], \n" : "]\n");
- }
- stream << "\t]\n}";
- stream.close();
- return true;
-};
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastExtExporterJsonCollision.h"
+#include "NvBlastExtAuthoringTypes.h"
+#include <PxVec3.h>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <iomanip>
+
+#define JS_NAME(name) "\"" << name << "\": "
+
+using namespace Nv::Blast;
+
+
+void serializaHullPolygon(std::ofstream& stream, const CollisionHull::HullPolygon& p, uint32_t indent)
+{
+ std::string sindent(indent, '\t');
+ std::string bindent(indent + 1, '\t');
+ stream << sindent << "{\n" <<
+ bindent << JS_NAME("mIndexBase") << p.mIndexBase << ",\n" <<
+ bindent << JS_NAME("mPlane") << "[" << p.mPlane[0] << ", " << p.mPlane[1] << ", " << p.mPlane[2] << ", " << p.mPlane[3] << "],\n" <<
+ bindent << JS_NAME("mNbVerts") << p.mNbVerts << "\n" <<
+ sindent << "}";
+}
+void serializeCollisionHull(std::ofstream& stream, const CollisionHull& hl, uint32_t indent)
+{
+ std::string sindent(indent, '\t');
+ std::string bindent(indent + 1, '\t');
+
+ stream << sindent << "{\n" << bindent << JS_NAME("indices") << "[";
+ for (uint32_t i = 0; i < hl.indicesCount; ++i)
+ {
+ stream << hl.indices[i];
+ if (i < hl.indicesCount - 1) stream << ", ";
+ }
+ stream << "],\n";
+ stream << bindent << JS_NAME("points") << "[";
+ for (uint32_t i = 0; i < hl.pointsCount; ++i)
+ {
+ auto& p = hl.points[i];
+ stream << p.x << ", " << p.y << ", " << p.z;
+ if (i < hl.pointsCount - 1) stream << ", ";
+ }
+ stream << "],\n";
+ stream << bindent << JS_NAME("polygonData") << "[\n";
+ for (uint32_t i = 0; i < hl.polygonDataCount; ++i)
+ {
+ serializaHullPolygon(stream, hl.polygonData[i], indent + 1);
+ if (i < hl.polygonDataCount - 1) stream << ", ";
+ stream << "\n";
+ }
+ stream << bindent << "]\n";
+ stream << sindent << "}";
+}
+
+
+/**
+Implementation of object which serializes collision geometry to JSON format.
+*/
+class JsonCollisionExporter : public IJsonCollisionExporter
+{
+public:
+ JsonCollisionExporter() {}
+ ~JsonCollisionExporter() = default;
+
+ virtual void release() override;
+
+ virtual bool writeCollision(const char* path, uint32_t chunkCount, const uint32_t* hullOffsets, const CollisionHull* const * hulls) override;
+};
+
+
+void
+JsonCollisionExporter::release()
+{
+ delete this;
+}
+
+
+bool
+JsonCollisionExporter::JsonCollisionExporter::writeCollision(const char* path, uint32_t chunkCount, const uint32_t* hullOffsets, const CollisionHull* const * hulls)
+{
+ std::ofstream stream(path, std::ios::out);
+ stream << std::fixed << std::setprecision(8);
+ if (!stream.is_open())
+ {
+ std::cout << "Can't open output stream" << std::endl;
+ return false;
+ }
+
+ stream << "{\n" << "\t" << JS_NAME("CollisionData") << "[\n";
+ for (uint32_t i = 0; i < chunkCount; ++i)
+ {
+ stream << "\t\t" << "[\n";
+ for (uint32_t j = hullOffsets[i]; j < hullOffsets[i + 1]; ++j)
+ {
+ serializeCollisionHull(stream, *hulls[j], 3);
+ stream << ((j < hullOffsets[i + 1] - 1) ? ",\n" : "\n");
+ }
+ stream << "\t\t" << ((i < chunkCount - 1) ? "], \n" : "]\n");
+ }
+ stream << "\t]\n}";
+ stream.close();
+ return true;
+};
+
+
+IJsonCollisionExporter* NvBlastExtExporterCreateJsonCollisionExporter()
+{
+ return new JsonCollisionExporter;
+}
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterObjReader.cpp b/sdk/extensions/exporter/source/NvBlastExtExporterObjReader.cpp
index 16da7d6..f188912 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterObjReader.cpp
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterObjReader.cpp
@@ -1,162 +1,162 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "NvBlastExtExporterObjReader.h"
-
-#pragma warning(push)
-#pragma warning(disable:4706)
-#pragma warning(disable:4702)
-#define TINYOBJLOADER_IMPLEMENTATION
-#include "tiny_obj_loader.h"
-#pragma warning(pop)
-
-
-#include <iostream>
-#include "PxVec3.h"
-#include "PxVec2.h"
-#include "NvBlastExtAuthoringMesh.h"
-
-using physx::PxVec3;
-using physx::PxVec2;
-using namespace Nv::Blast;
-
-ObjFileReader::ObjFileReader()
-{
-}
-
-void ObjFileReader::release()
-{
- delete this;
-}
-
-void ObjFileReader::loadFromFile(const char* filename)
-{
- std::vector<tinyobj::shape_t> shapes;
- std::vector<tinyobj::material_t> mats;
- std::string err;
- std::string mtlPath;
-
- int32_t lastDelimeter = strlen(filename);
-
- while (lastDelimeter > 0 && filename[lastDelimeter] != '/' && filename[lastDelimeter] != '\\')
- {
- lastDelimeter--;
- }
- mtlPath = std::string(filename, filename + lastDelimeter);
- mtlPath += '/';
-
- bool ret = tinyobj::LoadObj(shapes, mats, err, filename, mtlPath.c_str());
-
- // can't load?
- if (!ret)
- {
- return;
- }
- if (shapes.size() > 1)
- {
- std::cout << "Can load only one object per mesh" << std::endl;
- }
-
- if (!mats.empty())
- {
- if (mats.size() == 1 && mats[0].name == "")
- {
- mats[0].name = "Default";
- }
- for (uint32_t i = 0; i < mats.size(); ++i)
- {
- mMaterialNames.push_back(mats[i].name);
- }
- }
-
- mVertexPositions.clear();
- mVertexNormals.clear();
- mVertexUv.clear();
- mIndices.clear();
-
- auto& psVec = shapes[0].mesh.positions;
- for (uint32_t i = 0; i < psVec.size() / 3; ++i)
- {
- mVertexPositions.push_back(PxVec3(psVec[i * 3], psVec[i * 3 + 1], psVec[i * 3 + 2]));
- }
- auto& nmVec = shapes[0].mesh.normals;
- for (uint32_t i = 0; i < nmVec.size() / 3; ++i)
- {
- mVertexNormals.push_back(PxVec3(nmVec[i * 3], nmVec[i * 3 + 1], nmVec[i * 3 + 2]));
- }
- auto& txVec = shapes[0].mesh.texcoords;
- for (uint32_t i = 0; i < txVec.size() / 2; ++i)
- {
- mVertexUv.push_back(PxVec2(txVec[i * 2], txVec[i * 2 + 1]));
- }
-
- mIndices = shapes[0].mesh.indices;
- mPerFaceMatId = shapes[0].mesh.material_ids;
- for (uint32_t i = 0; i < mPerFaceMatId.size(); ++i)
- {
- if (mPerFaceMatId[i] == -1) // TinyOBJ loader sets ID to -1 when .mtl file not found. Set to default 0 material.
- {
- mPerFaceMatId[i] = 0;
- }
- }
-
-}
-
-
-bool ObjFileReader::isCollisionLoaded()
-{
- return false;
-};
-
-
-uint32_t ObjFileReader::getCollision(uint32_t*& hullsOffset, Nv::Blast::CollisionHull**& hulls)
-{
- hullsOffset = nullptr;
- hulls = nullptr;
- return 0;
-};
-
-physx::PxVec3* ObjFileReader::getPositionArray()
-{
- return mVertexPositions.data();
-};
-
-physx::PxVec3* ObjFileReader::getNormalsArray()
-{
- return mVertexNormals.data();
-};
-
-physx::PxVec2* ObjFileReader::getUvArray()
-{
- return mVertexUv.data();
-};
-
-uint32_t* ObjFileReader::getIndexArray()
-{
- return mIndices.data();
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastExtExporterObjReader.h"
+
+#pragma warning(push)
+#pragma warning(disable:4706)
+#pragma warning(disable:4702)
+#define TINYOBJLOADER_IMPLEMENTATION
+#include "tiny_obj_loader.h"
+#pragma warning(pop)
+
+
+#include <iostream>
+#include "PxVec3.h"
+#include "PxVec2.h"
+#include "NvBlastExtAuthoringMesh.h"
+
+using physx::PxVec3;
+using physx::PxVec2;
+using namespace Nv::Blast;
+
+ObjFileReader::ObjFileReader()
+{
+}
+
+void ObjFileReader::release()
+{
+ delete this;
+}
+
+void ObjFileReader::loadFromFile(const char* filename)
+{
+ std::vector<tinyobj::shape_t> shapes;
+ std::vector<tinyobj::material_t> mats;
+ std::string err;
+ std::string mtlPath;
+
+ int32_t lastDelimeter = strlen(filename);
+
+ while (lastDelimeter > 0 && filename[lastDelimeter] != '/' && filename[lastDelimeter] != '\\')
+ {
+ lastDelimeter--;
+ }
+ mtlPath = std::string(filename, filename + lastDelimeter);
+ mtlPath += '/';
+
+ bool ret = tinyobj::LoadObj(shapes, mats, err, filename, mtlPath.c_str());
+
+ // can't load?
+ if (!ret)
+ {
+ return;
+ }
+ if (shapes.size() > 1)
+ {
+ std::cout << "Can load only one object per mesh" << std::endl;
+ }
+
+ if (!mats.empty())
+ {
+ if (mats.size() == 1 && mats[0].name == "")
+ {
+ mats[0].name = "Default";
+ }
+ for (uint32_t i = 0; i < mats.size(); ++i)
+ {
+ mMaterialNames.push_back(mats[i].name);
+ }
+ }
+
+ mVertexPositions.clear();
+ mVertexNormals.clear();
+ mVertexUv.clear();
+ mIndices.clear();
+
+ auto& psVec = shapes[0].mesh.positions;
+ for (uint32_t i = 0; i < psVec.size() / 3; ++i)
+ {
+ mVertexPositions.push_back(PxVec3(psVec[i * 3], psVec[i * 3 + 1], psVec[i * 3 + 2]));
+ }
+ auto& nmVec = shapes[0].mesh.normals;
+ for (uint32_t i = 0; i < nmVec.size() / 3; ++i)
+ {
+ mVertexNormals.push_back(PxVec3(nmVec[i * 3], nmVec[i * 3 + 1], nmVec[i * 3 + 2]));
+ }
+ auto& txVec = shapes[0].mesh.texcoords;
+ for (uint32_t i = 0; i < txVec.size() / 2; ++i)
+ {
+ mVertexUv.push_back(PxVec2(txVec[i * 2], txVec[i * 2 + 1]));
+ }
+
+ mIndices = shapes[0].mesh.indices;
+ mPerFaceMatId = shapes[0].mesh.material_ids;
+ for (uint32_t i = 0; i < mPerFaceMatId.size(); ++i)
+ {
+ if (mPerFaceMatId[i] == -1) // TinyOBJ loader sets ID to -1 when .mtl file not found. Set to default 0 material.
+ {
+ mPerFaceMatId[i] = 0;
+ }
+ }
+
+}
+
+
+bool ObjFileReader::isCollisionLoaded()
+{
+ return false;
+};
+
+
+uint32_t ObjFileReader::getCollision(uint32_t*& hullsOffset, Nv::Blast::CollisionHull**& hulls)
+{
+ hullsOffset = nullptr;
+ hulls = nullptr;
+ return 0;
+};
+
+physx::PxVec3* ObjFileReader::getPositionArray()
+{
+ return mVertexPositions.data();
+};
+
+physx::PxVec3* ObjFileReader::getNormalsArray()
+{
+ return mVertexNormals.data();
+};
+
+physx::PxVec2* ObjFileReader::getUvArray()
+{
+ return mVertexUv.data();
+};
+
+uint32_t* ObjFileReader::getIndexArray()
+{
+ return mIndices.data();
}; \ No newline at end of file
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterObjReader.h b/sdk/extensions/exporter/source/NvBlastExtExporterObjReader.h
index c1210ab..7657be3 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterObjReader.h
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterObjReader.h
@@ -1,126 +1,126 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#ifndef NVBLASTEXTEXPORTEROBJREADER_H
-#define NVBLASTEXTEXPORTEROBJREADER_H
-#include <memory>
-#include <string>
-#include <vector>
-#include "NvBlastExtExporter.h"
-
-namespace Nv
-{
-namespace Blast
-{
-class Mesh;
-
-class ObjFileReader : public IMeshFileReader
-{
-public:
- ObjFileReader();
- ~ObjFileReader() = default;
-
- virtual void release() override;
-
- /*
- Load from the specified file path, returning a mesh or nullptr if failed
- */
- virtual void loadFromFile(const char* filename) override;
-
- virtual uint32_t getVerticesCount() const override
- {
- return mVertexPositions.size();
- }
-
- virtual uint32_t getIndicesCount() const override
- {
- return mIndices.size();
- }
-
- /**
- Check whether file contained an collision geometry
- */
- virtual bool isCollisionLoaded() override;
-
- /**
- Retrieve collision geometry if it exist
- */
- virtual uint32_t getCollision(uint32_t*& hullsOffset, Nv::Blast::CollisionHull**& hulls) override;
-
- /**
- Get loaded vertex positions
- */
- virtual physx::PxVec3* getPositionArray() override;
- /**
- Get loaded vertex normals
- */
- virtual physx::PxVec3* getNormalsArray() override;
- /**
- Get loaded vertex uv-coordinates
- */
- virtual physx::PxVec2* getUvArray() override;
- /**
- Get loaded triangle indices
- */
- virtual uint32_t* getIndexArray() override;
-
- /**
- Get loaded per triangle material ids.
- */
- int32_t* getMaterialIds() override { return mPerFaceMatId.data(); };
-
- /**
- Get loaded per triangle smoothing groups. Currently not supported by OBJ.
- */
- int32_t* getSmoothingGroups() override { return nullptr; };
-
- /**
- Get material name.
- */
- const char* getMaterialName(int32_t id) override { return mMaterialNames[id].c_str(); }
-
- /**
- Get material count.
- */
- int32_t getMaterialCount() { return mMaterialNames.size(); };
-
-private:
- std::vector<physx::PxVec3> mVertexPositions;
- std::vector<physx::PxVec3> mVertexNormals;
- std::vector<physx::PxVec2> mVertexUv;
- std::vector<uint32_t> mIndices;
-
- std::vector<std::string> mMaterialNames;
- std::vector<int32_t> mPerFaceMatId;
-
-};
-
-}
-}
-
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTEXTEXPORTEROBJREADER_H
+#define NVBLASTEXTEXPORTEROBJREADER_H
+#include <memory>
+#include <string>
+#include <vector>
+#include "NvBlastExtExporter.h"
+
+namespace Nv
+{
+namespace Blast
+{
+class Mesh;
+
+class ObjFileReader : public IMeshFileReader
+{
+public:
+ ObjFileReader();
+ ~ObjFileReader() = default;
+
+ virtual void release() override;
+
+ /*
+ Load from the specified file path, returning a mesh or nullptr if failed
+ */
+ virtual void loadFromFile(const char* filename) override;
+
+ virtual uint32_t getVerticesCount() const override
+ {
+ return mVertexPositions.size();
+ }
+
+ virtual uint32_t getIndicesCount() const override
+ {
+ return mIndices.size();
+ }
+
+ /**
+ Check whether file contained an collision geometry
+ */
+ virtual bool isCollisionLoaded() override;
+
+ /**
+ Retrieve collision geometry if it exist
+ */
+ virtual uint32_t getCollision(uint32_t*& hullsOffset, Nv::Blast::CollisionHull**& hulls) override;
+
+ /**
+ Get loaded vertex positions
+ */
+ virtual physx::PxVec3* getPositionArray() override;
+ /**
+ Get loaded vertex normals
+ */
+ virtual physx::PxVec3* getNormalsArray() override;
+ /**
+ Get loaded vertex uv-coordinates
+ */
+ virtual physx::PxVec2* getUvArray() override;
+ /**
+ Get loaded triangle indices
+ */
+ virtual uint32_t* getIndexArray() override;
+
+ /**
+ Get loaded per triangle material ids.
+ */
+ int32_t* getMaterialIds() override { return mPerFaceMatId.data(); };
+
+ /**
+ Get loaded per triangle smoothing groups. Currently not supported by OBJ.
+ */
+ int32_t* getSmoothingGroups() override { return nullptr; };
+
+ /**
+ Get material name.
+ */
+ const char* getMaterialName(int32_t id) override { return mMaterialNames[id].c_str(); }
+
+ /**
+ Get material count.
+ */
+ int32_t getMaterialCount() { return mMaterialNames.size(); };
+
+private:
+ std::vector<physx::PxVec3> mVertexPositions;
+ std::vector<physx::PxVec3> mVertexNormals;
+ std::vector<physx::PxVec2> mVertexUv;
+ std::vector<uint32_t> mIndices;
+
+ std::vector<std::string> mMaterialNames;
+ std::vector<int32_t> mPerFaceMatId;
+
+};
+
+}
+}
+
#endif // NVBLASTEXTEXPORTEROBJREADER_H \ No newline at end of file
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.cpp b/sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.cpp
index 722a258..e6ec276 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.cpp
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.cpp
@@ -1,265 +1,265 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "NvBlastExtExporterObjWriter.h"
-#include <PxVec3.h>
-#include <sstream>
-#include "NvBlastExtAuthoringTypes.h"
-#include "NvBlastExtAuthoringMesh.h"
-#include <algorithm>
-
-
-using namespace physx;
-using namespace Nv::Blast;
-
-char* gTexPath = "";
-
-void ObjFileWriter::release()
-{
- delete this;
-}
-
-void ObjFileWriter::setInteriorIndex(int32_t index)
-{
- mIntSurfaceMatIndex = index;
-}
-
-bool CompByMaterial(const Triangle& a, const Triangle& b)
-{
- return a.materialId < b.materialId;
-}
-
-bool ObjFileWriter::appendMesh(const AuthoringResult& aResult, const char* /*assetName*/, bool /*nonSkinned*/)
-{
- mMeshData = std::shared_ptr<ExporterMeshData>(new ExporterMeshData(), [](ExporterMeshData* md)
- {
- //delete[] md->hulls;
- //delete[] md->hullsOffsets;
- delete[] md->normals;
- //delete[] md->normIndex;
- delete[] md->posIndex;
- delete[] md->positions;
- delete[] md->submeshOffsets;
- //delete[] md->texIndex;
- delete[] md->submeshMats;
- delete[] md->uvs;
- delete md;
- });
-
-
- ExporterMeshData& md = *mMeshData.get();
- uint32_t triCount = aResult.geometryOffset[aResult.chunkCount];
- md.meshCount = aResult.chunkCount;
- md.submeshCount = aResult.materialCount;
-
- int32_t additionalMats = 0;
-
- if (mIntSurfaceMatIndex == -1 || mIntSurfaceMatIndex >= (int32_t)md.submeshCount)
- {
- md.submeshCount += 1;
- mIntSurfaceMatIndex = md.submeshCount - 1;
- additionalMats = 1;
- }
-
- md.submeshOffsets = new uint32_t[md.meshCount * md.submeshCount + 1];
- md.submeshMats = new Material[md.submeshCount];
-
- for (uint32_t i = 0; i < md.submeshCount - additionalMats; ++i)
- {
- md.submeshMats[i].name = aResult.materialNames[i];
- md.submeshMats[i].diffuse_tex = nullptr;
- }
-
- if (additionalMats)
- {
- md.submeshMats[mIntSurfaceMatIndex].name = interiorNameStr.c_str();
- md.submeshMats[mIntSurfaceMatIndex].diffuse_tex = nullptr;
- }
- md.positionsCount = triCount * 3;
- md.normalsCount = md.positionsCount;
- md.uvsCount = md.positionsCount;
- md.positions = new PxVec3[md.positionsCount];
- md.normals = new PxVec3[md.normalsCount];
- md.uvs = new PxVec2[md.uvsCount];
-
- md.posIndex = new uint32_t[triCount * 3];
- md.normIndex = md.posIndex;
- md.texIndex = md.posIndex;
-
-
-
- /**
- Now we need to sort input trianles chunk they belong to, then by material;
- */
- std::vector<Triangle> sorted;
- sorted.reserve(triCount);
-
-
- int32_t perChunkOffset = 0;
- for (uint32_t i = 0; i < md.meshCount; ++i)
- {
- std::vector<uint32_t> perMaterialCount(md.submeshCount);
-
- uint32_t first = aResult.geometryOffset[i];
- uint32_t last = aResult.geometryOffset[i + 1];
- uint32_t firstInSorted = sorted.size();
- for (uint32_t t = first; t < last; ++t)
- {
- sorted.push_back(aResult.geometry[t]);
- int32_t cmat = sorted.back().materialId;
- if (cmat == MATERIAL_INTERIOR)
- {
- cmat = mIntSurfaceMatIndex;
- }
- perMaterialCount[cmat]++;
- }
- for (uint32_t mof = 0; mof < md.submeshCount; ++mof)
- {
- md.submeshOffsets[i * md.submeshCount + mof] = perChunkOffset * 3;
- perChunkOffset += perMaterialCount[mof];
- }
- std::sort(sorted.begin() + firstInSorted, sorted.end(), CompByMaterial);
- }
- md.submeshOffsets[md.meshCount * md.submeshCount] = perChunkOffset * 3;
-
- for (uint32_t vc = 0; vc < triCount; ++vc)
- {
- Triangle& tri = sorted[vc];
- uint32_t i = vc * 3;
- md.positions[i+0] = tri.a.p;
- md.positions[i+1] = tri.b.p;
- md.positions[i+2] = tri.c.p;
-
- md.normals[i+0] = tri.a.n;
- md.normals[i+1] = tri.b.n;
- md.normals[i+2] = tri.c.n;
-
- md.uvs[i+0] = tri.a.uv[0];
- md.uvs[i+1] = tri.b.uv[0];
- md.uvs[i+2] = tri.c.uv[0];
-
- md.posIndex[i + 0] = i + 0;
- md.posIndex[i + 1] = i + 1;
- md.posIndex[i + 2] = i + 2;
- }
- return true;
-}
-
-bool ObjFileWriter::appendMesh(const ExporterMeshData& meshData, const char* /*assetName*/, bool /*nonSkinned*/)
-{
- mMeshData = std::shared_ptr<ExporterMeshData>(new ExporterMeshData(meshData));
- return true;
-}
-
-bool ObjFileWriter::saveToFile(const char* assetName, const char* outputPath)
-{
- if (mMeshData.get() == nullptr)
- {
- return false;
- }
- const ExporterMeshData& md = *mMeshData.get();
-
- uint32_t chunkCount = md.meshCount;
-
- // export materials (mtl file)
- {
- std::ostringstream mtlFilePath;
- mtlFilePath << outputPath << "\\" << assetName << ".mtl";
- FILE* f = fopen(mtlFilePath.str().c_str(), "w");
- if (!f)
- return false;
-
- for (uint32_t submeshIndex = 0; submeshIndex < md.submeshCount; ++submeshIndex)
- {
- fprintf(f, "newmtl %s\n", md.submeshMats[submeshIndex].name);
- if (md.submeshMats[submeshIndex].diffuse_tex != nullptr)
- {
- fprintf(f, "\tmap_Kd %s\n", md.submeshMats[submeshIndex].diffuse_tex);
- }
- else
- {
- fprintf(f, "\tKd %f %f %f\n", float(rand()) / RAND_MAX, float(rand()) / RAND_MAX, float(rand()) / RAND_MAX);
- }
- fprintf(f, "\n");
- }
-
- fclose(f);
- }
-
- /// Export geometry to *.obj file
- {
- std::ostringstream objFilePath;
- objFilePath << outputPath << "\\" << assetName << ".obj";
- FILE* f = fopen(objFilePath.str().c_str(), "w");
- if (!f)
- return false;
-
- fprintf(f, "mtllib %s.mtl\n", assetName);
- fprintf(f, "o frac \n");
-
-
- /// Write compressed vertices
- for (uint32_t i = 0; i < md.positionsCount; ++i)
- {
- fprintf(f, "v %.4f %.4f %.4f\n", md.positions[i].x, md.positions[i].y, md.positions[i].z);
- }
- for (uint32_t i = 0; i < md.normalsCount; ++i)
- {
- fprintf(f, "vn %.4f %.4f %.4f\n", md.normals[i].x, md.normals[i].y, md.normals[i].z);
- }
- for (uint32_t i = 0; i < md.uvsCount; ++i)
- {
- fprintf(f, "vt %.4f %.4f\n", md.uvs[i].x, md.uvs[i].y);
- }
-
- for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
- {
- fprintf(f, "g %d \n", chunkIndex);
- for (uint32_t submeshIndex = 0; submeshIndex < md.submeshCount; ++submeshIndex)
- {
- uint32_t firstIdx = md.submeshOffsets[chunkIndex * md.submeshCount + submeshIndex];
- uint32_t lastIdx = md.submeshOffsets[chunkIndex * md.submeshCount + submeshIndex + 1];
- if (firstIdx == lastIdx) // There is no trianlges in this submesh.
- {
- continue;
- }
- fprintf(f, "usemtl %s\n", md.submeshMats[submeshIndex].name);
- for (uint32_t i = firstIdx; i < lastIdx; i += 3)
- {
- fprintf(f, "f %d/%d/%d ", md.posIndex[i] + 1, md.texIndex[i] + 1, md.normIndex[i] + 1);
- fprintf(f, "%d/%d/%d ", md.posIndex[i + 1] + 1, md.texIndex[i + 1] + 1, md.normIndex[i + 1] + 1);
- fprintf(f, "%d/%d/%d \n", md.posIndex[i + 2] + 1, md.texIndex[i + 2] + 1, md.normIndex[i + 2] + 1);
- }
- }
- }
- fclose(f);
- }
- return true;
-
-}
-
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastExtExporterObjWriter.h"
+#include <PxVec3.h>
+#include <sstream>
+#include "NvBlastExtAuthoringTypes.h"
+#include "NvBlastExtAuthoringMesh.h"
+#include <algorithm>
+
+
+using namespace physx;
+using namespace Nv::Blast;
+
+char* gTexPath = "";
+
+void ObjFileWriter::release()
+{
+ delete this;
+}
+
+void ObjFileWriter::setInteriorIndex(int32_t index)
+{
+ mIntSurfaceMatIndex = index;
+}
+
+bool CompByMaterial(const Triangle& a, const Triangle& b)
+{
+ return a.materialId < b.materialId;
+}
+
+bool ObjFileWriter::appendMesh(const AuthoringResult& aResult, const char* /*assetName*/, bool /*nonSkinned*/)
+{
+ mMeshData = std::shared_ptr<ExporterMeshData>(new ExporterMeshData(), [](ExporterMeshData* md)
+ {
+ //delete[] md->hulls;
+ //delete[] md->hullsOffsets;
+ delete[] md->normals;
+ //delete[] md->normIndex;
+ delete[] md->posIndex;
+ delete[] md->positions;
+ delete[] md->submeshOffsets;
+ //delete[] md->texIndex;
+ delete[] md->submeshMats;
+ delete[] md->uvs;
+ delete md;
+ });
+
+
+ ExporterMeshData& md = *mMeshData.get();
+ uint32_t triCount = aResult.geometryOffset[aResult.chunkCount];
+ md.meshCount = aResult.chunkCount;
+ md.submeshCount = aResult.materialCount;
+
+ int32_t additionalMats = 0;
+
+ if (mIntSurfaceMatIndex == -1 || mIntSurfaceMatIndex >= (int32_t)md.submeshCount)
+ {
+ md.submeshCount += 1;
+ mIntSurfaceMatIndex = md.submeshCount - 1;
+ additionalMats = 1;
+ }
+
+ md.submeshOffsets = new uint32_t[md.meshCount * md.submeshCount + 1];
+ md.submeshMats = new Material[md.submeshCount];
+
+ for (uint32_t i = 0; i < md.submeshCount - additionalMats; ++i)
+ {
+ md.submeshMats[i].name = aResult.materialNames[i];
+ md.submeshMats[i].diffuse_tex = nullptr;
+ }
+
+ if (additionalMats)
+ {
+ md.submeshMats[mIntSurfaceMatIndex].name = interiorNameStr.c_str();
+ md.submeshMats[mIntSurfaceMatIndex].diffuse_tex = nullptr;
+ }
+ md.positionsCount = triCount * 3;
+ md.normalsCount = md.positionsCount;
+ md.uvsCount = md.positionsCount;
+ md.positions = new PxVec3[md.positionsCount];
+ md.normals = new PxVec3[md.normalsCount];
+ md.uvs = new PxVec2[md.uvsCount];
+
+ md.posIndex = new uint32_t[triCount * 3];
+ md.normIndex = md.posIndex;
+ md.texIndex = md.posIndex;
+
+
+
+ /**
+ Now we need to sort input trianles chunk they belong to, then by material;
+ */
+ std::vector<Triangle> sorted;
+ sorted.reserve(triCount);
+
+
+ int32_t perChunkOffset = 0;
+ for (uint32_t i = 0; i < md.meshCount; ++i)
+ {
+ std::vector<uint32_t> perMaterialCount(md.submeshCount);
+
+ uint32_t first = aResult.geometryOffset[i];
+ uint32_t last = aResult.geometryOffset[i + 1];
+ uint32_t firstInSorted = sorted.size();
+ for (uint32_t t = first; t < last; ++t)
+ {
+ sorted.push_back(aResult.geometry[t]);
+ int32_t cmat = sorted.back().materialId;
+ if (cmat == MATERIAL_INTERIOR)
+ {
+ cmat = mIntSurfaceMatIndex;
+ }
+ perMaterialCount[cmat]++;
+ }
+ for (uint32_t mof = 0; mof < md.submeshCount; ++mof)
+ {
+ md.submeshOffsets[i * md.submeshCount + mof] = perChunkOffset * 3;
+ perChunkOffset += perMaterialCount[mof];
+ }
+ std::sort(sorted.begin() + firstInSorted, sorted.end(), CompByMaterial);
+ }
+ md.submeshOffsets[md.meshCount * md.submeshCount] = perChunkOffset * 3;
+
+ for (uint32_t vc = 0; vc < triCount; ++vc)
+ {
+ Triangle& tri = sorted[vc];
+ uint32_t i = vc * 3;
+ md.positions[i+0] = tri.a.p;
+ md.positions[i+1] = tri.b.p;
+ md.positions[i+2] = tri.c.p;
+
+ md.normals[i+0] = tri.a.n;
+ md.normals[i+1] = tri.b.n;
+ md.normals[i+2] = tri.c.n;
+
+ md.uvs[i+0] = tri.a.uv[0];
+ md.uvs[i+1] = tri.b.uv[0];
+ md.uvs[i+2] = tri.c.uv[0];
+
+ md.posIndex[i + 0] = i + 0;
+ md.posIndex[i + 1] = i + 1;
+ md.posIndex[i + 2] = i + 2;
+ }
+ return true;
+}
+
+bool ObjFileWriter::appendMesh(const ExporterMeshData& meshData, const char* /*assetName*/, bool /*nonSkinned*/)
+{
+ mMeshData = std::shared_ptr<ExporterMeshData>(new ExporterMeshData(meshData));
+ return true;
+}
+
+bool ObjFileWriter::saveToFile(const char* assetName, const char* outputPath)
+{
+ if (mMeshData.get() == nullptr)
+ {
+ return false;
+ }
+ const ExporterMeshData& md = *mMeshData.get();
+
+ uint32_t chunkCount = md.meshCount;
+
+ // export materials (mtl file)
+ {
+ std::ostringstream mtlFilePath;
+ mtlFilePath << outputPath << "\\" << assetName << ".mtl";
+ FILE* f = fopen(mtlFilePath.str().c_str(), "w");
+ if (!f)
+ return false;
+
+ for (uint32_t submeshIndex = 0; submeshIndex < md.submeshCount; ++submeshIndex)
+ {
+ fprintf(f, "newmtl %s\n", md.submeshMats[submeshIndex].name);
+ if (md.submeshMats[submeshIndex].diffuse_tex != nullptr)
+ {
+ fprintf(f, "\tmap_Kd %s\n", md.submeshMats[submeshIndex].diffuse_tex);
+ }
+ else
+ {
+ fprintf(f, "\tKd %f %f %f\n", float(rand()) / RAND_MAX, float(rand()) / RAND_MAX, float(rand()) / RAND_MAX);
+ }
+ fprintf(f, "\n");
+ }
+
+ fclose(f);
+ }
+
+ /// Export geometry to *.obj file
+ {
+ std::ostringstream objFilePath;
+ objFilePath << outputPath << "\\" << assetName << ".obj";
+ FILE* f = fopen(objFilePath.str().c_str(), "w");
+ if (!f)
+ return false;
+
+ fprintf(f, "mtllib %s.mtl\n", assetName);
+ fprintf(f, "o frac \n");
+
+
+ /// Write compressed vertices
+ for (uint32_t i = 0; i < md.positionsCount; ++i)
+ {
+ fprintf(f, "v %.4f %.4f %.4f\n", md.positions[i].x, md.positions[i].y, md.positions[i].z);
+ }
+ for (uint32_t i = 0; i < md.normalsCount; ++i)
+ {
+ fprintf(f, "vn %.4f %.4f %.4f\n", md.normals[i].x, md.normals[i].y, md.normals[i].z);
+ }
+ for (uint32_t i = 0; i < md.uvsCount; ++i)
+ {
+ fprintf(f, "vt %.4f %.4f\n", md.uvs[i].x, md.uvs[i].y);
+ }
+
+ for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
+ {
+ fprintf(f, "g %d \n", chunkIndex);
+ for (uint32_t submeshIndex = 0; submeshIndex < md.submeshCount; ++submeshIndex)
+ {
+ uint32_t firstIdx = md.submeshOffsets[chunkIndex * md.submeshCount + submeshIndex];
+ uint32_t lastIdx = md.submeshOffsets[chunkIndex * md.submeshCount + submeshIndex + 1];
+ if (firstIdx == lastIdx) // There is no trianlges in this submesh.
+ {
+ continue;
+ }
+ fprintf(f, "usemtl %s\n", md.submeshMats[submeshIndex].name);
+ for (uint32_t i = firstIdx; i < lastIdx; i += 3)
+ {
+ fprintf(f, "f %d/%d/%d ", md.posIndex[i] + 1, md.texIndex[i] + 1, md.normIndex[i] + 1);
+ fprintf(f, "%d/%d/%d ", md.posIndex[i + 1] + 1, md.texIndex[i + 1] + 1, md.normIndex[i + 1] + 1);
+ fprintf(f, "%d/%d/%d \n", md.posIndex[i + 2] + 1, md.texIndex[i + 2] + 1, md.normIndex[i + 2] + 1);
+ }
+ }
+ }
+ fclose(f);
+ }
+ return true;
+
+}
+
diff --git a/sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.h b/sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.h
index 68e025d..7685ea2 100644..100755
--- a/sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.h
+++ b/sdk/extensions/exporter/source/NvBlastExtExporterObjWriter.h
@@ -1,80 +1,80 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#ifndef NVBLASTEXTEXPORTEROBJWRITER_H
-#define NVBLASTEXTEXPORTEROBJWRITER_H
-
-#include "NvBlastExtExporter.h"
-#include <memory>
-#include <vector>
-#include <PxVec2.h>
-#include <PxVec3.h>
-#include <string>
-struct NvBlastAsset;
-
-namespace Nv
-{
-namespace Blast
-{
-
-class ObjFileWriter : public IMeshFileWriter
-{
-public:
-
- ObjFileWriter(): mIntSurfaceMatIndex(-1), interiorNameStr("INTERIOR_MATERIAL") { };
- ~ObjFileWriter() = default;
-
- virtual void release() override;
-
- virtual bool appendMesh(const AuthoringResult& aResult, const char* assetName, bool nonSkinned) override;
-
- /**
- Append rendermesh to scene. Meshes constructed from arrays of vertices and indices
- */
- virtual bool appendMesh(const ExporterMeshData& meshData, const char* assetName, bool nonSkinned) override;
-
- /**
- Save scene to file.
- */
- virtual bool saveToFile(const char* assetName, const char* outputPath) override;
-
- /**
- Set interior material index. Not supported in OBJ since AuthoringTool doesn't created OBJ with materials currently.
- */
- virtual void setInteriorIndex(int32_t index) override;
-
-private:
- std::shared_ptr<ExporterMeshData> mMeshData;
- int32_t mIntSurfaceMatIndex;
- std::string interiorNameStr;
-};
-
-}
-}
-
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTEXTEXPORTEROBJWRITER_H
+#define NVBLASTEXTEXPORTEROBJWRITER_H
+
+#include "NvBlastExtExporter.h"
+#include <memory>
+#include <vector>
+#include <PxVec2.h>
+#include <PxVec3.h>
+#include <string>
+struct NvBlastAsset;
+
+namespace Nv
+{
+namespace Blast
+{
+
+class ObjFileWriter : public IMeshFileWriter
+{
+public:
+
+ ObjFileWriter(): mIntSurfaceMatIndex(-1), interiorNameStr("INTERIOR_MATERIAL") { };
+ ~ObjFileWriter() = default;
+
+ virtual void release() override;
+
+ virtual bool appendMesh(const AuthoringResult& aResult, const char* assetName, bool nonSkinned) override;
+
+ /**
+ Append rendermesh to scene. Meshes constructed from arrays of vertices and indices
+ */
+ virtual bool appendMesh(const ExporterMeshData& meshData, const char* assetName, bool nonSkinned) override;
+
+ /**
+ Save scene to file.
+ */
+ virtual bool saveToFile(const char* assetName, const char* outputPath) override;
+
+ /**
+ Set interior material index. Not supported in OBJ since AuthoringTool doesn't created OBJ with materials currently.
+ */
+ virtual void setInteriorIndex(int32_t index) override;
+
+private:
+ std::shared_ptr<ExporterMeshData> mMeshData;
+ int32_t mIntSurfaceMatIndex;
+ std::string interiorNameStr;
+};
+
+}
+}
+
#endif // NVBLASTEXTEXPORTEROBJWRITER_H \ No newline at end of file