aboutsummaryrefslogtreecommitdiff
path: root/NvBlast/tools/AuthoringTool/src
diff options
context:
space:
mode:
authorBryan Galdrikian <[email protected]>2017-02-21 12:07:59 -0800
committerBryan Galdrikian <[email protected]>2017-02-21 12:07:59 -0800
commit446ce137c6823ba9eff273bdafdaf266287c7c98 (patch)
treed20aab3e2ed08d7b3ca71c2f40db6a93ea00c459 /NvBlast/tools/AuthoringTool/src
downloadblast-1.0.0-beta.tar.xz
blast-1.0.0-beta.zip
first commitv1.0.0-beta
Diffstat (limited to 'NvBlast/tools/AuthoringTool/src')
-rw-r--r--NvBlast/tools/AuthoringTool/src/AuthoringTool.cpp403
-rw-r--r--NvBlast/tools/AuthoringTool/src/FractureProcessor.cpp264
-rw-r--r--NvBlast/tools/AuthoringTool/src/FractureProcessor.h64
-rw-r--r--NvBlast/tools/AuthoringTool/src/SimpleRandomGenerator.h27
4 files changed, 758 insertions, 0 deletions
diff --git a/NvBlast/tools/AuthoringTool/src/AuthoringTool.cpp b/NvBlast/tools/AuthoringTool/src/AuthoringTool.cpp
new file mode 100644
index 0000000..4898d3b
--- /dev/null
+++ b/NvBlast/tools/AuthoringTool/src/AuthoringTool.cpp
@@ -0,0 +1,403 @@
+#include "PxPhysicsAPI.h"
+#include "PxAllocatorCallback.h"
+#include "PxErrorCallback.h"
+#include "PsFileBuffer.h"
+#include "NvBlast.h"
+#include "NvBlastExtAuthoringCollisionBuilder.h"
+#include "NvBlastExtSerializationLLInterface.h"
+#include "NvBlastExtSerializationInterface.h"
+#include "NvBlastExtAuthoringBondGenerator.h"
+#include "NvBlastExtAuthoringFractureTool.h"
+#include "NvBlastExtAuthoringMesh.h"
+#include "SimpleRandomGenerator.h"
+#include "FbxFileReader.h"
+#include "ObjFileReader.h"
+#include "FractureProcessor.h"
+#include "FbxFileWriter.h"
+#include "ObjFileWriter.h"
+#include "BlastDataExporter.h"
+#include <string>
+#include <iostream>
+#include <vector>
+#include <cctype>
+#include <fstream>
+#include <iosfwd>
+#include <Windows.h>
+#include "tclap/CmdLine.h"
+
+using physx::PxVec3;
+using physx::PxVec2;
+
+#define DEFAULT_ASSET_NAME "AuthoringTest"
+
+
+using namespace Nv::Blast;
+
+struct TCLAPint3
+{
+ int32_t x, y, z;
+ TCLAPint3(int32_t x, int32_t y, int32_t z) :x(x), y(y), z(z){};
+ TCLAPint3() :x(0), y(0), z(0){};
+ TCLAPint3& operator=(const std::string &inp)
+ {
+ std::istringstream stream(inp);
+ if (!(stream >> x >> y >> z))
+ throw TCLAP::ArgParseException(inp + " is not int3");
+ return *this;
+ }
+};
+
+namespace TCLAP {
+ template<>
+ struct ArgTraits<TCLAPint3> {
+ typedef StringLike ValueCategory;
+ };
+}
+
+bool isDirectoryExist(std::string path)
+{
+ DWORD attributes = GetFileAttributesA(path.c_str());
+ if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ return true;
+ }
+ return false;
+}
+
+bool mkDirRecursively(std::string path)
+{
+ if (isDirectoryExist(path))
+ {
+ return true;
+ }
+ auto indx = path.find_first_of("\\/");
+ while (indx != std::string::npos)
+ {
+ std::string subfolder = path.substr(0, indx);
+ CreateDirectory(subfolder.c_str(), NULL);
+ indx = path.find_first_of("\\/", indx + 1);
+ }
+ return isDirectoryExist(path);
+}
+
+int main(int argc, const char* const* argv)
+{
+ // setup cmd line
+ TCLAP::CmdLine cmd("Blast SDK: Authoring Tool", ' ', "0.1");
+
+ TCLAP::UnlabeledValueArg<std::string> infileArg("file", "File to load", true, "", "infile");
+ cmd.add(infileArg);
+
+ TCLAP::UnlabeledValueArg<std::string> outAssetName("outAssetName", "Output asset name", true, DEFAULT_ASSET_NAME, "output asset name");
+ cmd.add(outAssetName);
+
+ TCLAP::ValueArg<std::string> outDirArg("", "outputDir", "Output directory", false, ".", "by default directory of the input file");
+ cmd.add(outDirArg);
+
+ // The output modes
+ //NOTE: Fun TCLAP quirk here - if you set the default to true and specify this switch on the command line, the value will be false!
+ TCLAP::SwitchArg bpxaOutputArg("", "bpxa", "Output ExtPxAsset to the output directory (ext: bpxa)", false);
+ cmd.add(bpxaOutputArg);
+
+ TCLAP::SwitchArg tkOutputArg("", "tk", "Output TkAsset to the output directory (ext: tkasset)", false);
+ cmd.add(tkOutputArg);
+
+ TCLAP::SwitchArg llOutputArg("", "ll", "Output LL Blast asset to the output directory (ext: llasset)", false);
+ cmd.add(llOutputArg);
+
+ TCLAP::SwitchArg ue4OutputArg("", "ue4", "Output FBX with UE4 coordinate system", false);
+ cmd.add(ue4OutputArg);
+
+ TCLAP::SwitchArg fbxAsciiArg("", "fbxascii", "Output FBX as an ascii file (defaults to binary output)", false);
+ cmd.add(fbxAsciiArg);
+
+ TCLAP::SwitchArg objOutputArg("", "obj", "Output a OBJ mesh to the output directory", false);
+ cmd.add(objOutputArg);
+
+ TCLAP::SwitchArg fbxOutputArg("", "fbx", "Output a FBX mesh to the output directory", false);
+ cmd.add(fbxOutputArg);
+
+ TCLAP::SwitchArg protoSer("", "proto", "Serialize Blast data with CapnProto", false);
+ cmd.add(protoSer);
+
+ TCLAP::SwitchArg blockSer("", "block", "Serialize Blast data as block of memory", false);
+ cmd.add(blockSer);
+
+
+
+
+ TCLAP::ValueArg<unsigned char> fracturingMode("", "mode", "Fracturing mode", false, 'v', "v - voronoi, c - clustered voronoi, s - slicing.");
+ cmd.add(fracturingMode);
+ TCLAP::ValueArg<uint32_t> cellsCount("", "cells", "Voronoi cells count", false, 5, "by default 5");
+ cmd.add(cellsCount);
+ TCLAP::ValueArg<uint32_t> clusterCount("", "clusters", "Uniform Voronoi cluster count", false, 5, "by default 5");
+ cmd.add(clusterCount);
+ TCLAP::ValueArg<float> clusterRad("", "radius", "Clustered Voronoi cluster radius", false, 1.0f, "by default 1.0");
+ cmd.add(clusterRad);
+
+ TCLAP::ValueArg<TCLAPint3> slicingNumber("", "slices", "Number of slices per direction", false, TCLAPint3(1, 1, 1), "by default 1 1 1");
+ cmd.add(slicingNumber);
+
+ TCLAP::ValueArg<float> angleVariation("", "avar", "Slicing angle variation", false, 0.0, "by default 0.0");
+ cmd.add(angleVariation);
+
+ TCLAP::ValueArg<float> offsetVariation("", "ovar", "Slicing offset variation", false, 0.0, "by default 0.0");
+ cmd.add(offsetVariation);
+
+ try
+ {
+ // parse cmd input
+ cmd.parse(argc, argv);
+ }
+ catch (TCLAP::ArgException &e) // catch any exceptions
+ {
+ std::cout << "error: " << e.error() << " for arg " << e.argId() << std::endl;
+ return -1;
+ }
+
+ // get cmd parse results
+ std::string infile = infileArg.getValue();
+
+ std::string outDir;
+
+
+ if (outDirArg.isSet())
+ {
+ outDir = outDirArg.getValue();
+ std::string temp = outDir + '/';
+ if (!isDirectoryExist(outDir.data()))
+ {
+ std::cout << "Output directory doesn't exist. It will be created." << std::endl;
+ if (!mkDirRecursively(temp.data()))
+ {
+ std::cout << "Directory creation failed!" << std::endl;
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ auto idx = infile.find_last_of("/\\");
+ if (idx == 0 || idx == std::string::npos)
+ {
+ outDir = ".";
+ }
+ else
+ {
+ outDir = infile.substr(0, idx);
+ }
+ }
+ std::string assetName = outAssetName.getValue();
+
+ // Determine whether to use the obj or fbx loader
+
+ auto idx = infile.rfind('.');
+ std::string extension;
+
+
+ if (idx != std::string::npos)
+ {
+ extension = infile.substr(idx + 1);
+ std::transform(extension.begin(), extension.end(), extension.begin(), std::toupper);
+ }
+ else
+ {
+ std::cout << "Can't determine extension (and thus, loader) of input file. " << infile << std::endl;
+ return -1;
+ }
+
+ bool bOutputBPXA = bpxaOutputArg.getValue();
+ bool bOutputTK = tkOutputArg.getValue();
+ bool bOutputLL = llOutputArg.getValue();
+
+ bool bUE4CoordSystem = ue4OutputArg.getValue();
+ bool bOutputFBXAscii = fbxAsciiArg.getValue();
+
+ bool bOutputObjFile = objOutputArg.isSet();
+ bool bOutputFbxFile = fbxOutputArg.isSet();
+
+ bool bOutputProtobufSer = protoSer.isSet();
+ bool bOutputBlockSer = blockSer.isSet();
+
+
+ // Did we specify no output formats?
+ if (!bpxaOutputArg.isSet() && !tkOutputArg.isSet() && !llOutputArg.isSet())
+ {
+ std::cout << "Didn't specify an output format on the command line, so defaulting to outputting BPXA" << std::endl;
+ bOutputBPXA = true;
+ }
+ // Did we specify no geometry output formats?
+ if (!bOutputObjFile && !bOutputFbxFile)
+ {
+ std::cout << "Didn't specify an output geometry format on the command line, so defaulting to outputting .FBX" << std::endl;
+ bOutputFbxFile = true;
+ }
+ // Did we specify no serialization type?
+ if (!bOutputBlockSer && !bOutputProtobufSer)
+ {
+ std::cout << "Didn't specify an serialization type on the command line, so defaulting to block serialization type" << std::endl;
+ bOutputBlockSer = true;
+ }
+
+ std::shared_ptr<IMeshFileReader> fileReader;
+
+ if (extension.compare("FBX")==0)
+ {
+ fileReader = std::make_shared<FbxFileReader>();
+ }
+ else if (extension.compare("OBJ")==0)
+ {
+ fileReader = std::make_shared<ObjFileReader>();
+ }
+ else
+ {
+ std::cout << "Unsupported file extension " << extension << std::endl;
+ return -1;
+ }
+
+ fileReader->setConvertToUE4(bUE4CoordSystem);
+
+ // Load the asset
+ std::shared_ptr<Mesh> loadedMesh = fileReader->loadFromFile(infile);
+
+ if (loadedMesh == nullptr)
+ {
+ std::cout << "Failed to load mesh " << infile << std::endl;
+ return -1;
+ }
+
+ // Send it to the fracture processor
+ FractureProcessor processor;
+ FractureSettings settings;
+ settings.mode = fracturingMode.getValue();
+ settings.cellsCount = cellsCount.getValue();
+ settings.clusterCount = clusterCount.getValue();
+ settings.slicingX = slicingNumber.getValue().x;
+ settings.slicingY = slicingNumber.getValue().y;
+ settings.slicingZ = slicingNumber.getValue().z;
+ settings.angleVariation = angleVariation.getValue();
+ settings.offsetVariation = offsetVariation.getValue();
+ settings.clusterRadius = clusterRad.getValue();
+
+ std::shared_ptr<FractureResult> result = processor.fractureMesh(loadedMesh, settings);
+
+ // Output the results
+ // NOTE: Writing to FBX by default.
+ std::shared_ptr<IMeshFileWriter> fileWriter;
+
+
+ auto assetLL = result->resultPhysicsAsset->getTkAsset().getAssetLL();
+
+
+ if (bOutputObjFile)
+ {
+ if (bUE4CoordSystem)
+ {
+ std::cout << "OBJ output doesn't support UE4 coordinate conversion." << std::endl;
+ }
+ fileWriter = std::make_shared<ObjFileWriter>();
+ bool writeResult = fileWriter->saveToFile(assetLL, result->resultGeometry, assetName, outDir);
+ if (!writeResult)
+ {
+ std::cerr << "Can't write geometry to OBJ file." << std::endl;
+ return -1;
+ }
+ }
+ if (bOutputFbxFile)
+ {
+ fileWriter = std::make_shared<FbxFileWriter>();
+ fileWriter->setConvertToUE4(bUE4CoordSystem);
+ {
+ auto fbxWriter = static_cast<FbxFileWriter *>(fileWriter.get());
+ fbxWriter->bOutputFBXAscii = bOutputFBXAscii;
+ }
+
+ bool writeResult = fileWriter->saveToFile(assetLL, result->resultGeometry, assetName, outDir);
+ if (!writeResult)
+ {
+ std::cerr << "Can't write geometry to FBX file." << std::endl;
+ return -1;
+ }
+ }
+
+ if (bOutputProtobufSer)
+ {
+ if (bOutputBPXA)
+ {
+ std::ostringstream outBlastFilePathStream;
+ outBlastFilePathStream << outDir << "/" << assetName << ".pbpxa";
+ std::string outBlastFilePath = outBlastFilePathStream.str();
+
+ std::ofstream myFile(outBlastFilePath, std::ios::out | std::ios::binary);
+
+ setPhysXSDK(processor.getPhysics());
+
+ serializeExtPxAssetIntoStream(result->resultPhysicsAsset.get(), myFile);
+
+ myFile.flush();
+
+ std::cout << "Wrote ExtPxAsset to " << outBlastFilePath << std::endl;
+ }
+
+ if (bOutputTK)
+ {
+ std::ostringstream outBlastFilePathStream;
+ outBlastFilePathStream << outDir << "/" << assetName << ".ptkasset";
+ std::string outBlastFilePath = outBlastFilePathStream.str();
+
+ std::ofstream myFile(outBlastFilePath, std::ios::out | std::ios::binary);
+
+ serializeTkAssetIntoStream(&result->resultPhysicsAsset->getTkAsset(), myFile);
+
+ myFile.flush();
+
+ std::cout << "Wrote TkAsset to " << outBlastFilePath << std::endl;
+ }
+
+ if (bOutputLL)
+ {
+ std::ostringstream outBlastFilePathStream;
+ outBlastFilePathStream << outDir << "/" << assetName << ".pllasset";
+ std::string outBlastFilePath = outBlastFilePathStream.str();
+
+ std::ofstream myFile(outBlastFilePath, std::ios::out | std::ios::binary);
+
+ serializeAssetIntoStream(result->resultPhysicsAsset->getTkAsset().getAssetLL(), myFile);
+
+ myFile.flush();
+
+ std::cout << "Wrote NvBlastAsset to " << outBlastFilePath << std::endl;
+ }
+ }
+
+ if (bOutputBlockSer)
+ {
+ BlastDataExporter blExpr(NvBlastTkFrameworkGet(), processor.getCooking(), NvBlastTkFrameworkGet()->getLogFn());
+ if (bOutputLL)
+ {
+ std::ostringstream outBlastFilePathStream;
+ outBlastFilePathStream << outDir << "/" << assetName << ".llasset";
+ std::string outBlastFilePath = outBlastFilePathStream.str();
+ blExpr.saveBlastLLAsset(outBlastFilePath, result->resultPhysicsAsset->getTkAsset().getAssetLL());
+ std::cout << "Wrote NvBlastAsset to " << outBlastFilePath << std::endl;
+ }
+ if (bOutputTK)
+ {
+ std::ostringstream outBlastFilePathStream;
+ outBlastFilePathStream << outDir << "/" << assetName << ".tkasset";
+ std::string outBlastFilePath = outBlastFilePathStream.str();
+ blExpr.saveBlastTkAsset(outBlastFilePath, &result->resultPhysicsAsset->getTkAsset());
+ std::cout << "Wrote TkAsset to " << outBlastFilePath << std::endl;
+ }
+ if (bOutputBPXA)
+ {
+ std::ostringstream outBlastFilePathStream;
+ outBlastFilePathStream << outDir << "/" << assetName << ".bpxa";
+ std::string outBlastFilePath = outBlastFilePathStream.str();
+ blExpr.saveBlastExtAsset(outBlastFilePath, result->resultPhysicsAsset.get());
+ std::cout << "Wrote ExtPxAsset to " << outBlastFilePath << std::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/NvBlast/tools/AuthoringTool/src/FractureProcessor.cpp b/NvBlast/tools/AuthoringTool/src/FractureProcessor.cpp
new file mode 100644
index 0000000..75307d9
--- /dev/null
+++ b/NvBlast/tools/AuthoringTool/src/FractureProcessor.cpp
@@ -0,0 +1,264 @@
+#include "FractureProcessor.h"
+#include "NvBlastExtAuthoringCollisionBuilder.h"
+#include <iostream>
+#include "PxPhysicsAPI.h"
+#include "NvBlastTkFramework.h"
+#include "NvBlastExtAuthoringFractureTool.h"
+#include "SimpleRandomGenerator.h"
+#include "NvBlastExtAuthoringBondGenerator.h"
+#include "NvBlastTypes.h"
+#include "NvBlastIndexFns.h"
+#include "NvBlast.h"
+#include <ctime>
+using namespace Nv::Blast;
+
+void loggingCallback(int type, const char* msg, const char* file, int line)
+{
+ (void)type;
+
+ std::cout << msg << " FILE:" << file << " Line: " << line << "\n";
+}
+
+
+FractureProcessor::FractureProcessor()
+{
+ initPhysX();
+
+ Nv::Blast::TkFrameworkDesc frameworkDesc =
+ {
+ &g_errorCallback,
+ &g_allocator
+ };
+
+ framework = NvBlastTkFrameworkCreate(frameworkDesc);
+ if (framework == nullptr)
+ {
+ std::cout << "Failed to create TkFramework" << std::endl;
+ return;
+ }
+}
+
+FractureProcessor::~FractureProcessor()
+{
+ releasePhysX();
+
+ if (framework != nullptr)
+ {
+ framework->release();
+ }
+}
+
+void FractureProcessor::buildPhysicsChunks(const std::vector<std::vector<Nv::Blast::Triangle>>& chunkGeometry, std::vector<Nv::Blast::ExtPxAssetDesc::ChunkDesc>& outPhysicsChunks, std::vector<Nv::Blast::ExtPxAssetDesc::SubchunkDesc>& outPhysicsSubchunks)
+{
+ Nv::Blast::ConvexMeshBuilder collisionBuilder(cooking, &physics->getPhysicsInsertionCallback());
+
+ outPhysicsChunks.resize(chunkGeometry.size());
+ outPhysicsSubchunks.resize(chunkGeometry.size());
+
+ for (uint32_t i = 0; i < chunkGeometry.size(); ++i)
+ {
+ std::vector<physx::PxVec3> vertices;
+ for (uint32_t p = 0; p < chunkGeometry[i].size(); ++p)
+ {
+ vertices.push_back(chunkGeometry[i][p].a.p);
+ vertices.push_back(chunkGeometry[i][p].b.p);
+ vertices.push_back(chunkGeometry[i][p].c.p);
+ }
+ outPhysicsSubchunks[i].transform = physx::PxTransform(physx::PxIdentity);
+ outPhysicsSubchunks[i].geometry = physx::PxConvexMeshGeometry(collisionBuilder.buildConvexMesh(vertices));
+ outPhysicsChunks[i].isStatic = false;
+ outPhysicsChunks[i].subchunkCount = 1;
+ outPhysicsChunks[i].subchunks = &outPhysicsSubchunks[i];
+ }
+
+}
+
+std::shared_ptr<FractureResult> FractureProcessor::fractureMesh(std::shared_ptr<Nv::Blast::Mesh> sourceMesh, const FractureSettings &settings)
+{
+ // Create FractureTool
+
+ std::cout << "Fracture tool initialization" << std::endl;
+
+ std::vector<NvBlastChunkDesc> chunkDesc;
+ std::vector<NvBlastBondDesc> bondDescs;
+ std::vector<std::vector<Nv::Blast::Triangle> > chunkMeshes;
+ std::vector<bool> isSupport;
+
+ Nv::Blast::FractureTool fTool(loggingCallback);
+
+ fTool.setSourceMesh(sourceMesh.get());
+ SimpleRandomGenerator rnd;
+ rnd.seed((int32_t)time(nullptr)); // Keep the same seed to have reproducible results.
+
+ std::cout << "Fracturing..." << std::endl;
+ VoronoiSitesGenerator stGenerator(sourceMesh.get(), &rnd);
+ switch (settings.mode)
+ {
+ case 'c':
+ stGenerator.clusteredSitesGeneration(settings.clusterCount, settings.cellsCount, settings.clusterRadius);
+ fTool.voronoiFracturing(0, stGenerator.getVoronoiSites(), false);
+ break;
+ case 's':
+ {
+ SlicingConfiguration slConfig;
+ slConfig.x_slices = settings.slicingX;
+ slConfig.y_slices = settings.slicingY;
+ slConfig.z_slices = settings.slicingZ;
+ slConfig.angle_variations = settings.angleVariation;
+ slConfig.offset_variations = settings.offsetVariation;
+ fTool.slicing(0, slConfig, false, &rnd);
+ break;
+ }
+ case 'v':
+ stGenerator.uniformlyGenerateSitesInMesh(settings.cellsCount);
+ fTool.voronoiFracturing(0, stGenerator.getVoronoiSites(), false);
+ break;
+ default:
+ std::cout << "Not supported mode" << std::endl;
+ return nullptr;
+ }
+ std::cout << "Creating geometry" << std::endl;
+ fTool.finalizeFracturing();
+
+ chunkMeshes.resize(fTool.getChunkList().size());
+ isSupport.resize(fTool.getChunkList().size());
+ for (uint32_t i = 0; i < fTool.getChunkList().size(); ++i)
+ {
+ fTool.getBaseMesh(i, chunkMeshes[i]);
+ isSupport[i] = fTool.getChunkList()[i].isLeaf;
+
+ }
+
+
+ BlastBondGenerator bondGenerator(cooking, &physics->getPhysicsInsertionCallback());
+
+ BondGenerationConfig cnf;
+ cnf.bondMode = BondGenerationConfig::EXACT;
+
+ bondGenerator.buildDescFromInternalFracture(&fTool, isSupport, bondDescs, chunkDesc);
+
+// const uint32_t chunkCount = static_cast<uint32_t>(chunkDesc.size());
+ const uint32_t bondCount = static_cast<uint32_t>(bondDescs.size());
+ if (bondCount == 0)
+ {
+ std::cout << "Can't create bonds descriptors..." << std::endl;
+ return nullptr;
+ }
+
+ return finalizeMeshProcessing(chunkDesc, bondDescs, chunkMeshes);
+}
+
+std::shared_ptr<FractureResult> FractureProcessor::finalizeMeshProcessing(std::vector<NvBlastChunkDesc> chunkDesc, std::vector<NvBlastBondDesc> bondDescs, std::vector<std::vector<Nv::Blast::Triangle> > chunkMeshes)
+{
+ const uint32_t chunkCount = static_cast<uint32_t>(chunkDesc.size());
+ const uint32_t bondCount = static_cast<uint32_t>(bondDescs.size());
+
+ // order chunks, build map
+ std::vector<uint32_t> chunkReorderInvMap;
+ {
+ std::vector<uint32_t> chunkReorderMap(chunkCount);
+ std::vector<char> scratch(chunkCount * sizeof(NvBlastChunkDesc));
+ NvBlastEnsureAssetExactSupportCoverage(chunkDesc.data(), chunkCount, scratch.data(), loggingCallback);
+ NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), chunkDesc.data(), chunkCount, scratch.data(), loggingCallback);
+ NvBlastApplyAssetDescChunkReorderMapInplace(chunkDesc.data(), chunkCount, bondDescs.data(), bondCount, chunkReorderMap.data(), scratch.data(), loggingCallback);
+ chunkReorderInvMap.resize(chunkReorderMap.size());
+ Nv::Blast::invertMap(chunkReorderInvMap.data(), chunkReorderMap.data(), static_cast<unsigned int>(chunkReorderMap.size()));
+ }
+
+ std::shared_ptr<FractureResult> result = std::make_shared<FractureResult>();
+
+ // get result geometry
+
+ result->resultGeometry.resize(chunkMeshes.size());
+ //std::vector<std::vector<Triangle>> resultGeometry(chunkMeshes.size());
+ for (uint32_t i = 0; i < chunkMeshes.size(); ++i)
+ {
+ uint32_t chunkIndex = chunkReorderInvMap[i];
+ result->resultGeometry[i] = chunkMeshes[chunkIndex];
+ }
+
+ float maxX = INT32_MIN;
+ float maxY = INT32_MIN;
+ float maxZ = INT32_MIN;
+
+ float minX = INT32_MAX;
+ float minY = INT32_MAX;
+ float minZ = INT32_MAX;
+
+ for (uint32_t i = 0; i < bondDescs.size(); i++)
+ {
+ NvBlastBondDesc bondDesc = bondDescs[i];
+
+ minX = std::min(minX, bondDesc.bond.centroid[0]);
+ maxX = std::max(maxX, bondDesc.bond.centroid[0]);
+
+ minY = std::min(minY, bondDesc.bond.centroid[1]);
+ maxY = std::max(maxY, bondDesc.bond.centroid[1]);
+
+ minZ = std::min(minZ, bondDesc.bond.centroid[2]);
+ maxZ = std::max(maxZ, bondDesc.bond.centroid[2]);
+ }
+
+ std::cout << "Bond bounds: " << std::endl;
+ std::cout << "MIN: " << minX << ", " << minY << ", " << minZ << std::endl;
+ std::cout << "MAX: " << maxX << ", " << maxY << ", " << maxZ << std::endl;
+
+ // prepare physics data (convexes)
+ std::vector<Nv::Blast::ExtPxAssetDesc::ChunkDesc> physicsChunks(chunkCount);
+ std::vector<Nv::Blast::ExtPxAssetDesc::SubchunkDesc> physicsSubchunks;
+ buildPhysicsChunks(result->resultGeometry, physicsChunks, physicsSubchunks);
+
+ // build and serialize ExtPhysicsAsset
+ Nv::Blast::ExtPxAssetDesc descriptor;
+ descriptor.bondCount = bondCount;
+ descriptor.bondDescs = bondDescs.data();
+ descriptor.chunkCount = chunkCount;
+ descriptor.chunkDescs = chunkDesc.data();
+ descriptor.bondFlags = nullptr;
+ descriptor.pxChunks = physicsChunks.data();
+
+ result->resultPhysicsAsset = std::shared_ptr<Nv::Blast::ExtPxAsset>(Nv::Blast::ExtPxAsset::create(descriptor, *framework), [=](Nv::Blast::ExtPxAsset* asset)
+ {
+ asset->release();
+ });
+
+ std::cout << "Done" << std::endl;
+
+ return result;
+}
+
+bool FractureProcessor::initPhysX()
+{
+ foundation = PxCreateFoundation(PX_FOUNDATION_VERSION, g_allocator, g_errorCallback);
+ if (!foundation)
+ {
+ std::cout << "Can't init PhysX foundation" << std::endl;
+ return false;
+ }
+ physx::PxTolerancesScale scale;
+ physics = PxCreatePhysics(PX_PHYSICS_VERSION, *foundation, scale, true);
+ if (!physics)
+ {
+ std::cout << "Can't create Physics" << std::endl;
+ return false;
+ }
+ physx::PxCookingParams cookingParams(scale);
+ cookingParams.buildGPUData = true;
+ cooking = PxCreateCooking(PX_PHYSICS_VERSION, physics->getFoundation(), cookingParams);
+ if (!cooking)
+ {
+ std::cout << "Can't create Cooking" << std::endl;
+ return false;
+ }
+ return true;
+}
+
+void FractureProcessor::releasePhysX()
+{
+ cooking->release();
+ cooking = 0;
+ physics->release();
+ physics = 0;
+ foundation->release();
+ foundation = 0;
+}
diff --git a/NvBlast/tools/AuthoringTool/src/FractureProcessor.h b/NvBlast/tools/AuthoringTool/src/FractureProcessor.h
new file mode 100644
index 0000000..8b8fefe
--- /dev/null
+++ b/NvBlast/tools/AuthoringTool/src/FractureProcessor.h
@@ -0,0 +1,64 @@
+#pragma once
+#include <vector>
+#include "NvBlastExtAuthoringTypes.h"
+#include "PxFoundation.h"
+#include "PxPhysics.h"
+#include "PxCooking.h"
+#include "PxDefaultAllocator.h"
+#include "PxDefaultErrorCallback.h"
+#include <memory>
+#include "NvBlastExtAuthoringMesh.h"
+#include "NvBlastExtAuthoringBondGenerator.h"
+#include "NvBlastTypes.h"
+#include "NvBlastExtPxAsset.h"
+
+struct FractureResult
+{
+ std::vector<std::vector<Nv::Blast::Triangle>> resultGeometry;
+ std::shared_ptr<Nv::Blast::ExtPxAsset> resultPhysicsAsset;
+};
+
+struct FractureSettings
+{
+ unsigned char mode;
+ uint32_t cellsCount;
+ uint32_t clusterCount;
+ float clusterRadius;
+ int32_t slicingX;
+ int32_t slicingY;
+ int32_t slicingZ;
+ float angleVariation;
+ float offsetVariation;
+};
+
+class FractureProcessor
+{
+public:
+ FractureProcessor();
+ ~FractureProcessor();
+
+
+ std::shared_ptr<FractureResult> fractureMesh(std::shared_ptr<Nv::Blast::Mesh> sourceMesh, const FractureSettings &settings);
+
+
+ physx::PxPhysics* getPhysics() { return physics; }
+ physx::PxCooking* getCooking() { return cooking; }
+private:
+ physx::PxFoundation* foundation = nullptr;
+ physx::PxPhysics* physics = nullptr;
+ physx::PxCooking* cooking = nullptr;
+
+ Nv::Blast::TkFramework* framework = nullptr;
+
+ physx::PxDefaultAllocator g_allocator;
+ physx::PxDefaultErrorCallback g_errorCallback;
+
+
+ void buildPhysicsChunks(const std::vector<std::vector<Nv::Blast::Triangle>>& chunkGeometry, std::vector<Nv::Blast::ExtPxAssetDesc::ChunkDesc>& outPhysicsChunks,
+ std::vector<Nv::Blast::ExtPxAssetDesc::SubchunkDesc>& outPhysicsSubchunks);
+
+ std::shared_ptr<FractureResult> finalizeMeshProcessing(std::vector<NvBlastChunkDesc> chunkDesc, std::vector<NvBlastBondDesc> bondDescs, std::vector<std::vector<Nv::Blast::Triangle> > chunkMeshes);
+
+ bool initPhysX();
+ void releasePhysX();
+};
diff --git a/NvBlast/tools/AuthoringTool/src/SimpleRandomGenerator.h b/NvBlast/tools/AuthoringTool/src/SimpleRandomGenerator.h
new file mode 100644
index 0000000..63e2d45
--- /dev/null
+++ b/NvBlast/tools/AuthoringTool/src/SimpleRandomGenerator.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "NvBlastExtAuthoringTypes.h"
+
+
+class SimpleRandomGenerator : public Nv::Blast::RandomGeneratorBase
+{
+public:
+ SimpleRandomGenerator() {
+ remember = false;
+ };
+
+ virtual float getRandomValue()
+ {
+ float r = (float)rand();
+ r = r / RAND_MAX;
+ return r;
+ }
+ virtual void seed(int32_t seed)
+ {
+ srand(seed);
+ }
+
+ virtual ~SimpleRandomGenerator() {};
+
+private:
+ bool remember;
+}; \ No newline at end of file