mirror of
https://github.com/lubosz/overte.git
synced 2025-04-18 14:58:30 +02:00
Merge pull request #8222 from AndrewMeadows/better-simple-compound
simple-compound = wrap each render part of each submesh
This commit is contained in:
commit
20b7ae2e1b
3 changed files with 133 additions and 15 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue