ShapeManager doesn't support tiny and giant shapes

This commit is contained in:
Andrew Meadows 2014-12-03 10:08:26 -08:00
parent 64cdef42fe
commit 8d49b694cc
4 changed files with 86 additions and 69 deletions

View file

@ -57,87 +57,70 @@ int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) {
} }
void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info) { void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info) {
info._data.clear();
if (shape) { if (shape) {
info._type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType()); int type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType());
switch(info._type) { switch(type) {
case BOX_SHAPE: case BOX_SHAPE: {
{
const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape); const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape);
glm::vec3 halfExtents; glm::vec3 halfExtents;
bulletToGLM(boxShape->getHalfExtentsWithMargin(), halfExtents); bulletToGLM(boxShape->getHalfExtentsWithMargin(), halfExtents);
info._data.push_back(halfExtents); info.setBox(halfExtents);
} }
break; break;
case SPHERE_SHAPE: case SPHERE_SHAPE: {
{
const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape); const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
glm::vec3 data; info.setSphere(sphereShape->getRadius());
bulletToGLM(btVector3(0.0f, 0.0f, sphereShape->getRadius()), data);
info._data.push_back(data);
} }
break; break;
case CYLINDER_SHAPE: case CYLINDER_SHAPE: {
{ // NOTE: we only support cylinders along yAxis
const btCylinderShape* cylinderShape = static_cast<const btCylinderShape*>(shape); const btCylinderShape* cylinderShape = static_cast<const btCylinderShape*>(shape);
glm::vec3 halfExtents; btVector3 halfExtents = cylinderShape->getHalfExtentsWithMargin();
bulletToGLM(cylinderShape->getHalfExtentsWithMargin(), halfExtents); info.setCylinder(halfExtents.getX(), halfExtents.getY());
info._data.push_back(halfExtents);
} }
break; break;
case CAPSULE_SHAPE: case CAPSULE_SHAPE: {
{ // NOTE: we only support capsules along yAxis
const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape); const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape);
glm::vec3 data; info.setCapsule(capsuleShape->getRadius(), capsuleShape->getHalfHeight());
bulletToGLM(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f), data);
info._data.push_back(data);
// NOTE: we only support capsules with axis along yAxis
} }
break; break;
default: default:
info._type = INVALID_SHAPE; info.clear();
break; break;
} }
} else { } else {
info._type = INVALID_SHAPE; info.clear();
} }
} }
btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
btCollisionShape* shape = NULL; btCollisionShape* shape = NULL;
int numData = info._data.size(); const QVector<glm::vec3>& data = info.getData();
switch(info._type) { switch(info.getType()) {
case BOX_SHAPE: { case BOX_SHAPE: {
if (numData > 0) { btVector3 halfExtents;
btVector3 halfExtents; glmToBullet(data[0], halfExtents);
glmToBullet(info._data[0], halfExtents); shape = new btBoxShape(halfExtents);
shape = new btBoxShape(halfExtents);
}
} }
break; break;
case SPHERE_SHAPE: { case SPHERE_SHAPE: {
if (numData > 0) { float radius = data[0].z;
float radius = info._data[0].z; shape = new btSphereShape(radius);
shape = new btSphereShape(radius);
}
} }
break; break;
case CYLINDER_SHAPE: { case CYLINDER_SHAPE: {
if (numData > 0) { btVector3 halfExtents;
btVector3 halfExtents; glmToBullet(data[0], halfExtents);
glmToBullet(info._data[0], halfExtents); // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X // halfExtents = btVector3(radius, halfHeight, unused)
// halfExtents = btVector3(radius, halfHeight, unused) shape = new btCylinderShape(halfExtents);
shape = new btCylinderShape(halfExtents);
}
} }
break; break;
case CAPSULE_SHAPE: { case CAPSULE_SHAPE: {
if (numData > 0) { float radius = data[0].x;
float radius = info._data[0].x; float height = 2.0f * data[0].y;
float height = 2.0f * info._data[0].y; shape = new btCapsuleShape(radius, height);
shape = new btCapsuleShape(radius, height);
}
} }
break; break;
} }
@ -150,12 +133,13 @@ DoubleHashKey ShapeInfoUtil::computeHash(const ShapeInfo& info) {
// scramble the bits of the type // scramble the bits of the type
// TODO?: provide lookup table for hash of info._type rather than recompute? // TODO?: provide lookup table for hash of info._type rather than recompute?
int primeIndex = 0; int primeIndex = 0;
unsigned int hash = DoubleHashKey::hashFunction((unsigned int)info._type, primeIndex++); unsigned int hash = DoubleHashKey::hashFunction((unsigned int)info.getType(), primeIndex++);
const QVector<glm::vec3>& data = info.getData();
glm::vec3 tmpData; glm::vec3 tmpData;
int numData = info._data.size(); int numData = data.size();
for (int i = 0; i < numData; ++i) { for (int i = 0; i < numData; ++i) {
tmpData = info._data[i]; tmpData = data[i];
for (int j = 0; j < 3; ++j) { for (int j = 0; j < 3; ++j) {
// NOTE: 0.49f is used to bump the float up almost half a millimeter // NOTE: 0.49f is used to bump the float up almost half a millimeter
// so the cast to int produces a round() effect rather than a floor() // so the cast to int produces a round() effect rather than a floor()
@ -169,10 +153,10 @@ DoubleHashKey ShapeInfoUtil::computeHash(const ShapeInfo& info) {
// compute hash2 // compute hash2
// scramble the bits of the type // scramble the bits of the type
// TODO?: provide lookup table for hash2 of info._type rather than recompute? // TODO?: provide lookup table for hash2 of info._type rather than recompute?
hash = DoubleHashKey::hashFunction2((unsigned int)info._type); hash = DoubleHashKey::hashFunction2((unsigned int)info.getType());
for (int i = 0; i < numData; ++i) { for (int i = 0; i < numData; ++i) {
tmpData = info._data[i]; tmpData = data[i];
for (int j = 0; j < 3; ++j) { for (int j = 0; j < 3; ++j) {
// NOTE: 0.49f is used to bump the float up almost half a millimeter // NOTE: 0.49f is used to bump the float up almost half a millimeter
// so the cast to int produces a round() effect rather than a floor() // so the cast to int produces a round() effect rather than a floor()

View file

@ -10,6 +10,9 @@
// //
#ifdef USE_BULLET_PHYSICS #ifdef USE_BULLET_PHYSICS
#include <glm/gtx/norm.hpp>
#include "ShapeInfoUtil.h" #include "ShapeInfoUtil.h"
#include "ShapeManager.h" #include "ShapeManager.h"
@ -25,23 +28,28 @@ ShapeManager::~ShapeManager() {
_shapeMap.clear(); _shapeMap.clear();
} }
btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
// Very small or large objects are not supported.
float diagonal = glm::length2(info.getBoundingBoxDiagonal());
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) {
return NULL;
}
DoubleHashKey key = ShapeInfoUtil::computeHash(info); DoubleHashKey key = ShapeInfoUtil::computeHash(info);
ShapeReference* shapeRef = _shapeMap.find(key); ShapeReference* shapeRef = _shapeMap.find(key);
if (shapeRef) { if (shapeRef) {
shapeRef->_refCount++; shapeRef->_refCount++;
return shapeRef->_shape; return shapeRef->_shape;
} else {
btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info);
if (shape) {
ShapeReference newRef;
newRef._refCount = 1;
newRef._shape = shape;
_shapeMap.insert(key, newRef);
}
return shape;
} }
btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info);
if (shape) {
ShapeReference newRef;
newRef._refCount = 1;
newRef._shape = shape;
_shapeMap.insert(key, newRef);
}
return shape;
} }
bool ShapeManager::releaseShape(const ShapeInfo& info) { bool ShapeManager::releaseShape(const ShapeInfo& info) {

View file

@ -16,6 +16,11 @@
//#include "DoubleHashKey.h" //#include "DoubleHashKey.h"
#include "ShapeInfo.h" #include "ShapeInfo.h"
void ShapeInfo::clear() {
_type = INVALID_SHAPE;
_data.clear();
}
void ShapeInfo::setBox(const glm::vec3& halfExtents) { void ShapeInfo::setBox(const glm::vec3& halfExtents) {
_type = BOX_SHAPE; _type = BOX_SHAPE;
_data.clear(); _data.clear();
@ -25,19 +30,31 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) {
void ShapeInfo::setSphere(float radius) { void ShapeInfo::setSphere(float radius) {
_type = SPHERE_SHAPE; _type = SPHERE_SHAPE;
_data.clear(); _data.clear();
_data.push_back(glm::vec3(0.0f, 0.0f, radius)); _data.push_back(glm::vec3(radius));
} }
void ShapeInfo::setCylinder(float radius, float height) { void ShapeInfo::setCylinder(float radius, float halfHeight) {
_type = CYLINDER_SHAPE; _type = CYLINDER_SHAPE;
_data.clear(); _data.clear();
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X // NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
_data.push_back(glm::vec3(radius, 0.5f * height, radius)); _data.push_back(glm::vec3(radius, halfHeight, radius));
} }
void ShapeInfo::setCapsule(float radius, float height) { void ShapeInfo::setCapsule(float radius, float halfHeight) {
_type = CAPSULE_SHAPE; _type = CAPSULE_SHAPE;
_data.clear(); _data.clear();
_data.push_back(glm::vec3(radius, 0.5f * height, 0.0f)); _data.push_back(glm::vec3(radius, halfHeight, radius));
} }
glm::vec3 ShapeInfo::getBoundingBoxDiagonal() const {
switch(_type) {
case BOX_SHAPE:
case SPHERE_SHAPE:
case CYLINDER_SHAPE:
case CAPSULE_SHAPE:
return 2.0f * _data[0];
default:
break;
}
return glm::vec3(0.0f);
}

View file

@ -21,11 +21,19 @@ class ShapeInfo {
public: public:
ShapeInfo() : _type(INVALID_SHAPE) {} ShapeInfo() : _type(INVALID_SHAPE) {}
void clear();
void setBox(const glm::vec3& halfExtents); void setBox(const glm::vec3& halfExtents);
void setSphere(float radius); void setSphere(float radius);
void setCylinder(float radius, float height); void setCylinder(float radius, float halfHeight);
void setCapsule(float radius, float height); void setCapsule(float radius, float halfHeight);
const int getType() const { return _type; }
const QVector<glm::vec3>& getData() const { return _data; }
glm::vec3 getBoundingBoxDiagonal() const;
protected:
int _type; int _type;
QVector<glm::vec3> _data; QVector<glm::vec3> _data;
}; };