mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-14 13:49:11 +02:00
Merge pull request #4345 from virneo/20305
CR for Job #20305 - Physics: V-HACD convex decomposition utilities
This commit is contained in:
commit
375255f22e
9 changed files with 412 additions and 14 deletions
1
BUILD.md
1
BUILD.md
|
@ -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
|
||||
|
||||
|
|
15
BUILD_WIN.md
15
BUILD_WIN.md
|
@ -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.
|
||||
|
||||
|
|
59
cmake/modules/FindVHACD.cmake
Normal file
59
cmake/modules/FindVHACD.cmake
Normal 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)
|
|
@ -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)
|
|
@ -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()
|
||||
|
|
23
tools/vhacd/CMakeLists.txt
Normal file
23
tools/vhacd/CMakeLists.txt
Normal 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})
|
129
tools/vhacd/src/VHACDUtil.cpp
Normal file
129
tools/vhacd/src/VHACDUtil.cpp
Normal 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(){}
|
55
tools/vhacd/src/VHACDUtil.h
Normal file
55
tools/vhacd/src/VHACDUtil.h
Normal 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
111
tools/vhacd/src/main.cpp
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue