From e00bd847fda52705a2c0e09ac01899ba0b7d2c5b Mon Sep 17 00:00:00 2001 From: Areloch Date: Tue, 20 Dec 2016 00:05:30 -0600 Subject: [PATCH] Fixes Bullet not supporting holes in terrain. --- .../source/T3D/physics/bullet/btCollision.cpp | 165 +++++++++++++++++- 1 file changed, 158 insertions(+), 7 deletions(-) diff --git a/Engine/source/T3D/physics/bullet/btCollision.cpp b/Engine/source/T3D/physics/bullet/btCollision.cpp index d81bd2c5b..477c1b261 100644 --- a/Engine/source/T3D/physics/bullet/btCollision.cpp +++ b/Engine/source/T3D/physics/bullet/btCollision.cpp @@ -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(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); + } + } + } +} \ No newline at end of file