mirror of
https://github.com/lubosz/overte.git
synced 2025-08-08 03:48:38 +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 <glm/gtx/quaternion.hpp>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
@ -690,8 +691,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
glm::vec3 scaleToFit = dimensions / _model->getFBXGeometry().getUnscaledMeshExtents().size();
|
glm::vec3 scaleToFit = dimensions / _model->getFBXGeometry().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.
|
||||||
// also determine the extents of the collision model.
|
// also determine the extents of the collision model.
|
||||||
for (int i = 0; i < pointCollection.size(); i++) {
|
for (int32_t i = 0; i < pointCollection.size(); i++) {
|
||||||
for (int j = 0; j < pointCollection[i].size(); j++) {
|
for (int32_t j = 0; j < pointCollection[i].size(); j++) {
|
||||||
// compensate for registration
|
// compensate for registration
|
||||||
pointCollection[i][j] += _model->getOffset();
|
pointCollection[i][j] += _model->getOffset();
|
||||||
// scale so the collision points match the model points
|
// scale so the collision points match the model points
|
||||||
|
@ -708,9 +709,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
// compute meshPart local transforms
|
// compute meshPart local transforms
|
||||||
QVector<glm::mat4> localTransforms;
|
QVector<glm::mat4> localTransforms;
|
||||||
const FBXGeometry& fbxGeometry = _model->getFBXGeometry();
|
const FBXGeometry& fbxGeometry = _model->getFBXGeometry();
|
||||||
int numberOfMeshes = fbxGeometry.meshes.size();
|
int32_t numMeshes = (int32_t)fbxGeometry.meshes.size();
|
||||||
int totalNumVertices = 0;
|
int32_t totalNumVertices = 0;
|
||||||
for (int i = 0; i < numberOfMeshes; i++) {
|
for (int32_t i = 0; i < numMeshes; i++) {
|
||||||
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
||||||
if (mesh.clusters.size() > 0) {
|
if (mesh.clusters.size() > 0) {
|
||||||
const FBXCluster& cluster = mesh.clusters.at(0);
|
const FBXCluster& cluster = mesh.clusters.at(0);
|
||||||
|
@ -722,7 +723,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
}
|
}
|
||||||
totalNumVertices += mesh.vertices.size();
|
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) {
|
if (totalNumVertices > MAX_VERTICES_PER_STATIC_MESH) {
|
||||||
qWarning() << "model" << getModelURL() << "has too many vertices" << totalNumVertices << "and will collide as a box.";
|
qWarning() << "model" << getModelURL() << "has too many vertices" << totalNumVertices << "and will collide as a box.";
|
||||||
info.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions);
|
info.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions);
|
||||||
|
@ -730,7 +731,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& meshes = _model->getGeometry()->getGeometry()->getMeshes();
|
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();
|
ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||||
pointCollection.clear();
|
pointCollection.clear();
|
||||||
|
@ -741,8 +744,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Extents extents;
|
Extents extents;
|
||||||
int meshCount = 0;
|
int32_t meshCount = 0;
|
||||||
int pointListIndex = 0;
|
int32_t pointListIndex = 0;
|
||||||
for (auto& mesh : meshes) {
|
for (auto& mesh : meshes) {
|
||||||
const gpu::BufferView& vertices = mesh->getVertexBuffer();
|
const gpu::BufferView& vertices = mesh->getVertexBuffer();
|
||||||
const gpu::BufferView& indices = mesh->getIndexBuffer();
|
const gpu::BufferView& indices = mesh->getIndexBuffer();
|
||||||
|
@ -775,6 +778,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
if (type == SHAPE_TYPE_STATIC_MESH) {
|
if (type == SHAPE_TYPE_STATIC_MESH) {
|
||||||
// copy into triangleIndices
|
// copy into triangleIndices
|
||||||
ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices();
|
ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices();
|
||||||
|
triangleIndices.clear();
|
||||||
triangleIndices.reserve((int32_t)((gpu::Size)(triangleIndices.size()) + indices.getNumElements()));
|
triangleIndices.reserve((int32_t)((gpu::Size)(triangleIndices.size()) + indices.getNumElements()));
|
||||||
gpu::BufferView::Iterator<const model::Mesh::Part> partItr = parts.cbegin<const model::Mesh::Part>();
|
gpu::BufferView::Iterator<const model::Mesh::Part> partItr = parts.cbegin<const model::Mesh::Part>();
|
||||||
while (partItr != parts.cend<const model::Mesh::Part>()) {
|
while (partItr != parts.cend<const model::Mesh::Part>()) {
|
||||||
|
@ -823,6 +827,64 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
}
|
}
|
||||||
++partItr;
|
++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;
|
++meshCount;
|
||||||
}
|
}
|
||||||
|
@ -830,13 +892,13 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
// scale and shift
|
// scale and shift
|
||||||
glm::vec3 extentsSize = extents.size();
|
glm::vec3 extentsSize = extents.size();
|
||||||
glm::vec3 scaleToFit = dimensions / extentsSize;
|
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) {
|
if (extentsSize[i] < 1.0e-6f) {
|
||||||
scaleToFit[i] = 1.0f;
|
scaleToFit[i] = 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto points : pointCollection) {
|
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);
|
points[i] = (points[i] * scaleToFit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ static const btVector3 _unitSphereDirections[NUM_UNIT_SPHERE_DIRECTIONS] = {
|
||||||
|
|
||||||
// util method
|
// util method
|
||||||
btConvexHullShape* createConvexHull(const ShapeInfo::PointList& points) {
|
btConvexHullShape* createConvexHull(const ShapeInfo::PointList& points) {
|
||||||
|
//std::cout << "adebug createConvexHull() points.size() = " << points.size() << std::endl; // adebug
|
||||||
assert(points.size() > 0);
|
assert(points.size() > 0);
|
||||||
|
|
||||||
btConvexHullShape* hull = new btConvexHullShape();
|
btConvexHullShape* hull = new btConvexHullShape();
|
||||||
|
@ -240,6 +241,7 @@ void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) {
|
||||||
btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
|
btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
|
||||||
btCollisionShape* shape = NULL;
|
btCollisionShape* shape = NULL;
|
||||||
int type = info.getType();
|
int type = info.getType();
|
||||||
|
//std::cout << "adebug createShapeFromInfo() type = " << type << std::endl; // adebug
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SHAPE_TYPE_BOX: {
|
case SHAPE_TYPE_BOX: {
|
||||||
shape = new btBoxShape(glmToBullet(info.getHalfExtents()));
|
shape = new btBoxShape(glmToBullet(info.getHalfExtents()));
|
||||||
|
@ -258,8 +260,7 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SHAPE_TYPE_COMPOUND:
|
case SHAPE_TYPE_COMPOUND:
|
||||||
case SHAPE_TYPE_SIMPLE_HULL:
|
case SHAPE_TYPE_SIMPLE_HULL: {
|
||||||
case SHAPE_TYPE_SIMPLE_COMPOUND: {
|
|
||||||
const ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
const ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||||
uint32_t numSubShapes = info.getNumSubShapes();
|
uint32_t numSubShapes = info.getNumSubShapes();
|
||||||
if (numSubShapes == 1) {
|
if (numSubShapes == 1) {
|
||||||
|
@ -270,12 +271,63 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
|
||||||
trans.setIdentity();
|
trans.setIdentity();
|
||||||
foreach (const ShapeInfo::PointList& hullPoints, pointCollection) {
|
foreach (const ShapeInfo::PointList& hullPoints, pointCollection) {
|
||||||
btConvexHullShape* hull = createConvexHull(hullPoints);
|
btConvexHullShape* hull = createConvexHull(hullPoints);
|
||||||
compound->addChildShape (trans, hull);
|
compound->addChildShape(trans, hull);
|
||||||
}
|
}
|
||||||
shape = compound;
|
shape = compound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case SHAPE_TYPE_STATIC_MESH: {
|
||||||
btTriangleIndexVertexArray* dataArray = createStaticMeshArray(info);
|
btTriangleIndexVertexArray* dataArray = createStaticMeshArray(info);
|
||||||
shape = new StaticMeshShape(dataArray);
|
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.
|
// trim convex hulls with many points down to only 42 points.
|
||||||
const int MAX_HULL_POINTS = 42;
|
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 {
|
enum ShapeType {
|
||||||
SHAPE_TYPE_NONE,
|
SHAPE_TYPE_NONE,
|
||||||
SHAPE_TYPE_BOX,
|
SHAPE_TYPE_BOX,
|
||||||
|
@ -50,7 +54,7 @@ public:
|
||||||
|
|
||||||
using PointList = QVector<glm::vec3>;
|
using PointList = QVector<glm::vec3>;
|
||||||
using PointCollection = QVector<PointList>;
|
using PointCollection = QVector<PointList>;
|
||||||
using TriangleIndices = QVector<uint32_t>;
|
using TriangleIndices = QVector<int32_t>;
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue