Merge pull request #4582 from sethalves/island

Comma toggles rendering of collision hulls; more changes to vhacd stuff
This commit is contained in:
Andrew Meadows 2015-04-02 10:37:17 -07:00
commit a824403132
11 changed files with 324 additions and 299 deletions

View file

@ -164,6 +164,8 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D
const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js"; const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js";
bool renderCollisionHulls = false;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
class MyNativeEventFilter : public QAbstractNativeEventFilter { class MyNativeEventFilter : public QAbstractNativeEventFilter {
public: public:
@ -1178,6 +1180,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
break; break;
} }
case Qt::Key_Comma: {
renderCollisionHulls = !renderCollisionHulls;
}
default: default:
event->ignore(); event->ignore();
break; break;
@ -2974,7 +2980,11 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
PerformanceTimer perfTimer("entities"); PerformanceTimer perfTimer("entities");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... entities..."); "Application::displaySide() ... entities...");
_entities.render(RenderArgs::DEFAULT_RENDER_MODE, renderSide); if (renderCollisionHulls) {
_entities.render(RenderArgs::DEBUG_RENDER_MODE, renderSide);
} else {
_entities.render(RenderArgs::DEFAULT_RENDER_MODE, renderSide);
}
} }
// render JS/scriptable overlays // render JS/scriptable overlays

View file

