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 {

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();
}