Can I make btTriangleMeshShape from btHeightfieldTerrainShape?

Post Reply
kcjsend2
Posts: 15
Joined: Wed Jun 30, 2021 9:10 am

Can I make btTriangleMeshShape from btHeightfieldTerrainShape?

Post by kcjsend2 »

continues from this question : viewtopic.php?f=9&t=13374

hi.

I know these questions may seem a little short technically, but I don't know how to proceed, so I'm asking you this question.

We 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, so I don't know how to create a mesh in the Bullet.

Is there a simple way to change btTerrainHeightfieldShape to btBvhTriangleMeshShape? If there's no such way, how should I process my data?
Last edited by kcjsend2 on Sun Feb 20, 2022 7:34 am, edited 1 time in total.
kcjsend2
Posts: 15
Joined: Wed Jun 30, 2021 9:10 am

Re: Can I make btTrangleMeshShape from btHeightfieldTerrainShape?

Post by kcjsend2 »

I found it. threre's Demo named HeightFieldExample.

it collects all vertices and indices by TriangleCallback and processAllTriangles.

there's three more questions.

first, Why does the vertexBase of the getLockedVertexIndexBase function receive double pointers? The vertex information I have is in the form of btAlignedObjectArray<XMFLOAT3>, but I don't know how to pass it over to work well.

second, Unlike vector, btAlignedObjectArray does not have a data() function, so how do I get the location of the actual data?

third, actually in HeightFieldExample, btTriangleCallback collects indices by this code :

Code: Select all

m_pIndicesOut->push_back(m_pVerticesOut->size());
is this correct data? I can't sure this data fits to btTriangleIndexVertexArray object.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Can I make btTrangleMeshShape from btHeightfieldTerrainShape?

Post by drleviathan »

Why does the vertexBase of the getLockedVertexIndexBase function receive double pointers?
The actual declaration for that API looks like this:

Code: Select all

void getLockedVertexIndexBase(
    unsigned char** vertexbase,
    int& numverts,
    PHY_ScalarType& type,
    int& stride, unsigned char** indexbase,
    int& indexstride,
    int& numfaces,
    PHY_ScalarType& indicestype,
    int subpart = 0)
The API is: btStridingMeshInterface will cast a pointer to its own data to unsigned char* then set the supplied vertexbase to it, and also set type accordingly. All this so the receiving side can have the vertexbase pointer and cast back accordingly.
Unlike vector, btAlignedObjectArray does not have a data() function, so how do I get the location of the actual data?
There is btAlignedObjectArray::at(int n) (both const and non-const varieties) which returns the data by reference. You could probably snag the pointers from the references.
is this correct data?

Code: Select all

m_pIndicesOut->push_back(m_pVerticesOut->size());
AFAICT the code is building its own triangle data which is a list of vertices (MyTriangleCollector3::m_pVerticesOut) and indices into that array of vertices (MyTriangleCollector3::m_pIndicesOut). So the index to the about-to-be-created vertex is the size of the array right before the vertex is added. It looks correct to me.
kcjsend2
Posts: 15
Joined: Wed Jun 30, 2021 9:10 am

Re: Can I make btTrangleMeshShape from btHeightfieldTerrainShape?

Post by kcjsend2 »

Thanks for the answer!

I found this post : viewtopic.php?p=38852&hilit=btTriangleI ... ray#p38852

so I modify that codes like this :

Code: Select all

	class btTriangleCollector : public btTriangleCallback
	{
	public:
		std::vector<XMFLOAT3>* m_pVerticesOut;
		std::vector<unsigned short>* m_pIndicesOut;

		btTriangleCollector()
		{
			m_pVerticesOut = NULL;
			m_pIndicesOut = NULL;
		}

		virtual void processTriangle(btVector3* tris, int partId, int triangleIndex)
		{
			for (int k = 0; k < 3; k++)
			{
				btVector3 v;
				for (int l = 0; l < 3; l++)
				{
					v[l] = tris[k][l];
				}
				m_pIndicesOut->push_back(m_pVerticesOut->size());
	
				XMFLOAT3 vertex(v[0], v[1], v[2]);

				m_pVerticesOut->push_back(vertex);
			}
		}
	};


	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);

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.
Post Reply