@ -393,7 +393,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
// collision model's extents). // collision model's extents).
glm::vec3 scale = _dimensions / renderGeometry.getUnscaledMeshExtents().size(); glm::vec3 scale = _dimensions / renderGeometry.getUnscaledMeshExtents().size();
// multiply each point by scale before handing the point-set off to the physics engine // multiply each point by scale before handing the point-set off to the physics engine
for (int i = 0; i < _points.size(); i++) { for (int i = 0; i < _points.size(); i++) {
for (int j = 0; j < _points[i].size(); j++) { for (int j = 0; j < _points[i].size(); j++) {

View file

@ -819,8 +819,9 @@ void appendIndex(MeshData& data, QVector<int>& indices, int index) {
} }
} }
ExtractedMesh extractMesh(const FBXNode& object) { ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) {
MeshData data; MeshData data;
data.extracted.mesh.meshIndex = meshIndex++;
QVector<int> materials; QVector<int> materials;
QVector<int> textures; QVector<int> textures;
foreach (const FBXNode& child, object.children) { foreach (const FBXNode& child, object.children) {
@ -1261,6 +1262,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
float unitScaleFactor = 1.0f; float unitScaleFactor = 1.0f;
glm::vec3 ambientColor; glm::vec3 ambientColor;
QString hifiGlobalNodeID; QString hifiGlobalNodeID;
unsigned int meshIndex = 0;
foreach (const FBXNode& child, node.children) { foreach (const FBXNode& child, node.children) {
if (child.name == "FBXHeaderExtension") { if (child.name == "FBXHeaderExtension") {
@ -1305,7 +1307,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
foreach (const FBXNode& object, child.children) { foreach (const FBXNode& object, child.children) {
if (object.name == "Geometry") { if (object.name == "Geometry") {
if (object.properties.at(2) == "Mesh") { if (object.properties.at(2) == "Mesh") {
meshes.insert(getID(object.properties), extractMesh(object)); meshes.insert(getID(object.properties), extractMesh(object, meshIndex));
} else { // object.properties.at(2) == "Shape" } else { // object.properties.at(2) == "Shape"
ExtractedBlendshape extracted = { getID(object.properties), extractBlendshape(object) }; ExtractedBlendshape extracted = { getID(object.properties), extractBlendshape(object) };
blendshapes.append(extracted); blendshapes.append(extracted);
@ -1440,7 +1442,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
} else if (subobject.name == "Vertices") { } else if (subobject.name == "Vertices") {
// it's a mesh as well as a model // it's a mesh as well as a model
mesh = &meshes[getID(object.properties)]; mesh = &meshes[getID(object.properties)];
*mesh = extractMesh(object); *mesh = extractMesh(object, meshIndex);
} else if (subobject.name == "Shape") { } else if (subobject.name == "Shape") {
ExtractedBlendshape blendshape = { subobject.properties.at(0).toString(), ExtractedBlendshape blendshape = { subobject.properties.at(0).toString(),
@ -1980,7 +1982,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
// see if any materials have texture children // see if any materials have texture children
bool materialsHaveTextures = checkMaterialsHaveTextures(materials, textureFilenames, childMap); bool materialsHaveTextures = checkMaterialsHaveTextures(materials, textureFilenames, childMap);
for (QHash<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) { for (QHash<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
ExtractedMesh& extracted = it.value(); ExtractedMesh& extracted = it.value();

View file

@ -152,6 +152,8 @@ public:
bool hasSpecularTexture() const; bool hasSpecularTexture() const;
bool hasEmissiveTexture() const; bool hasEmissiveTexture() const;
unsigned int meshIndex; // the order the meshes appeared in the object file
}; };
/// A single animation frame extracted from an FBX document. /// A single animation frame extracted from an FBX document.

View file

@ -343,6 +343,7 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) {
} }
FBXMesh &mesh = geometry.meshes[0]; FBXMesh &mesh = geometry.meshes[0];
mesh.meshIndex = 0;
// if we got a hint about units, scale all the points // if we got a hint about units, scale all the points
if (scaleGuess != 1.0f) { if (scaleGuess != 1.0f) {

View file

@ -82,7 +82,8 @@ Model::Model(QObject* parent) :
_appliedBlendNumber(0), _appliedBlendNumber(0),
_calculatedMeshBoxesValid(false), _calculatedMeshBoxesValid(false),
_calculatedMeshTrianglesValid(false), _calculatedMeshTrianglesValid(false),
_meshGroupsKnown(false) { _meshGroupsKnown(false),
_renderCollisionHull(false) {
// we may have been created in the network thread, but we live in the main thread // we may have been created in the network thread, but we live in the main thread
if (_viewState) { if (_viewState) {
@ -712,13 +713,13 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
{ {
GLenum buffers[3]; GLenum buffers[3];
int bufferCount = 0; int bufferCount = 0;
if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE || mode == DEBUG_RENDER_MODE) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
} }
if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE) { if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE || mode == DEBUG_RENDER_MODE) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
} }
if (mode == DEFAULT_RENDER_MODE) { if (mode == DEFAULT_RENDER_MODE || mode == DEBUG_RENDER_MODE) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
} }
GLBATCH(glDrawBuffers)(bufferCount, buffers); GLBATCH(glDrawBuffers)(bufferCount, buffers);
@ -777,7 +778,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
GLBATCH(glDrawBuffers)(bufferCount, buffers); GLBATCH(glDrawBuffers)(bufferCount, buffers);
} }
if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE || mode == DEBUG_RENDER_MODE) {
const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f;
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args, true); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args, true);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args, true); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args, true);
@ -1778,13 +1779,13 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
{ {
GLenum buffers[3]; GLenum buffers[3];
int bufferCount = 0; int bufferCount = 0;
if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE || mode == DEBUG_RENDER_MODE) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
} }
if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE) { if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE || mode == DEBUG_RENDER_MODE) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
} }
if (mode == DEFAULT_RENDER_MODE) { if (mode == DEFAULT_RENDER_MODE || mode == DEBUG_RENDER_MODE) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
} }
GLBATCH(glDrawBuffers)(bufferCount, buffers); GLBATCH(glDrawBuffers)(bufferCount, buffers);
@ -1843,7 +1844,7 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
GLBATCH(glDrawBuffers)(bufferCount, buffers); GLBATCH(glDrawBuffers)(bufferCount, buffers);
} }
if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE || mode == DEBUG_RENDER_MODE) {
const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f;
translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args); translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args);
translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args); translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args);
@ -1919,6 +1920,23 @@ bool Model::renderInScene(float alpha, RenderArgs* args) {
if (_meshStates.isEmpty()) { if (_meshStates.isEmpty()) {
return false; return false;
} }
if (args->_renderMode == RenderArgs::DEBUG_RENDER_MODE && _renderCollisionHull == false) {
// turning collision hull rendering on
_renderCollisionHull = true;
_nextGeometry = _collisionGeometry;
_saveNonCollisionGeometry = _geometry;
updateGeometry();
simulate(0.0, true);
} else if (args->_renderMode != RenderArgs::DEBUG_RENDER_MODE && _renderCollisionHull == true) {
// turning collision hull rendering off
_renderCollisionHull = false;
_nextGeometry = _saveNonCollisionGeometry;
_saveNonCollisionGeometry.clear();
updateGeometry();
simulate(0.0, true);
}
renderSetup(args); renderSetup(args);
_modelsInScene.push_back(this); _modelsInScene.push_back(this);
return true; return true;
@ -2402,8 +2420,9 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl
} }
int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args, int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMode mode, bool translucent,
Locations* locations, SkinLocations* skinLocations, bool forceRenderMeshes) { float alphaThreshold, RenderArgs* args, Locations* locations, SkinLocations* skinLocations,
bool forceRenderMeshes) {
PROFILE_RANGE(__FUNCTION__); PROFILE_RANGE(__FUNCTION__);
auto textureCache = DependencyManager::get<TextureCache>(); auto textureCache = DependencyManager::get<TextureCache>();

View file

@ -91,7 +91,7 @@ public:
void reset(); void reset();
virtual void simulate(float deltaTime, bool fullUpdate = true); virtual void simulate(float deltaTime, bool fullUpdate = true);
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, DEBUG_RENDER_MODE };
bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL);
@ -295,6 +295,7 @@ private:
float _nextLODHysteresis; float _nextLODHysteresis;
QSharedPointer<NetworkGeometry> _collisionGeometry; QSharedPointer<NetworkGeometry> _collisionGeometry;
QSharedPointer<NetworkGeometry> _saveNonCollisionGeometry;
float _pupilDilation; float _pupilDilation;
QVector<float> _blendshapeCoefficients; QVector<float> _blendshapeCoefficients;
@ -479,6 +480,7 @@ private:
static AbstractViewStateInterface* _viewState; static AbstractViewStateInterface* _viewState;
bool _renderCollisionHull;
}; };
Q_DECLARE_METATYPE(QPointer<Model>) Q_DECLARE_METATYPE(QPointer<Model>)

View file

@ -17,7 +17,7 @@ class OctreeRenderer;
class RenderArgs { class RenderArgs {
public: public:
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, DEBUG_RENDER_MODE };
enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT }; enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT };
OctreeRenderer* _renderer; OctreeRenderer* _renderer;

View file

