mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 06:03:26 +02:00
Merge pull request #4582 from sethalves/island
Comma toggles rendering of collision hulls; more changes to vhacd stuff
This commit is contained in:
commit
a824403132
11 changed files with 324 additions and 299 deletions
|
@ -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,8 +2980,12 @@ 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...");
|
||||||
|
if (renderCollisionHulls) {
|
||||||
|
_entities.render(RenderArgs::DEBUG_RENDER_MODE, renderSide);
|
||||||
|
} else {
|
||||||
_entities.render(RenderArgs::DEFAULT_RENDER_MODE, renderSide);
|
_entities.render(RenderArgs::DEFAULT_RENDER_MODE, renderSide);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// render JS/scriptable overlays
|
// render JS/scriptable overlays
|
||||||
{
|
{
|
||||||
|
|
|
@ -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++) {
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
|
@ -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>)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -13,8 +13,18 @@
|
||||||
#include "VHACDUtil.h"
|
#include "VHACDUtil.h"
|
||||||
|
|
||||||
|
|
||||||
|
// FBXReader jumbles the order of the meshes by reading them back out of a hashtable. This will put
|
||||||
|
// 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
|
// Read all the meshes from provided FBX file
|
||||||
bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) {
|
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++) {
|
// auto n = results->perMeshVertices.size();
|
||||||
QVector<glm::vec3> vertices = meshes->perMeshVertices.at(i);
|
// results->perMeshVertices[i] << p3;
|
||||||
QVector<int> triangles = meshes->perMeshTriangleIndices.at(i);
|
|
||||||
const float largestDimension = meshes->perMeshLargestDimension.at(i);
|
|
||||||
|
|
||||||
results->perMeshVertices.append(vertices);
|
// results->perMeshTriangleIndices[i] << triangles[j] << n << triangles[j + 1];
|
||||||
results->perMeshTriangleIndices.append(triangles);
|
// results->perMeshTriangleIndices[i] << triangles[j + 1] << n << triangles[j + 2];
|
||||||
results->perMeshLargestDimension.append(largestDimension);
|
// results->perMeshTriangleIndices[i] << triangles[j + 2] << n << triangles[j];
|
||||||
|
// }
|
||||||
|
|
||||||
for (int j = 0; j < triangles.size(); j += 3) {
|
// results->meshCount++;
|
||||||
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();
|
|
||||||
results->perMeshVertices[i] << p3;
|
|
||||||
|
|
||||||
results->perMeshTriangleIndices[i] << triangles[j] << n << triangles[j + 1];
|
|
||||||
results->perMeshTriangleIndices[i] << triangles[j + 1] << n << triangles[j + 2];
|
|
||||||
results->perMeshTriangleIndices[i] << triangles[j + 2] << n << triangles[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
|
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||||
|
|
||||||
|
// each mesh has its own transform to move it to model-space
|
||||||
|
std::vector<glm::vec3> vertices;
|
||||||
|
foreach (glm::vec3 vertex, mesh.vertices) {
|
||||||
|
vertices.push_back(glm::vec3(mesh.modelTransform * glm::vec4(vertex, 1.0f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (const FBXMeshPart &meshPart, mesh.parts) {
|
||||||
|
|
||||||
|
if (count < startMeshIndex || count >= endMeshIndex) {
|
||||||
|
count ++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "--------------------";
|
||||||
|
|
||||||
|
std::vector<int> triangles = meshPart.triangleIndices.toStdVector();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
<< "size =" << largestDimension;
|
||||||
|
|
||||||
if (largestDimension < minimumMeshSize /* || largestDimension > 1000 */) {
|
if (largestDimension < minimumMeshSize /* || largestDimension > 1000 */) {
|
||||||
qDebug() << " Skipping...";
|
qDebug() << " Skipping (too small)...";
|
||||||
|
count++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute approximate convex decomposition
|
// compute approximate convex decomposition
|
||||||
bool res = interfaceVHACD->Compute(&vertices[0].x, 3, nPoints, &triangles[0], 3, nTriangles, params);
|
bool res = interfaceVHACD->Compute(&vertices[0].x, 3, nPoints, &triangles[0], 3, triangleCount, params);
|
||||||
if (!res){
|
if (!res){
|
||||||
qDebug() << "V-HACD computation failed for Mesh : " << i;
|
qDebug() << "V-HACD computation failed for Mesh : " << count;
|
||||||
|
count++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
count++; //For counting number of successfull computations
|
|
||||||
|
|
||||||
//Number of hulls for the mesh
|
// Number of hulls for this input meshPart
|
||||||
unsigned int nConvexHulls = interfaceVHACD->GetNConvexHulls();
|
unsigned int nConvexHulls = interfaceVHACD->GetNConvexHulls();
|
||||||
results->convexHullsCountList.append(nConvexHulls);
|
|
||||||
|
|
||||||
//get all the convex hulls for this mesh
|
// create an output meshPart for each convex hull
|
||||||
QVector<VHACD::IVHACD::ConvexHull> convexHulls;
|
|
||||||
for (unsigned int j = 0; j < nConvexHulls; j++) {
|
for (unsigned int j = 0; j < nConvexHulls; j++) {
|
||||||
VHACD::IVHACD::ConvexHull hull;
|
VHACD::IVHACD::ConvexHull hull;
|
||||||
interfaceVHACD->GetConvexHull(j, hull);
|
interfaceVHACD->GetConvexHull(j, hull);
|
||||||
|
|
||||||
double *m_points_copy = new double[hull.m_nPoints * 3];
|
resultMesh.parts.append(FBXMeshPart());
|
||||||
// std::copy(std::begin(hull.m_points), std::end(hull.m_points), std::begin(m_points_copy));
|
FBXMeshPart &resultMeshPart = resultMesh.parts.last();
|
||||||
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];
|
int hullIndexStart = resultMesh.vertices.size();
|
||||||
// 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_nPoints; i++) {
|
||||||
for (unsigned int i=0; i<hull.m_nTriangles * 3; i++) {
|
float x = hull.m_points[i * 3];
|
||||||
m_triangles_copy[ i ] = hull.m_triangles[ i ];
|
float y = hull.m_points[i * 3 + 1];
|
||||||
|
float z = hull.m_points[i * 3 + 2];
|
||||||
|
resultMesh.vertices.append(glm::vec3(x, y, z));
|
||||||
}
|
}
|
||||||
hull.m_triangles = m_triangles_copy;
|
|
||||||
convexHulls.append(hull);
|
|
||||||
}
|
|
||||||
results->convexHullList.append(convexHulls);
|
|
||||||
} //end of for loop
|
|
||||||
|
|
||||||
results->meshCount = count;
|
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){
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
||||||
foreach (QVector<VHACD::IVHACD::ConvexHull> hulls, meshList) {
|
|
||||||
unsigned int nth = 0;
|
unsigned int nth = 0;
|
||||||
foreach (VHACD::IVHACD::ConvexHull hull, hulls) {
|
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||||
out << "g hull-" << nth++ << "\n";
|
for (int i = 0; i < mesh.vertices.size(); i++) {
|
||||||
for (unsigned int i = 0; i < hull.m_nPoints; i++) {
|
|
||||||
out << "v ";
|
out << "v ";
|
||||||
out << formatFloat(hull.m_points[i*3]) << " ";
|
out << formatFloat(mesh.vertices[i][0]) << " ";
|
||||||
out << formatFloat(hull.m_points[i*3+1]) << " ";
|
out << formatFloat(mesh.vertices[i][1]) << " ";
|
||||||
out << formatFloat(hull.m_points[i*3+2]) << "\n";
|
out << formatFloat(mesh.vertices[i][2]) << "\n";
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i < hull.m_nTriangles; i++) {
|
|
||||||
|
foreach (const FBXMeshPart &meshPart, mesh.parts) {
|
||||||
|
out << "g hull-" << nth++ << "\n";
|
||||||
|
int triangleCount = meshPart.triangleIndices.size() / 3;
|
||||||
|
for (int i = 0; i < triangleCount; 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() {
|
||||||
|
|
Loading…
Reference in a new issue