Merge pull request #8222 from AndrewMeadows/better-simple-compound

simple-compound = wrap each render part of each submesh
This commit is contained in:
Brad Hefta-Gaub 2016-07-12 19:56:04 -07:00 committed by GitHub
commit 20b7ae2e1b
3 changed files with 133 additions and 15 deletions

View file

@ -10,6 +10,7 @@
//
#include <glm/gtx/quaternion.hpp>
#include <set>
#include <QJsonDocument>
#include <QtCore/QThread>
@ -690,8 +691,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
glm::vec3 scaleToFit = dimensions / _model->getFBXGeometry().getUnscaledMeshExtents().size();
// multiply each point by scale before handing the point-set off to the physics engine.
// also determine the extents of the collision model.
for (int i = 0; i < pointCollection.size(); i++) {
for (int j = 0; j < pointCollection[i].size(); j++) {
for (int32_t i = 0; i < pointCollection.size(); i++) {
for (int32_t j = 0; j < pointCollection[i].size(); j++) {
// compensate for registration
pointCollection[i][j] += _model->getOffset();
// scale so the collision points match the model points
@ -708,9 +709,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
// compute meshPart local transforms
QVector<glm::mat4> localTransforms;
const FBXGeometry& fbxGeometry = _model->getFBXGeometry();
int numberOfMeshes = fbxGeometry.meshes.size();
int totalNumVertices = 0;
for (int i = 0; i < numberOfMeshes; i++) {
int32_t numMeshes = (int32_t)fbxGeometry.meshes.size();
int32_t totalNumVertices = 0;
for (int32_t i = 0; i < numMeshes; i++) {
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
if (mesh.clusters.size() > 0) {
const FBXCluster& cluster = mesh.clusters.at(0);
@ -722,7 +723,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
}
totalNumVertices += mesh.vertices.size();
}
const int MAX_VERTICES_PER_STATIC_MESH = 1e6;
const int32_t MAX_VERTICES_PER_STATIC_MESH = 1e6;
if (totalNumVertices > MAX_VERTICES_PER_STATIC_MESH) {
qWarning() << "model" << getModelURL() << "has too many vertices" << totalNumVertices << "and will collide as a box.";
info.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions);
@ -730,7 +731,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
}
auto& meshes = _model->getGeometry()->getGeometry()->getMeshes();
int32_t numMeshes = (int32_t)(meshes.size());
// the render geometry's mesh count should match that of the FBXGeometry
assert(numMeshes == (int32_t)(meshes.size()));
ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
pointCollection.clear();
@ -741,8 +744,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
}
Extents extents;
int meshCount = 0;
int pointListIndex = 0;
int32_t meshCount = 0;
int32_t pointListIndex = 0;
for (auto& mesh : meshes) {
const gpu::BufferView& vertices = mesh->getVertexBuffer();
const gpu::BufferView& indices = mesh->getIndexBuffer();
@ -775,6 +778,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
if (type == SHAPE_TYPE_STATIC_MESH) {
// copy into triangleIndices
ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices();
triangleIndices.clear();
triangleIndices.reserve((int32_t)((gpu::Size)(triangleIndices.size()) + indices.getNumElements()));
gpu::BufferView::Iterator<const model::Mesh::Part> partItr = parts.cbegin<const model::Mesh::Part>();
while (partItr != parts.cend<const model::Mesh::Part>()) {
@ -823,6 +827,64 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
}
++partItr;
}
} else if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
// for each mesh copy unique part indices, separated by special bogus (flag) index values
ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices();
triangleIndices.clear();
gpu::BufferView::Iterator<const model::Mesh::Part> partItr = parts.cbegin<const model::Mesh::Part>();
while (partItr != parts.cend<const model::Mesh::Part>()) {
// collect unique list of indices for this part
std::set<int32_t> uniqueIndices;
if (partItr->_topology == model::Mesh::TRIANGLES) {
assert(partItr->_numIndices % 3 == 0);
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
auto indexEnd = indexItr + partItr->_numIndices;
while (indexItr != indexEnd) {
uniqueIndices.insert(*indexItr);
++indexItr;
}
} else if (partItr->_topology == model::Mesh::TRIANGLE_STRIP) {
assert(partItr->_numIndices > 2);
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
auto indexEnd = indexItr + (partItr->_numIndices - 2);
// first triangle uses the first three indices
uniqueIndices.insert(*(indexItr++));
uniqueIndices.insert(*(indexItr++));
uniqueIndices.insert(*(indexItr++));
// the rest use previous and next index
uint32_t triangleCount = 1;
while (indexItr != indexEnd) {
if ((*indexItr) != model::Mesh::PRIMITIVE_RESTART_INDEX) {
if (triangleCount % 2 == 0) {
// even triangles use first two indices in order
uniqueIndices.insert(*(indexItr - 2));
uniqueIndices.insert(*(indexItr - 1));
} else {
// odd triangles swap order of first two indices
uniqueIndices.insert(*(indexItr - 1));
uniqueIndices.insert(*(indexItr - 2));
}
uniqueIndices.insert(*indexItr);
++triangleCount;
}
++indexItr;
}
}
// store uniqueIndices in triangleIndices
triangleIndices.reserve(triangleIndices.size() + (int32_t)uniqueIndices.size());
for (auto index : uniqueIndices) {
triangleIndices.push_back(index);
}
// flag end of part
triangleIndices.push_back(END_OF_MESH_PART);
++partItr;
}
// flag end of mesh
triangleIndices.push_back(END_OF_MESH);
}
++meshCount;
}
@ -830,13 +892,13 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
// scale and shift
glm::vec3 extentsSize = extents.size();
glm::vec3 scaleToFit = dimensions / extentsSize;
for (int i = 0; i < 3; ++i) {
for (int32_t i = 0; i < 3; ++i) {
if (extentsSize[i] < 1.0e-6f) {
scaleToFit[i] = 1.0f;
}
}
for (auto points : pointCollection) {
for (int i = 0; i < points.size(); ++i) {
for (int32_t i = 0; i < points.size(); ++i) {
points[i] = (points[i] * scaleToFit);
}
}

View file

@ -69,6 +69,7 @@ static const btVector3 _unitSphereDirections[NUM_UNIT_SPHERE_DIRECTIONS] = {
// util method
btConvexHullShape* createConvexHull(const ShapeInfo::PointList& points) {
//std::cout << "adebug createConvexHull() points.size() = " << points.size() << std::endl; // adebug
assert(points.size() > 0);
btConvexHullShape* hull = new btConvexHullShape();
@ -240,6 +241,7 @@ void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) {
btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
btCollisionShape* shape = NULL;
int type = info.getType();
//std::cout << "adebug createShapeFromInfo() type = " << type << std::endl; // adebug
switch(type) {
case SHAPE_TYPE_BOX: {
shape = new btBoxShape(glmToBullet(info.getHalfExtents()));
@ -258,8 +260,7 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
}
break;
case SHAPE_TYPE_COMPOUND:
case SHAPE_TYPE_SIMPLE_HULL:
case SHAPE_TYPE_SIMPLE_COMPOUND: {
case SHAPE_TYPE_SIMPLE_HULL: {
const ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
uint32_t numSubShapes = info.getNumSubShapes();
if (numSubShapes == 1) {
@ -270,12 +271,63 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
trans.setIdentity();
foreach (const ShapeInfo::PointList& hullPoints, pointCollection) {
btConvexHullShape* hull = createConvexHull(hullPoints);
compound->addChildShape (trans, hull);
compound->addChildShape(trans, hull);
}
shape = compound;
}
}
break;
case SHAPE_TYPE_SIMPLE_COMPOUND: {
const ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
const ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices();
uint32_t numIndices = triangleIndices.size();
uint32_t numMeshes = info.getNumSubShapes();
const uint32_t MIN_NUM_SIMPLE_COMPOUND_INDICES = 2; // END_OF_MESH_PART + END_OF_MESH
if (numMeshes > 0 && numIndices > MIN_NUM_SIMPLE_COMPOUND_INDICES) {
uint32_t i = 0;
std::vector<btConvexHullShape*> hulls;
for (auto& points : pointCollection) {
// build a hull around each part
while (i < numIndices) {
ShapeInfo::PointList hullPoints;
hullPoints.reserve(points.size());
while (i < numIndices) {
int32_t j = triangleIndices[i];
++i;
if (j == END_OF_MESH_PART) {
// end of part
break;
}
hullPoints.push_back(points[j]);
}
if (hullPoints.size() > 0) {
btConvexHullShape* hull = createConvexHull(hullPoints);
hulls.push_back(hull);
}
assert(i < numIndices);
if (triangleIndices[i] == END_OF_MESH) {
// end of mesh
++i;
break;
}
}
}
uint32_t numHulls = (uint32_t)hulls.size();
if (numHulls == 1) {
shape = hulls[0];
} else {
auto compound = new btCompoundShape();
btTransform trans;
trans.setIdentity();
for (auto hull : hulls) {
compound->addChildShape(trans, hull);
}
shape = compound;
}
}
}
break;
case SHAPE_TYPE_STATIC_MESH: {
btTriangleIndexVertexArray* dataArray = createStaticMeshArray(info);
shape = new StaticMeshShape(dataArray);

View file

@ -26,6 +26,10 @@ const float MIN_SHAPE_OFFSET = 0.001f; // offsets less than 1mm will be ignored
// trim convex hulls with many points down to only 42 points.
const int MAX_HULL_POINTS = 42;
const int32_t END_OF_MESH_PART = -1; // bogus vertex index at end of mesh part
const int32_t END_OF_MESH = -2; // bogus vertex index at end of mesh
enum ShapeType {
SHAPE_TYPE_NONE,
SHAPE_TYPE_BOX,
@ -50,7 +54,7 @@ public:
using PointList = QVector<glm::vec3>;
using PointCollection = QVector<PointList>;
using TriangleIndices = QVector<uint32_t>;
using TriangleIndices = QVector<int32_t>;
void clear();