@ -13,8 +13,18 @@
#include "VHACDUtil.h" #include "VHACDUtil.h"
//Read all the meshes from provided FBX file // FBXReader jumbles the order of the meshes by reading them back out of a hashtable. This will put
bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) { // them back in the order in which they appeared in the file.
bool FBXGeometryLessThan(const FBXMesh& e1, const FBXMesh& e2) {
return e1.meshIndex < e2.meshIndex;
}
void reSortFBXGeometryMeshes(FBXGeometry& geometry) {
qSort(geometry.meshes.begin(), geometry.meshes.end(), FBXGeometryLessThan);
}
// Read all the meshes from provided FBX file
bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) {
// open the fbx file // open the fbx file
QFile fbx(filename); QFile fbx(filename);
@ -25,174 +35,71 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re
QByteArray fbxContents = fbx.readAll(); QByteArray fbxContents = fbx.readAll();
FBXGeometry geometry;
if (filename.toLower().endsWith(".obj")) { if (filename.toLower().endsWith(".obj")) {
geometry = readOBJ(fbxContents, QVariantHash()); result = readOBJ(fbxContents, QVariantHash());
} else if (filename.toLower().endsWith(".fbx")) { } else if (filename.toLower().endsWith(".fbx")) {
geometry = readFBX(fbxContents, QVariantHash()); result = readFBX(fbxContents, QVariantHash());
} else { } else {
qDebug() << "unknown file extension"; qDebug() << "unknown file extension";
return false; return false;
} }
reSortFBXGeometryMeshes(result);
std::cout << "-------------------\n";
foreach (const FBXMesh& mesh, geometry.meshes) {
foreach (const FBXMeshPart &meshPart, mesh.parts) {
std::cout << meshPart.triangleIndices.size() << " ";
}
}
std::cout << "\n";
//results->meshCount = geometry.meshes.count();
// qDebug() << "read in" << geometry.meshes.count() << "meshes";
int count = 0;
foreach(FBXMesh mesh, geometry.meshes) {
//get vertices for each mesh
// QVector<glm::vec3> vertices = mesh.vertices;
QVector<glm::vec3> vertices;
foreach (glm::vec3 vertex, mesh.vertices) {
vertices.append(glm::vec3(mesh.modelTransform * glm::vec4(vertex, 1.0f)));
}
// get the triangle indices for each mesh
QVector<int> triangles;
foreach(FBXMeshPart meshPart, mesh.parts){
QVector<int> indices = meshPart.triangleIndices;
triangles += indices;
unsigned int quadCount = meshPart.quadIndices.size() / 4;
for (unsigned int i = 0; i < quadCount; i++) {
unsigned int p0Index = meshPart.quadIndices[i * 4];
unsigned int p1Index = meshPart.quadIndices[i * 4 + 1];
unsigned int p2Index = meshPart.quadIndices[i * 4 + 2];
unsigned int p3Index = meshPart.quadIndices[i * 4 + 3];
// split each quad into two triangles
triangles.append(p0Index);
triangles.append(p1Index);
triangles.append(p2Index);
triangles.append(p0Index);
triangles.append(p2Index);
triangles.append(p3Index);
}
}
// only read meshes with triangles
if (triangles.count() <= 0){
continue;
}
AABox aaBox;
foreach (glm::vec3 p, vertices) {
aaBox += p;
}
results->perMeshVertices.append(vertices);
results->perMeshTriangleIndices.append(triangles);
results->perMeshLargestDimension.append(aaBox.getLargestDimension());
count++;
}
results->meshCount = count;
return true; return true;
} }
void vhacd::VHACDUtil::combineMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const {
float largestDimension = 0;
int indexStart = 0;
QVector<glm::vec3> emptyVertices; // void vhacd::VHACDUtil::fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const {
QVector<int> emptyTriangles;
results->perMeshVertices.append(emptyVertices);
results->perMeshTriangleIndices.append(emptyTriangles);
results->perMeshLargestDimension.append(largestDimension);
for (int i = 0; i < meshes->meshCount; i++) { // for (int i = 0; i < meshes->meshCount; i++) {
QVector<glm::vec3> vertices = meshes->perMeshVertices.at(i); // QVector<glm::vec3> vertices = meshes->perMeshVertices.at(i);
QVector<int> triangles = meshes->perMeshTriangleIndices.at(i); // QVector<int> triangles = meshes->perMeshTriangleIndices.at(i);
const float largestDimension = meshes->perMeshLargestDimension.at(i); // const float largestDimension = meshes->perMeshLargestDimension.at(i);
for (int j = 0; j < triangles.size(); j++) { // results->perMeshVertices.append(vertices);
triangles[ j ] += indexStart; // results->perMeshTriangleIndices.append(triangles);
} // results->perMeshLargestDimension.append(largestDimension);
indexStart += vertices.size();
results->perMeshVertices[0] << vertices; // for (int j = 0; j < triangles.size(); j += 3) {
results->perMeshTriangleIndices[0] << triangles; // auto p0 = vertices[triangles[j]];
if (results->perMeshLargestDimension[0] < largestDimension) { // auto p1 = vertices[triangles[j+1]];
results->perMeshLargestDimension[0] = largestDimension; // auto p2 = vertices[triangles[j+2]];
}
}
results->meshCount = 1; // auto d0 = p1 - p0;
} // auto d1 = p2 - p0;
// auto cp = glm::cross(d0, d1);
// cp = -2.0f * glm::normalize(cp);
void vhacd::VHACDUtil::fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const { // auto p3 = p0 + cp;
for (int i = 0; i < meshes->meshCount; i++) {
QVector<glm::vec3> vertices = meshes->perMeshVertices.at(i);
QVector<int> triangles = meshes->perMeshTriangleIndices.at(i);
const float largestDimension = meshes->perMeshLargestDimension.at(i);
results->perMeshVertices.append(vertices);
results->perMeshTriangleIndices.append(triangles);
results->perMeshLargestDimension.append(largestDimension);
for (int j = 0; j < triangles.size(); j += 3) {
auto p0 = vertices[triangles[j]];
auto p1 = vertices[triangles[j+1]];
auto p2 = vertices[triangles[j+2]];
auto d0 = p1 - p0;
auto d1 = p2 - p0;
auto cp = glm::cross(d0, d1);
cp = -2.0f * glm::normalize(cp);
auto p3 = p0 + cp;
auto n = results->perMeshVertices.size(); // auto n = results->perMeshVertices.size();
results->perMeshVertices[i] << p3; // results->perMeshVertices[i] << p3;
results->perMeshTriangleIndices[i] << triangles[j] << n << triangles[j + 1]; // results->perMeshTriangleIndices[i] << triangles[j] << n << triangles[j + 1];
results->perMeshTriangleIndices[i] << triangles[j + 1] << n << triangles[j + 2]; // results->perMeshTriangleIndices[i] << triangles[j + 1] << n << triangles[j + 2];
results->perMeshTriangleIndices[i] << triangles[j + 2] << n << triangles[j]; // results->perMeshTriangleIndices[i] << triangles[j + 2] << n << triangles[j];
} // }
results->meshCount++; // results->meshCount++;
} // }
} // }
bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *inMeshes, VHACD::IVHACD::Parameters params, bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
vhacd::ComputeResults *results, VHACD::IVHACD::Parameters params,
int startMeshIndex, int endMeshIndex, float minimumMeshSize, FBXGeometry& result,
bool fattenFaces) const { int startMeshIndex,
int endMeshIndex, float minimumMeshSize,
vhacd::LoadFBXResults *meshes = new vhacd::LoadFBXResults; bool fattenFaces) {
// combineMeshes(inMeshes, meshes); // count the mesh-parts
QVector<FBXMeshPart> meshParts;
// vhacd::LoadFBXResults *meshes = new vhacd::LoadFBXResults; int meshCount = 0;
if (fattenFaces) {
fattenMeshes(inMeshes, meshes);
} else {
meshes = inMeshes;
}
VHACD::IVHACD * interfaceVHACD = VHACD::CreateVHACD(); VHACD::IVHACD * interfaceVHACD = VHACD::CreateVHACD();
int meshCount = meshes->meshCount;
int count = 0;
if (startMeshIndex < 0) { if (startMeshIndex < 0) {
startMeshIndex = 0; startMeshIndex = 0;
@ -201,66 +108,127 @@ bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *inMeshes, VHACD::IVHA
endMeshIndex = meshCount; endMeshIndex = meshCount;
} }
for (int i = 0; i < meshCount; i++) {
std::cout << meshes->perMeshTriangleIndices.at(i).size() << " ";
}
std::cout << "\n";
std::cout << "Performing V-HACD computation on " << endMeshIndex - startMeshIndex << " meshes ..... " << std::endl; std::cout << "Performing V-HACD computation on " << endMeshIndex - startMeshIndex << " meshes ..... " << std::endl;
for (int i = startMeshIndex; i < endMeshIndex; i++){ result.meshExtents.reset();
qDebug() << "--------------------"; result.meshes.append(FBXMesh());
std::vector<glm::vec3> vertices = meshes->perMeshVertices.at(i).toStdVector(); FBXMesh &resultMesh = result.meshes.last();
std::vector<int> triangles = meshes->perMeshTriangleIndices.at(i).toStdVector();
int nPoints = (unsigned int)vertices.size();
int nTriangles = (unsigned int)triangles.size() / 3;
const float largestDimension = meshes->perMeshLargestDimension.at(i);
qDebug() << "Mesh " << i << " -- " << nPoints << " points, " << nTriangles << " triangles, " int count = 0;
<< "size =" << largestDimension; foreach (const FBXMesh& mesh, geometry.meshes) {
if (largestDimension < minimumMeshSize /* || largestDimension > 1000 */) { // each mesh has its own transform to move it to model-space
qDebug() << " Skipping..."; std::vector<glm::vec3> vertices;
continue; foreach (glm::vec3 vertex, mesh.vertices) {
vertices.push_back(glm::vec3(mesh.modelTransform * glm::vec4(vertex, 1.0f)));
} }
// compute approximate convex decomposition
bool res = interfaceVHACD->Compute(&vertices[0].x, 3, nPoints, &triangles[0], 3, nTriangles, params);
if (!res){
qDebug() << "V-HACD computation failed for Mesh : " << i;
continue;
}
count++; //For counting number of successfull computations
//Number of hulls for the mesh foreach (const FBXMeshPart &meshPart, mesh.parts) {
unsigned int nConvexHulls = interfaceVHACD->GetNConvexHulls();
results->convexHullsCountList.append(nConvexHulls);
//get all the convex hulls for this mesh if (count < startMeshIndex || count >= endMeshIndex) {
QVector<VHACD::IVHACD::ConvexHull> convexHulls; count ++;
for (unsigned int j = 0; j < nConvexHulls; j++){ continue;
VHACD::IVHACD::ConvexHull hull;
interfaceVHACD->GetConvexHull(j, hull);
double *m_points_copy = new double[hull.m_nPoints * 3];
// std::copy(std::begin(hull.m_points), std::end(hull.m_points), std::begin(m_points_copy));
for (unsigned int i=0; i<hull.m_nPoints * 3; i++) {
m_points_copy[ i ] = hull.m_points[ i ];
} }
hull.m_points = m_points_copy;
int *m_triangles_copy = new int[hull.m_nTriangles * 3]; qDebug() << "--------------------";
// std::copy(std::begin(hull.m_triangles), std::end(hull.m_triangles), std::begin(m_triangles_copy));
for (unsigned int i=0; i<hull.m_nTriangles * 3; i++) { std::vector<int> triangles = meshPart.triangleIndices.toStdVector();
m_triangles_copy[ i ] = hull.m_triangles[ i ];
AABox aaBox;
unsigned int triangleCount = meshPart.triangleIndices.size() / 3;
for (unsigned int i = 0; i < triangleCount; i++) {
glm::vec3 p0 = mesh.vertices[meshPart.triangleIndices[i * 3]];
glm::vec3 p1 = mesh.vertices[meshPart.triangleIndices[i * 3 + 1]];
glm::vec3 p2 = mesh.vertices[meshPart.triangleIndices[i * 3 + 2]];
aaBox += p0;
aaBox += p1;
aaBox += p2;
} }
hull.m_triangles = m_triangles_copy;
convexHulls.append(hull);
}
results->convexHullList.append(convexHulls);
} //end of for loop
results->meshCount = count; // convert quads to triangles
unsigned int quadCount = meshPart.quadIndices.size() / 4;
for (unsigned int i = 0; i < quadCount; i++) {
unsigned int p0Index = meshPart.quadIndices[i * 4];
unsigned int p1Index = meshPart.quadIndices[i * 4 + 1];
unsigned int p2Index = meshPart.quadIndices[i * 4 + 2];
unsigned int p3Index = meshPart.quadIndices[i * 4 + 3];
glm::vec3 p0 = mesh.vertices[p0Index];
glm::vec3 p1 = mesh.vertices[p1Index + 1];
glm::vec3 p2 = mesh.vertices[p2Index + 2];
glm::vec3 p3 = mesh.vertices[p3Index + 3];
aaBox += p0;
aaBox += p1;
aaBox += p2;
aaBox += p3;
// split each quad into two triangles
triangles.push_back(p0Index);
triangles.push_back(p1Index);
triangles.push_back(p2Index);
triangles.push_back(p0Index);
triangles.push_back(p2Index);
triangles.push_back(p3Index);
triangleCount += 2;
}
// only process meshes with triangles
if (triangles.size() <= 0) {
qDebug() << " Skipping (no triangles)...";
count++;
continue;
}
int nPoints = vertices.size();
const float largestDimension = aaBox.getLargestDimension();
qDebug() << "Mesh " << count << " -- " << nPoints << " points, " << triangleCount << " triangles, "
<< "size =" << largestDimension;
if (largestDimension < minimumMeshSize /* || largestDimension > 1000 */) {
qDebug() << " Skipping (too small)...";
count++;
continue;
}
// compute approximate convex decomposition
bool res = interfaceVHACD->Compute(&vertices[0].x, 3, nPoints, &triangles[0], 3, triangleCount, params);
if (!res){
qDebug() << "V-HACD computation failed for Mesh : " << count;
count++;
continue;
}
// Number of hulls for this input meshPart
unsigned int nConvexHulls = interfaceVHACD->GetNConvexHulls();
// create an output meshPart for each convex hull
for (unsigned int j = 0; j < nConvexHulls; j++) {
VHACD::IVHACD::ConvexHull hull;
interfaceVHACD->GetConvexHull(j, hull);
resultMesh.parts.append(FBXMeshPart());
FBXMeshPart &resultMeshPart = resultMesh.parts.last();
int hullIndexStart = resultMesh.vertices.size();
for (unsigned int i = 0; i < hull.m_nPoints; i++) {
float x = hull.m_points[i * 3];
float y = hull.m_points[i * 3 + 1];
float z = hull.m_points[i * 3 + 2];
resultMesh.vertices.append(glm::vec3(x, y, z));
}
for (unsigned int i = 0; i < hull.m_nTriangles; i++) {
int index0 = hull.m_triangles[i * 3] + hullIndexStart;
int index1 = hull.m_triangles[i * 3 + 1] + hullIndexStart;
int index2 = hull.m_triangles[i * 3 + 2] + hullIndexStart;
resultMeshPart.triangleIndices.append(index0);
resultMeshPart.triangleIndices.append(index1);
resultMeshPart.triangleIndices.append(index2);
}
}
count++;
}
}
//release memory //release memory
interfaceVHACD->Clean(); interfaceVHACD->Clean();
@ -272,7 +240,6 @@ bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *inMeshes, VHACD::IVHA
else{ else{
return false; return false;
} }
} }
vhacd::VHACDUtil:: ~VHACDUtil(){ vhacd::VHACDUtil:: ~VHACDUtil(){
@ -280,8 +247,11 @@ vhacd::VHACDUtil:: ~VHACDUtil(){
} }
//ProgressClaback implementation //ProgressClaback implementation
void vhacd::ProgressCallback::Update(const double overallProgress, const double stageProgress, const double operationProgress, void vhacd::ProgressCallback::Update(const double overallProgress,
const char * const stage, const char * const operation){ const double stageProgress,
const double operationProgress,
const char* const stage,
const char* const operation) {
int progress = (int)(overallProgress + 0.5); int progress = (int)(overallProgress + 0.5);
if (progress < 10){ if (progress < 10){
@ -293,9 +263,9 @@ void vhacd::ProgressCallback::Update(const double overallProgress, const double
std::cout << progress << "%"; std::cout << progress << "%";
if (progress >= 100){ if (progress >= 100){
std::cout << std::endl; std::cout << std::endl;
} }
} }
vhacd::ProgressCallback::ProgressCallback(void){} vhacd::ProgressCallback::ProgressCallback(void){}

View file

@ -23,28 +23,17 @@
#include <VHACD.h> #include <VHACD.h>
namespace vhacd { namespace vhacd {
typedef struct {
int meshCount;
QVector<int> convexHullsCountList;
QVector<QVector<VHACD::IVHACD::ConvexHull>> convexHullList;
} ComputeResults;
typedef struct {
int meshCount;
QVector<QVector<glm::vec3>> perMeshVertices;
QVector<QVector<int>> perMeshTriangleIndices;
QVector<float> perMeshLargestDimension;
} LoadFBXResults;
class VHACDUtil { class VHACDUtil {
public: public:
bool loadFBX(const QString filename, vhacd::LoadFBXResults *results); bool loadFBX(const QString filename, FBXGeometry& result);
void combineMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const; // void combineMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const;
void fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const; // void fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const;
bool computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params, bool computeVHACD(FBXGeometry& geometry,
vhacd::ComputeResults *results, int startMeshIndex, int endMeshIndex, float minimumMeshSize, VHACD::IVHACD::Parameters params,
bool fattenFaces) const; FBXGeometry& result,
int startMeshIndex, int endMeshIndex,
float minimumMeshSize,
bool fattenFaces);
~VHACDUtil(); ~VHACDUtil();
}; };
@ -53,7 +42,7 @@ namespace vhacd {
ProgressCallback(void); ProgressCallback(void);
~ProgressCallback(); ~ProgressCallback();
//Couldn't follow coding guideline here due to virtual function declared in IUserCallback // 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); const char * const stage, const char * const operation);
}; };

View file

@ -32,7 +32,7 @@ QString formatFloat(double n) {
} }
bool writeOBJ(QString outFileName, QVector<QVector<VHACD::IVHACD::ConvexHull>>& meshList, bool outputOneMesh) { bool writeOBJ(QString outFileName, FBXGeometry& geometry) {
QFile file(outFileName); QFile file(outFileName);
if (!file.open(QIODevice::WriteOnly)) { if (!file.open(QIODevice::WriteOnly)) {
qDebug() << "Unable to write to " << outFileName; qDebug() << "Unable to write to " << outFileName;
@ -41,26 +41,25 @@ bool writeOBJ(QString outFileName, QVector<QVector<VHACD::IVHACD::ConvexHull>>&
QTextStream out(&file); QTextStream out(&file);
unsigned int pointStartOffset = 0; unsigned int nth = 0;
foreach (const FBXMesh& mesh, geometry.meshes) {
for (int i = 0; i < mesh.vertices.size(); i++) {
out << "v ";
out << formatFloat(mesh.vertices[i][0]) << " ";
out << formatFloat(mesh.vertices[i][1]) << " ";
out << formatFloat(mesh.vertices[i][2]) << "\n";
}
foreach (QVector<VHACD::IVHACD::ConvexHull> hulls, meshList) { foreach (const FBXMeshPart &meshPart, mesh.parts) {
unsigned int nth = 0;
foreach (VHACD::IVHACD::ConvexHull hull, hulls) {
out << "g hull-" << nth++ << "\n"; out << "g hull-" << nth++ << "\n";
for (unsigned int i = 0; i < hull.m_nPoints; i++) { int triangleCount = meshPart.triangleIndices.size() / 3;
out << "v "; for (int i = 0; i < triangleCount; i++) {
out << formatFloat(hull.m_points[i*3]) << " ";
out << formatFloat(hull.m_points[i*3+1]) << " ";
out << formatFloat(hull.m_points[i*3+2]) << "\n";
}
for (unsigned int i = 0; i < hull.m_nTriangles; i++) {
out << "f "; out << "f ";
out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; out << meshPart.triangleIndices[i*3] + 1 << " ";
out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " "; out << meshPart.triangleIndices[i*3+1] + 1 << " ";
out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n"; out << meshPart.triangleIndices[i*3+2] + 1 << "\n";
} }
out << "\n"; out << "\n";
pointStartOffset += hull.m_nPoints;
} }
} }
@ -76,8 +75,6 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
vector<int> triangles; // array of indexes vector<int> triangles; // array of indexes
vector<float> points; // array of coordinates vector<float> points; // array of coordinates
vhacd::VHACDUtil vUtil; vhacd::VHACDUtil vUtil;
vhacd::LoadFBXResults fbx; //mesh data from loaded fbx file
vhacd::ComputeResults results; // results after computing vhacd
VHACD::IVHACD::Parameters params; VHACD::IVHACD::Parameters params;
vhacd::ProgressCallback pCallBack; vhacd::ProgressCallback pCallBack;
@ -89,9 +86,6 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
const QCommandLineOption helpOption = parser.addHelpOption(); const QCommandLineOption helpOption = parser.addHelpOption();
const QCommandLineOption outputOneMeshOption("1", "output hulls as single mesh");
parser.addOption(outputOneMeshOption);
const QCommandLineOption fattenFacesOption("f", "fatten faces"); const QCommandLineOption fattenFacesOption("f", "fatten faces");
parser.addOption(fattenFacesOption); parser.addOption(fattenFacesOption);
@ -107,18 +101,48 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
const QCommandLineOption endMeshIndexOption("e", "end-mesh index", "0"); const QCommandLineOption endMeshIndexOption("e", "end-mesh index", "0");
parser.addOption(endMeshIndexOption); parser.addOption(endMeshIndexOption);
const QCommandLineOption minimumMeshSizeOption("m", "minimum mesh size to consider", "0"); const QCommandLineOption minimumMeshSizeOption("m", "minimum mesh (diagonal) size to consider", "0");
parser.addOption(minimumMeshSizeOption); parser.addOption(minimumMeshSizeOption);
const QCommandLineOption vHacdResolutionOption("resolution", "v-hacd resolution", "100000"); const QCommandLineOption vHacdResolutionOption("resolution", "Maximum number of voxels generated during the "
"voxelization stage (range=10,000-16,000,000)", "100000");
parser.addOption(vHacdResolutionOption); parser.addOption(vHacdResolutionOption);
const QCommandLineOption vHacdDepthOption("depth", "v-hacd depth", "20"); const QCommandLineOption vHacdDepthOption("depth", "Maximum number of clipping stages. During each split stage, parts "
"with a concavity higher than the user defined threshold are clipped "
"according the \"best\" clipping plane (range=1-32)", "20");
parser.addOption(vHacdDepthOption); parser.addOption(vHacdDepthOption);
const QCommandLineOption vHacdDeltaOption("delta", "v-hacd delta", "0.05"); const QCommandLineOption vHacdDeltaOption("delta", "Controls the bias toward maximaxing local concavity (range=0.0-1.0)", "0.05");
parser.addOption(vHacdDeltaOption); parser.addOption(vHacdDeltaOption);
const QCommandLineOption vHacdConcavityOption("concavity", "Maximum allowed concavity (range=0.0-1.0)", "0.0025");
parser.addOption(vHacdConcavityOption);
const QCommandLineOption vHacdPlanedownsamplingOption("planedownsampling", "Controls the granularity of the search for"
" the \"best\" clipping plane (range=1-16)", "4");
parser.addOption(vHacdPlanedownsamplingOption);
const QCommandLineOption vHacdConvexhulldownsamplingOption("convexhulldownsampling", "Controls the precision of the "
"convex-hull generation process during the clipping "
"plane selection stage (range=1-16)", "4");
parser.addOption(vHacdConvexhulldownsamplingOption);
// alpha
// beta
// gamma
// delta
// pca
// mode
const QCommandLineOption vHacdMaxVerticesPerCHOption("maxvertices", "Controls the maximum number of triangles per "
"convex-hull (range=4-1024)", "64");
parser.addOption(vHacdMaxVerticesPerCHOption);
// minVolumePerCH
// convexhullApproximation
if (!parser.parse(QCoreApplication::arguments())) { if (!parser.parse(QCoreApplication::arguments())) {
qCritical() << parser.errorText() << endl; qCritical() << parser.errorText() << endl;
@ -132,7 +156,6 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
} }
bool fattenFaces = parser.isSet(fattenFacesOption); bool fattenFaces = parser.isSet(fattenFacesOption);
bool outputOneMesh = parser.isSet(outputOneMeshOption);
QString inputFilename; QString inputFilename;
if (parser.isSet(inputFilenameOption)) { if (parser.isSet(inputFilenameOption)) {
@ -187,22 +210,42 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
vHacdDelta = parser.value(vHacdDeltaOption).toFloat(); vHacdDelta = parser.value(vHacdDeltaOption).toFloat();
} }
float vHacdConcavity = 0.0025;
if (parser.isSet(vHacdConcavityOption)) {
vHacdConcavity = parser.value(vHacdConcavityOption).toFloat();
}
int vHacdPlanedownsampling = 4;
if (parser.isSet(vHacdPlanedownsamplingOption)) {
vHacdPlanedownsampling = parser.value(vHacdPlanedownsamplingOption).toInt();
}
int vHacdConvexhulldownsampling = 4;
if (parser.isSet(vHacdConvexhulldownsamplingOption)) {
vHacdConvexhulldownsampling = parser.value(vHacdConvexhulldownsamplingOption).toInt();
}
int vHacdMaxVerticesPerCH = 64;
if (parser.isSet(vHacdMaxVerticesPerCHOption)) {
vHacdMaxVerticesPerCH = parser.value(vHacdMaxVerticesPerCHOption).toInt();
}
//set parameters for V-HACD //set parameters for V-HACD
params.m_callback = &pCallBack; //progress callback params.m_callback = &pCallBack; //progress callback
params.m_resolution = vHacdResolution; // 100000 params.m_resolution = vHacdResolution;
params.m_depth = vHacdDepth; // 20 params.m_depth = vHacdDepth;
params.m_concavity = 0.001; // 0.001 params.m_concavity = vHacdConcavity;
params.m_delta = vHacdDelta; // 0.05 params.m_delta = vHacdDelta;
params.m_planeDownsampling = 4; // 4 params.m_planeDownsampling = vHacdPlanedownsampling;
params.m_convexhullDownsampling = 4; // 4 params.m_convexhullDownsampling = vHacdConvexhulldownsampling;
params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes
params.m_beta = 0.05; // 0.05 params.m_beta = 0.05; // 0.05
params.m_gamma = 0.0005; // 0.0005 params.m_gamma = 0.0005; // 0.0005
params.m_pca = 0; // 0 enable/disable normalizing the mesh before applying the convex decomposition params.m_pca = 0; // 0 enable/disable normalizing the mesh before applying the convex decomposition
params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based
params.m_maxNumVerticesPerCH = 64; // 64 params.m_maxNumVerticesPerCH = vHacdMaxVerticesPerCH;
params.m_minVolumePerCH = 0.0001; // 0.0001 params.m_minVolumePerCH = 0.0001; // 0.0001
params.m_callback = 0; // 0 params.m_callback = 0; // 0
params.m_logger = 0; // 0 params.m_logger = 0; // 0
@ -211,8 +254,9 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
// load the mesh // load the mesh
FBXGeometry fbx;
auto begin = std::chrono::high_resolution_clock::now(); auto begin = std::chrono::high_resolution_clock::now();
if (!vUtil.loadFBX(inputFilename, &fbx)){ if (!vUtil.loadFBX(inputFilename, fbx)){
cout << "Error in opening FBX file...."; cout << "Error in opening FBX file....";
} }
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
@ -221,50 +265,37 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
//perform vhacd computation //perform vhacd computation
begin = std::chrono::high_resolution_clock::now(); begin = std::chrono::high_resolution_clock::now();
if (!vUtil.computeVHACD(&fbx, params, &results, startMeshIndex, endMeshIndex, minimumMeshSize, fattenFaces)) { FBXGeometry result;
if (!vUtil.computeVHACD(fbx, params, result, startMeshIndex, endMeshIndex, minimumMeshSize, fattenFaces)) {
cout << "Compute Failed..."; cout << "Compute Failed...";
} }
end = std::chrono::high_resolution_clock::now(); end = std::chrono::high_resolution_clock::now();
auto computeDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count(); auto computeDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
int totalVertices = 0; int totalVertices = 0;
for (int i = 0; i < fbx.meshCount; i++){
totalVertices += fbx.perMeshVertices.at(i).count();
}
int totalTriangles = 0; int totalTriangles = 0;
for (int i = 0; i < fbx.meshCount; i++){ int totalMeshParts = 0;
totalTriangles += fbx.perMeshTriangleIndices.at(i).count(); foreach (const FBXMesh& mesh, result.meshes) {
totalVertices += mesh.vertices.size();
foreach (const FBXMeshPart &meshPart, mesh.parts) {
totalTriangles += meshPart.triangleIndices.size() / 3;
// each quad was made into two triangles
totalTriangles += 2 * meshPart.quadIndices.size() / 4;
totalMeshParts++;
}
} }
int totalHulls = 0; int totalHulls = result.meshes[0].parts.size();
QVector<int> hullCounts = results.convexHullsCountList;
for (int i = 0; i < results.meshCount; i++){
totalHulls += hullCounts.at(i);
}
cout << endl << "Summary of V-HACD Computation..................." << endl; cout << endl << "Summary of V-HACD Computation..................." << endl;
cout << "File Path : " << inputFilename.toStdString() << endl; cout << "File Path : " << inputFilename.toStdString() << endl;
cout << "Number Of Meshes : " << fbx.meshCount << endl; cout << "Number Of Meshes : " << totalMeshParts << endl;
cout << "Processed Meshes : " << results.meshCount << endl;
cout << "Total vertices : " << totalVertices << endl; cout << "Total vertices : " << totalVertices << endl;
cout << "Total Triangles : " << totalTriangles << endl; cout << "Total Triangles : " << totalTriangles << endl;
cout << "Total Convex Hulls : " << totalHulls << endl; cout << "Total Convex Hulls : " << totalHulls << endl;
cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl; cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl;
cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl; cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl;
cout << endl << "Summary per convex hull ........................" << endl <<endl;
for (int i = 0; i < results.meshCount; i++) {
cout << "Mesh : " << i + 1 << endl;
QVector<VHACD::IVHACD::ConvexHull> chList = results.convexHullList.at(i);
cout << "\t" << "Number Of Hulls : " << chList.count() << endl;
for (int j = 0; j < results.convexHullList.at(i).count(); j++){ writeOBJ(outputFilename, result);
cout << "\tHUll : " << j + 1 << endl;
cout << "\t\tNumber Of Points : " << chList.at(j).m_nPoints << endl;
cout << "\t\tNumber Of Triangles : " << chList.at(j).m_nTriangles << endl;
}
}
writeOBJ(outputFilename, results.convexHullList, outputOneMesh);
} }
VHACDUtilApp::~VHACDUtilApp() { VHACDUtilApp::~VHACDUtilApp() {