Merge pull request #4345 from virneo/20305

CR for Job #20305 - Physics: V-HACD convex decomposition utilities
This commit is contained in:
Andrew Meadows 2015-02-26 13:24:49 -08:00
commit 375255f22e
9 changed files with 412 additions and 14 deletions

View file

@ -4,6 +4,7 @@
* [Qt](http://qt-project.org/downloads) ~> 5.3.2
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
####CMake External Project Dependencies

View file

@ -79,6 +79,21 @@ To prevent these problems, install OpenSSL yourself. Download the following bina
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
###vhacd
Download it directly from https://github.com/virneo/v-hacd
To build it run the following commands
1. cd src\
2. mkdir build
3. cd build
4. cmake ..
Build using visual studio 2013. Build ALL_BUILD and INSTALL targets both in Release and Debug.
This will create an output folder with include and lib directory inside it.
Either copy the contents of output folder to ENV %HIFI_LIB_DIR%/vhacd or create an environment variable VHACD_ROOT_DIR to this output directory.
###Build High Fidelity using Visual Studio
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.

View file

@ -0,0 +1,59 @@
#
# FindVHACD.cmake
#
# Try to find the V-HACD library that decomposes a 3D surface into a set of "near" convex parts.
#
# Once done this will define
#
# VHACD_FOUND - system found V-HACD
# VHACD_INCLUDE_DIRS - the V-HACD include directory
# VHACD_LIBRARIES - link to this to use V-HACD
#
# Created on 2/20/2015 by Virendra Singh
# Copyright 2015 High Fidelity, Inc.
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("vhacd")
macro(_FIND_VHACD_LIBRARY _var)
set(_${_var}_NAMES ${ARGN})
find_library(${_var}_LIBRARY_RELEASE
NAMES ${_${_var}_NAMES}
HINTS
${VHACD_SEARCH_DIRS}
$ENV{VHACD_ROOT_DIR}
PATH_SUFFIXES lib lib/Release
)
find_library(${_var}_LIBRARY_DEBUG
NAMES ${_${_var}_NAMES}
HINTS
${VHACD_SEARCH_DIRS}
$ENV{VHACD_ROOT_DIR}
PATH_SUFFIXES lib lib/Debug
)
select_library_configurations(${_var})
mark_as_advanced(${_var}_LIBRARY)
mark_as_advanced(${_var}_LIBRARY)
endmacro()
find_path(VHACD_INCLUDE_DIRS VHACD.h PATH_SUFFIXES include HINTS ${VHACD_SEARCH_DIRS} $ENV{VHACD_ROOT_DIR})
if(NOT WIN32)
_FIND_VHACD_LIBRARY(VHACD libVHACD.a)
else()
_FIND_VHACD_LIBRARY(VHACD VHACD_LIB)
endif()
set(VHACD_LIBRARIES ${VHACD_LIBRARY})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(VHACD "Could NOT find VHACD, try to set the path to VHACD root folder in the system variable VHACD_ROOT_DIR or create a directory vhacd in HIFI_LIB_DIR and paste the necessary files there"
VHACD_INCLUDE_DIRS VHACD_LIBRARIES)
mark_as_advanced(VHACD_INCLUDE_DIRS VHACD_LIBRARIES VHACD_SEARCH_DIRS)

View file

@ -1,15 +1,15 @@
set(TARGET_NAME render-utils)
AUTOSCRIBE_SHADER_LIB()
# pull in the resources.qrc file
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
setup_hifi_library(Widgets OpenGL Network Script)
add_dependency_external_projects(glm)
find_package(GLM REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
set(TARGET_NAME render-utils)
AUTOSCRIBE_SHADER_LIB()
# pull in the resources.qrc file
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
setup_hifi_library(Widgets OpenGL Network Script)
add_dependency_external_projects(glm)
find_package(GLM REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
link_hifi_libraries(animation fbx shared gpu)

View file

@ -3,3 +3,8 @@ add_subdirectory(bitstream2json)
add_subdirectory(json2bitstream)
add_subdirectory(mtc)
add_subdirectory(scribe)
find_package(VHACD)
if(VHACD_FOUND)
add_subdirectory(vhacd)
endif()

View file

@ -0,0 +1,23 @@
set(TARGET_NAME vhacd)
setup_hifi_project()
link_hifi_libraries(shared model fbx gpu networking octree)
#find_package(VHACD REQUIRED) done in CMakeList.txt in parent directory
target_include_directories(${TARGET_NAME} PUBLIC ${VHACD_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${VHACD_LIBRARIES})
if(NOT WIN32)
find_package( Threads)
target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT})
include(FindOpenMP)
if(OPENMP_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()
endif()
add_dependency_external_projects(glm)
find_package(GLM REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})

View file

@ -0,0 +1,129 @@
//
// VHACDUtil.cpp
// tools/vhacd/src
//
// Created by Virendra Singh on 2/20/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QVector>
#include "VHACDUtil.h"
//Read all the meshes from provided FBX file
bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results){
// open the fbx file
QFile fbx(filename);
if (!fbx.open(QIODevice::ReadOnly)) {
return false;
}
std::cout << "Reading FBX.....\n";
QByteArray fbxContents = fbx.readAll();
FBXGeometry geometry = readFBX(fbxContents, QVariantHash());
//results->meshCount = geometry.meshes.count();
int count = 0;
foreach(FBXMesh mesh, geometry.meshes){
//get vertices for each mesh
QVector<glm::vec3> vertices = mesh.vertices;
//get the triangle indices for each mesh
QVector<int> triangles;
foreach(FBXMeshPart part, mesh.parts){
QVector<int> indices = part.triangleIndices;
triangles += indices;
}
//only read meshes with triangles
if (triangles.count() <= 0){
continue;
}
results->perMeshVertices.append(vertices);
results->perMeshTriangleIndices.append(triangles);
count++;
}
results->meshCount = count;
return true;
}
bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params, vhacd::ComputeResults *results)const{
VHACD::IVHACD * interfaceVHACD = VHACD::CreateVHACD();
int meshCount = meshes->meshCount;
int count = 0;
std::cout << "Performing V-HACD computation on " << meshCount << " meshes ..... " << std::endl;
for (int i = 0; i < meshCount; i++){
std::vector<glm::vec3> vertices = meshes->perMeshVertices.at(i).toStdVector();
std::vector<int> triangles = meshes->perMeshTriangleIndices.at(i).toStdVector();
int nPoints = (unsigned int)vertices.size();
int nTriangles = (unsigned int)triangles.size() / 3;
std::cout << "Mesh " << i + 1 << " : ";
// compute approximate convex decomposition
bool res = interfaceVHACD->Compute(&vertices[0].x, 3, nPoints, &triangles[0], 3, nTriangles, params);
if (!res){
std::cout << "V-HACD computation failed for Mesh : " << i + 1 << std::endl;
continue;
}
count++; //For counting number of successfull computations
//Number of hulls for the mesh
unsigned int nConvexHulls = interfaceVHACD->GetNConvexHulls();
results->convexHullsCountList.append(nConvexHulls);
//get all the convex hulls for this mesh
QVector<VHACD::IVHACD::ConvexHull> convexHulls;
for (unsigned int j = 0; j < nConvexHulls; j++){
VHACD::IVHACD::ConvexHull hull;
interfaceVHACD->GetConvexHull(j, hull);
convexHulls.append(hull);
}
results->convexHullList.append(convexHulls);
} //end of for loop
results->meshCount = count;
//release memory
interfaceVHACD->Clean();
interfaceVHACD->Release();
if (count > 0){
return true;
}
else{
return false;
}
}
vhacd::VHACDUtil:: ~VHACDUtil(){
//nothing to be cleaned
}
//ProgressClaback implementation
void vhacd::ProgressCallback::Update(const double overallProgress, const double stageProgress, const double operationProgress,
const char * const stage, const char * const operation){
int progress = (int)(overallProgress + 0.5);
if (progress < 10){
std::cout << "\b\b";
}
else{
std::cout << "\b\b\b";
}
std::cout << progress << "%";
if (progress >= 100){
std::cout << std::endl;
}
}
vhacd::ProgressCallback::ProgressCallback(void){}
vhacd::ProgressCallback::~ProgressCallback(){}

View file

@ -0,0 +1,55 @@
//
// VHACDUtil.h
// tools/vhacd/src
//
// Created by Virendra Singh on 2/20/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_VHACDUtil_h
#define hifi_VHACDUtil_h
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <chrono> //c++11 feature
#include <QFile>
#include <FBXReader.h>
#include <VHACD.h>
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;
}LoadFBXResults;
class VHACDUtil{
public:
bool loadFBX(const QString filename, vhacd::LoadFBXResults *results);
bool computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params, vhacd::ComputeResults *results)const;
~VHACDUtil();
};
class ProgressCallback : public VHACD::IVHACD::IUserCallback{
public:
ProgressCallback(void);
~ProgressCallback();
//Couldn't follow coding guideline here due to virtual function declared in IUserCallback
void Update(const double overallProgress, const double stageProgress, const double operationProgress,
const char * const stage, const char * const operation);
};
}
#endif //hifi_VHACDUtil_h

111
tools/vhacd/src/main.cpp Normal file
View file

@ -0,0 +1,111 @@
//
// main.cpp
// tools/vhacd/src
//
// Created by Virendra Singh on 2/20/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <VHACD.h>
#include <string>
#include <vector>
#include "VHACDUtil.h"
using namespace std;
using namespace VHACD;
int main(int argc, char * argv[]){
vector<int> triangles; // array of indexes
vector<float> points; // array of coordinates
vhacd::VHACDUtil vUtil;
vhacd::LoadFBXResults fbx; //mesh data from loaded fbx file
vhacd::ComputeResults results; // results after computing vhacd
VHACD::IVHACD::Parameters params;
vhacd::ProgressCallback pCallBack;
if (argc < 2){
cout << "please provide a FBX file as argument\n ";
return 1;
}
string filename(argv[1]);
if (filename.empty()){
cout << "please provide a FBX file as argument\n ";
return 1;
}
QString fname = QString::fromStdString(filename);
//set parameters for V-HACD
params.m_callback = &pCallBack; //progress callback
params.m_resolution = 50000;
params.m_depth = 10;
params.m_concavity = 0.003;
params.m_alpha = 0.05; // controls the bias toward clipping along symmetry planes
params.m_pca = 1; // enable/disable normalizing the mesh before applying the convex decomposition
params.m_mode = 1; // 0: voxel - based approximate convex decomposition, 1 : tetrahedron - based approximate convex decomposition
params.m_maxNumVerticesPerCH = 128;
params.m_minVolumePerCH = 0.0001; // controls the adaptive sampling of the generated convex - hulls
// load the mesh
auto begin = std::chrono::high_resolution_clock::now();
if (!vUtil.loadFBX(fname, &fbx)){
cout << "Error in opening FBX file....";
return 1;
}
auto end = std::chrono::high_resolution_clock::now();
auto loadDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
//perform vhacd computation
begin = std::chrono::high_resolution_clock::now();
if (!vUtil.computeVHACD(&fbx, params, &results)){
cout << "Compute Failed...";
return 1;
}
end = std::chrono::high_resolution_clock::now();
auto computeDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
int totalVertices = 0;
for (int i = 0; i < fbx.meshCount; i++){
totalVertices += fbx.perMeshVertices.at(i).count();
}
int totalTriangles = 0;
for (int i = 0; i < fbx.meshCount; i++){
totalTriangles += fbx.perMeshTriangleIndices.at(i).count();
}
int totalHulls = 0;
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 << "File Path : " << fname.toStdString() << endl;
cout << "Number Of Meshes : " << fbx.meshCount << endl;
cout << "Processed Meshes : " << results.meshCount << endl;
cout << "Total vertices : " << totalVertices << endl;
cout << "Total Triangles : " << totalTriangles << endl;
cout << "Total Convex Hulls : " << totalHulls << endl;
cout << "Total FBX load time: " << (double)loadDuration / 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++){
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;
}
}
getchar();
return 0;
}