'Bullet Physics - How can I convert btHeightfieldTerrainShape to btTriangleMeshShape?

I found that btStridingMeshInterface is required to create btBvhTriangleMeshShape.

But all I have is as much data as (Width * Height) for btTerrainHeightfieldShape. There is no index information on the data.

Then, I found this post on Forum : https://pybullet.org/Bullet/phpBB3/viewtopic.php?p=38852&hilit=btTriangleIndexVertexArray#p38852

so I modify that codes like this :

auto TerrainShape = new btHeightfieldTerrainShape(mWidth * mTerrainScale.x, mDepth * mTerrainScale.z, mHeightmapData, minHeight, maxHeight, 1, false);
TerrainShape->setLocalScaling(btVector3(1, mTerrainScale.y, 1));

btVector3 aabbMin, aabbMax;
for (int k = 0; k < 3; k++)
{
    aabbMin[k] = -BT_LARGE_FLOAT;
    aabbMax[k] = BT_LARGE_FLOAT;
}

std::vector<XMFLOAT3> vertices;
std::vector<unsigned short> Targetindices;

btTriangleCollector collector;
collector.m_pVerticesOut = &vertices;
collector.m_pIndicesOut = &Targetindices;

TerrainShape->processAllTriangles(&collector, aabbMin, aabbMax);

mVertexArray = std::make_shared<btTriangleIndexVertexArray>();

btIndexedMesh tempMesh;
mVertexArray->addIndexedMesh(tempMesh, PHY_FLOAT);

btIndexedMesh& mesh = mVertexArray->getIndexedMeshArray()[0];

const int32_t VERTICES_PER_TRIANGLE = 3;
size_t numIndices = Targetindices.size();
mesh.m_numTriangles = numIndices / VERTICES_PER_TRIANGLE;

if (numIndices < std::numeric_limits<int16_t>::max())
{
    mesh.m_triangleIndexBase = new unsigned char[sizeof(int16_t) * (size_t)numIndices];
    mesh.m_indexType = PHY_SHORT;
    mesh.m_triangleIndexStride = VERTICES_PER_TRIANGLE * sizeof(int16_t);
}
else
{
    mesh.m_triangleIndexBase = new unsigned char[sizeof(int32_t) * (size_t)numIndices];
    mesh.m_indexType = PHY_INTEGER;
    mesh.m_triangleIndexStride = VERTICES_PER_TRIANGLE * sizeof(int32_t);
}
mesh.m_numVertices = vertices.size();
mesh.m_vertexBase = new unsigned char[VERTICES_PER_TRIANGLE * sizeof(btScalar) * (size_t)mesh.m_numVertices];
mesh.m_vertexStride = VERTICES_PER_TRIANGLE * sizeof(btScalar);

btScalar* vertexData = static_cast<btScalar*>((void*)(mesh.m_vertexBase));

for (int32_t i = 0; i < mesh.m_numVertices; ++i)
{
    int32_t j = i * VERTICES_PER_TRIANGLE;
    const XMFLOAT3& point = vertices[i];
    vertexData[j] = point.x;
    vertexData[j + 1] = point.y;
    vertexData[j + 2] = point.z;
}

if (numIndices < std::numeric_limits<int16_t>::max())
{
    int16_t* indices = static_cast<int16_t*>((void*)(mesh.m_triangleIndexBase));
    for (int32_t i = 0; i < numIndices; ++i) {
        indices[i] = (int16_t)Targetindices[i];
    }
}
else
{
    int32_t* indices = static_cast<int32_t*>((void*)(mesh.m_triangleIndexBase));
    for (int32_t i = 0; i < numIndices; ++i) {
        indices[i] = Targetindices[i];
    }
}

btBvhTriangleMeshShape* shape = new btBvhTriangleMeshShape(mVertexArray.get(), true);


btTransform btTerrainTransform;
btTerrainTransform.setIdentity();
btTerrainTransform.setOrigin(btVector3(0, 0, 0));

mBtRigidBody = physics->CreateRigidBody(0.0f, btTerrainTransform, shape);

What I try to do is simple. make btHeightfieldTerrainShape, and collect all triangle data by TriangleCallback(collector) and make btTriangleIndexVertexArray by that data sets.

problem is data that I collected seems wrong.

if this codes works well, mBtRigdBody's AABB must be min(-511.5, 4, -511.5), max(511.5, 242, 511.5), but, actually what i got is min(-511.5, -105.389..., -511.5), max(511.5, 25.8... ,-500.5)

definitely wrong values.

I think btTriangleIndexVertexArray doesn't have right data of terrain, but I can't find where's wrong.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source