return non-zero on error, add verbose option

This commit is contained in:
Andrew Meadows 2016-05-23 14:20:25 -07:00
parent 7d7c991447
commit 78357057b6
5 changed files with 107 additions and 42 deletions

View file

@ -28,13 +28,16 @@ void reSortFBXGeometryMeshes(FBXGeometry& geometry) {
// Read all the meshes from provided FBX file
bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) {
if (_verbose) {
qDebug() << "reading FBX file =" << filename << "...";
}
// open the fbx file
QFile fbx(filename);
if (!fbx.open(QIODevice::ReadOnly)) {
qWarning() << "unable to open FBX file =" << filename;
return false;
}
qDebug() << "reading FBX file =" << filename << "...";
try {
QByteArray fbxContents = fbx.readAll();
FBXGeometry* geom;
@ -43,14 +46,14 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) {
} else if (filename.toLower().endsWith(".fbx")) {
geom = readFBX(fbxContents, QVariantHash(), filename);
} else {
qDebug() << "unknown file extension";
qWarning() << "unknown file extension";
return false;
}
result = *geom;
reSortFBXGeometryMeshes(result);
} catch (const QString& error) {
qDebug() << "Error reading" << filename << ":" << error;
qWarning() << "error reading" << filename << ":" << error;
return false;
}
@ -230,10 +233,12 @@ bool isClosedManifold(const std::vector<int>& triangles) {
return true;
}
void getConvexResults(VHACD::IVHACD* convexifier, FBXMesh& resultMesh) {
void vhacd::VHACDUtil::getConvexResults(VHACD::IVHACD* convexifier, FBXMesh& resultMesh) const {
// Number of hulls for this input meshPart
unsigned int numHulls = convexifier->GetNConvexHulls();
qDebug() << " hulls =" << numHulls;
if (_verbose) {
qDebug() << " hulls =" << numHulls;
}
// create an output meshPart for each convex hull
for (unsigned int j = 0; j < numHulls; j++) {
@ -259,9 +264,11 @@ void getConvexResults(VHACD::IVHACD* convexifier, FBXMesh& resultMesh) {
resultMeshPart.triangleIndices.append(index1);
resultMeshPart.triangleIndices.append(index2);
}
qDebug() << " hull" << j << " vertices =" << hull.m_nPoints
<< " triangles =" << hull.m_nTriangles
<< " FBXMeshVertices =" << resultMesh.vertices.size();
if (_verbose) {
qDebug() << " hull" << j << " vertices =" << hull.m_nPoints
<< " triangles =" << hull.m_nTriangles
<< " FBXMeshVertices =" << resultMesh.vertices.size();
}
}
}
@ -273,14 +280,18 @@ bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
VHACD::IVHACD::Parameters params,
FBXGeometry& result,
float minimumMeshSize, float maximumMeshSize) {
qDebug() << "meshes =" << geometry.meshes.size();
if (_verbose) {
qDebug() << "meshes =" << geometry.meshes.size();
}
// count the mesh-parts
int numParts = 0;
foreach (const FBXMesh& mesh, geometry.meshes) {
numParts += mesh.parts.size();
}
qDebug() << "total parts =" << numParts;
if (_verbose) {
qDebug() << "total parts =" << numParts;
}
VHACD::IVHACD * convexifier = VHACD::CreateVHACD();
@ -315,9 +326,11 @@ bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
}
auto numVertices = vertices.size();
qDebug() << "mesh" << meshIndex << ": "
<< " parts =" << mesh.parts.size() << " clusters =" << mesh.clusters.size()
<< " vertices =" << numVertices;
if (_verbose) {
qDebug() << "mesh" << meshIndex << ": "
<< " parts =" << mesh.parts.size() << " clusters =" << mesh.clusters.size()
<< " vertices =" << numVertices;
}
++meshIndex;
std::vector<int> openParts;
@ -329,7 +342,9 @@ bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
// only process meshes with triangles
if (triangles.size() <= 0) {
qDebug() << " skip part" << partIndex << "(zero triangles)";
if (_verbose) {
qDebug() << " skip part" << partIndex << "(zero triangles)";
}
++partIndex;
continue;
}
@ -343,13 +358,17 @@ bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
const float largestDimension = aaBox.getLargestDimension();
if (largestDimension < minimumMeshSize) {
qDebug() << " skip part" << partIndex << ": dimension =" << largestDimension << "(too small)";
if (_verbose) {
qDebug() << " skip part" << partIndex << ": dimension =" << largestDimension << "(too small)";
}
++partIndex;
continue;
}
if (maximumMeshSize > 0.0f && largestDimension > maximumMeshSize) {
qDebug() << " skip part" << partIndex << ": dimension =" << largestDimension << "(too large)";
if (_verbose) {
qDebug() << " skip part" << partIndex << ": dimension =" << largestDimension << "(too large)";
}
++partIndex;
continue;
}
@ -358,18 +377,21 @@ bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
bool closed = isClosedManifold(triangles);
if (closed) {
unsigned int triangleCount = triangles.size() / 3;
qDebug() << " process closed part" << partIndex << ": "
<< " triangles =" << triangleCount;
if (_verbose) {
qDebug() << " process closed part" << partIndex << ": " << " triangles =" << triangleCount;
}
// compute approximate convex decomposition
bool success = convexifier->Compute(&vertices[0].x, 3, (uint)numVertices, &triangles[0], 3, triangleCount, params);
if (success) {
getConvexResults(convexifier, resultMesh);
} else {
} else if (_verbose) {
qDebug() << " failed to convexify";
}
} else {
qDebug() << " postpone open part" << partIndex;
if (_verbose) {
qDebug() << " postpone open part" << partIndex;
}
openParts.push_back(partIndex);
}
++partIndex;
@ -391,14 +413,16 @@ bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
// this time we don't care if the parts are close or not
unsigned int triangleCount = triangles.size() / 3;
qDebug() << " process remaining open parts =" << openParts.size() << ": "
<< " triangles =" << triangleCount;
if (_verbose) {
qDebug() << " process remaining open parts =" << openParts.size() << ": "
<< " triangles =" << triangleCount;
}
// compute approximate convex decomposition
bool success = convexifier->Compute(&vertices[0].x, 3, (uint)numVertices, &triangles[0], 3, triangleCount, params);
if (success) {
getConvexResults(convexifier, resultMesh);
} else {
} else if (_verbose) {
qDebug() << " failed to convexify";
}
}

View file

@ -25,6 +25,8 @@
namespace vhacd {
class VHACDUtil {
public:
void setVerbose(bool verbose) { _verbose = verbose; }
bool loadFBX(const QString filename, FBXGeometry& result);
void fattenMeshes(const FBXMesh& mesh, FBXMesh& result,
@ -35,7 +37,13 @@ namespace vhacd {
VHACD::IVHACD::Parameters params,
FBXGeometry& result,
float minimumMeshSize, float maximumMeshSize);
void getConvexResults(VHACD::IVHACD* convexifier, FBXMesh& resultMesh) const;
~VHACDUtil();
private:
bool _verbose { false };
};
class ProgressCallback : public VHACD::IVHACD::IUserCallback {
@ -44,7 +52,7 @@ namespace vhacd {
~ProgressCallback();
// Couldn't follow coding guideline here due to virtual function declared in IUserCallback
void Update(const double overallProgress, const double stageProgress, const double operationProgress,
void Update(const double overallProgress, const double stageProgress, const double operationProgress,
const char * const stage, const char * const operation);
};
}

View file

@ -18,6 +18,9 @@
using namespace std;
using namespace VHACD;
const int VHACD_RETURN_CODE_FAILURE_TO_READ = 1;
const int VHACD_RETURN_CODE_FAILURE_TO_WRITE = 2;
const int VHACD_RETURN_CODE_FAILURE_TO_CONVEXIFY = 3;
QString formatFloat(double n) {
@ -33,14 +36,15 @@ QString formatFloat(double n) {
}
bool writeOBJ(QString outFileName, FBXGeometry& geometry, bool outputCentimeters, int whichMeshPart = -1) {
bool VHACDUtilApp::writeOBJ(QString outFileName, FBXGeometry& geometry, bool outputCentimeters, int whichMeshPart) {
QFile file(outFileName);
if (!file.open(QIODevice::WriteOnly)) {
qDebug() << "Unable to write to " << outFileName;
qWarning() << "unable to write to" << outFileName;
_returnCode = VHACD_RETURN_CODE_FAILURE_TO_WRITE;
return false;
}
QTextStream out(&file);
QTextStream out(&file);
if (outputCentimeters) {
out << "# This file uses centimeters as units\n\n";
}
@ -105,6 +109,9 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
const QCommandLineOption helpOption = parser.addHelpOption();
const QCommandLineOption verboseOutput("v", "verbose output");
parser.addOption(verboseOutput);
const QCommandLineOption splitOption("split", "split input-file into one mesh per output-file");
parser.addOption(splitOption);
@ -195,8 +202,10 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
Q_UNREACHABLE();
}
bool outputCentimeters = parser.isSet(outputCentimetersOption);
bool verbose = parser.isSet(verboseOutput);
vUtil.setVerbose(verbose);
bool outputCentimeters = parser.isSet(outputCentimetersOption);
bool fattenFaces = parser.isSet(fattenFacesOption);
bool generateHulls = parser.isSet(generateHullsOption);
bool splitModel = parser.isSet(splitOption);
@ -305,13 +314,15 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
FBXGeometry fbx;
auto begin = std::chrono::high_resolution_clock::now();
if (!vUtil.loadFBX(inputFilename, fbx)){
qDebug() << "error reading input file" << inputFilename;
_returnCode = VHACD_RETURN_CODE_FAILURE_TO_READ;
return;
}
auto end = std::chrono::high_resolution_clock::now();
auto loadDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
qDebug() << "load time =" << (double)loadDuration / 1000000000.00 << "seconds";
if (verbose) {
qDebug() << "load time =" << (double)loadDuration / 1000000000.00 << "seconds";
}
if (splitModel) {
QVector<QString> infileExtensions = {"fbx", "obj"};
@ -332,7 +343,11 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
vhacd::ProgressCallback progressCallback;
//set parameters for V-HACD
params.m_callback = &progressCallback; //progress callback
if (verbose) {
params.m_callback = &progressCallback; //progress callback
} else {
params.m_callback = nullptr;
}
params.m_resolution = vHacdResolution;
params.m_depth = vHacdDepth;
params.m_concavity = vHacdConcavity;
@ -346,12 +361,14 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based
params.m_maxNumVerticesPerCH = vHacdMaxVerticesPerCH;
params.m_minVolumePerCH = 0.0001; // 0.0001
params.m_logger = 0; // 0
params.m_logger = nullptr;
params.m_convexhullApproximation = true; // true
params.m_oclAcceleration = true; // true
//perform vhacd computation
qDebug() << "running V-HACD algorithm ...";
if (verbose) {
qDebug() << "running V-HACD algorithm ...";
}
begin = std::chrono::high_resolution_clock::now();
FBXGeometry result;
@ -359,10 +376,15 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
end = std::chrono::high_resolution_clock::now();
auto computeDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
qDebug() << "run time =" << (double)computeDuration / 1000000000.00 << " seconds";
if (verbose) {
qDebug() << "run time =" << (double)computeDuration / 1000000000.00 << " seconds";
}
if (!success) {
qDebug() << "failed to convexify model";
if (verbose) {
qDebug() << "failed to convexify model";
}
_returnCode = VHACD_RETURN_CODE_FAILURE_TO_CONVEXIFY;
return;
}
@ -377,11 +399,13 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
}
}
int totalHulls = result.meshes[0].parts.size();
qDebug() << "output file =" << outputFilename;
qDebug() << "vertices =" << totalVertices;
qDebug() << "triangles =" << totalTriangles;
qDebug() << "hulls =" << totalHulls;
if (verbose) {
int totalHulls = result.meshes[0].parts.size();
qDebug() << "output file =" << outputFilename;
qDebug() << "vertices =" << totalVertices;
qDebug() << "triangles =" << totalTriangles;
qDebug() << "hulls =" << totalHulls;
}
writeOBJ(outputFilename, result, outputCentimeters);
}

View file

@ -15,12 +15,21 @@
#include <QApplication>
#include <FBXReader.h>
class VHACDUtilApp : public QCoreApplication {
Q_OBJECT
public:
public:
VHACDUtilApp(int argc, char* argv[]);
~VHACDUtilApp();
bool writeOBJ(QString outFileName, FBXGeometry& geometry, bool outputCentimeters, int whichMeshPart = -1);
int getReturnCode() const { return _returnCode; }
private:
int _returnCode { 0 };
};

View file

@ -23,5 +23,5 @@ using namespace VHACD;
int main(int argc, char * argv[]) {
VHACDUtilApp app(argc, argv);
return 0;
return app.getReturnCode();
}