Fixes Bullet not supporting holes in terrain.

This commit is contained in:
Areloch 2016-12-20 00:05:30 -06:00
parent 54456fa4fa
commit e00bd847fd

View file

@ -28,6 +28,42 @@
#include "T3D/physics/bullet/bt.h"
#include "T3D/physics/bullet/btCasts.h"
class btHeightfieldTerrainShapeCustom : public btHeightfieldTerrainShape
{
bool* mHoles;
public:
btHeightfieldTerrainShapeCustom(const bool *holes,
int heightStickWidth,
int heightStickLength,
const void* heightfieldData,
btScalar heightScale,
btScalar minHeight,
btScalar maxHeight,
int upAxis,
PHY_ScalarType heightDataType,
bool flipQuadEdges) : btHeightfieldTerrainShape(heightStickWidth,
heightStickLength,
heightfieldData,
heightScale,
minHeight,
maxHeight,
upAxis,
heightDataType,
flipQuadEdges)
{
mHoles = new bool[heightStickWidth * heightStickLength];
dMemcpy(mHoles, holes, heightStickWidth * heightStickLength * sizeof(bool));
}
virtual ~btHeightfieldTerrainShapeCustom()
{
delete[] mHoles;
}
virtual void processAllTriangles(btTriangleCallback* callback, const btVector3& aabbMin, const btVector3& aabbMax) const;
};
BtCollision::BtCollision()
: mCompound( NULL ),
@ -170,13 +206,15 @@ bool BtCollision::addHeightfield( const U16 *heights,
const F32 minHeight = 0;
const F32 maxHeight = 65535 * heightScale;
btHeightfieldTerrainShape *shape = new btHeightfieldTerrainShape( blockSize, blockSize,
(void*)heights,
heightScale,
minHeight, maxHeight,
2, // Z up!
PHY_SHORT,
false );
btHeightfieldTerrainShapeCustom* shape = new btHeightfieldTerrainShapeCustom(holes,
blockSize, blockSize,
reinterpret_cast<const void*>(heights),
heightScale,
0, 0xFFFF * heightScale,
2, // Z up!
PHY_SHORT,
false);
shape->setMargin( 0.01f );
shape->setLocalScaling( btVector3( metersPerSample, metersPerSample, 1.0f ) );
shape->setUseDiamondSubdivision( true );
@ -203,3 +241,116 @@ bool BtCollision::addHeightfield( const U16 *heights,
return true;
}
void btHeightfieldTerrainShapeCustom::processAllTriangles(btTriangleCallback* callback, const btVector3& aabbMin, const btVector3& aabbMax) const
{
// scale down the input aabb's so they are in local (non-scaled) coordinates
btVector3 localAabbMin = aabbMin * btVector3(1.f / m_localScaling[0], 1.f / m_localScaling[1], 1.f / m_localScaling[2]);
btVector3 localAabbMax = aabbMax * btVector3(1.f / m_localScaling[0], 1.f / m_localScaling[1], 1.f / m_localScaling[2]);
// account for local origin
localAabbMin += m_localOrigin;
localAabbMax += m_localOrigin;
//quantize the aabbMin and aabbMax, and adjust the start/end ranges
int quantizedAabbMin[3];
int quantizedAabbMax[3];
quantizeWithClamp(quantizedAabbMin, localAabbMin, 0);
quantizeWithClamp(quantizedAabbMax, localAabbMax, 1);
// expand the min/max quantized values
// this is to catch the case where the input aabb falls between grid points!
for (int i = 0; i < 3; ++i) {
quantizedAabbMin[i]--;
quantizedAabbMax[i]++;
}
int startX = 0;
int endX = m_heightStickWidth - 1;
int startJ = 0;
int endJ = m_heightStickLength - 1;
switch (m_upAxis)
{
case 0:
{
if (quantizedAabbMin[1] > startX)
startX = quantizedAabbMin[1];
if (quantizedAabbMax[1] < endX)
endX = quantizedAabbMax[1];
if (quantizedAabbMin[2] > startJ)
startJ = quantizedAabbMin[2];
if (quantizedAabbMax[2] < endJ)
endJ = quantizedAabbMax[2];
break;
}
case 1:
{
if (quantizedAabbMin[0] > startX)
startX = quantizedAabbMin[0];
if (quantizedAabbMax[0] < endX)
endX = quantizedAabbMax[0];
if (quantizedAabbMin[2] > startJ)
startJ = quantizedAabbMin[2];
if (quantizedAabbMax[2] < endJ)
endJ = quantizedAabbMax[2];
break;
};
case 2:
{
if (quantizedAabbMin[0] > startX)
startX = quantizedAabbMin[0];
if (quantizedAabbMax[0] < endX)
endX = quantizedAabbMax[0];
if (quantizedAabbMin[1] > startJ)
startJ = quantizedAabbMin[1];
if (quantizedAabbMax[1] < endJ)
endJ = quantizedAabbMax[1];
break;
}
default:
{
//need to get valid m_upAxis
btAssert(0);
}
}
for (int j = startJ; j < endJ; j++)
{
for (int x = startX; x < endX; x++)
{
U32 index = (m_heightStickLength - (m_heightStickLength - x - 1)) + (j * m_heightStickWidth);
if (mHoles && mHoles[getMax((S32)index - 1, 0)])
continue;
btVector3 vertices[3];
if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j + x) & 1)) || (m_useZigzagSubdivision && !(j & 1)))
{
//first triangle
getVertex(x, j, vertices[0]);
getVertex(x, j + 1, vertices[1]);
getVertex(x + 1, j + 1, vertices[2]);
callback->processTriangle(vertices, x, j);
//second triangle
// getVertex(x,j,vertices[0]);//already got this vertex before, thanks to Danny Chapman
getVertex(x + 1, j + 1, vertices[1]);
getVertex(x + 1, j, vertices[2]);
callback->processTriangle(vertices, x, j);
}
else
{
//first triangle
getVertex(x, j, vertices[0]);
getVertex(x, j + 1, vertices[1]);
getVertex(x + 1, j, vertices[2]);
callback->processTriangle(vertices, x, j);
//second triangle
getVertex(x + 1, j, vertices[0]);
//getVertex(x,j+1,vertices[1]);
getVertex(x + 1, j + 1, vertices[2]);
callback->processTriangle(vertices, x, j);
}
}
}
}