Using btIndexedMesh with btTriangleIndexVertexArray+btBvhTriangleMeshShape

User avatar
goosesensor
Posts: 15
Joined: Tue Jul 17, 2018 3:50 am
Location: Santa Cruz, CA

Using btIndexedMesh with btTriangleIndexVertexArray+btBvhTriangleMeshShape

Post by goosesensor »

I am trying to create static physics bodies using btBvhTriangleMeshShape.

This works fine if I copy vertex data into btTriangleMesh, and use that to create a btBvhTriangleMeshShape. However, copying is obviously not desirable.

The approach I am currently trying is:
  1. Describe vertex layout using btIndexedMesh referencing existing visual data
  2. Create btTriangleIndexVertexArray using btIndexedMesh
  3. Create btBvhTriangleMeshShape using btTriangleIndexVertexArray
My Face and Vertex structures:

Code: Select all

	typedef struct {
		int a;
		int b;
		int c;
	} Face;

	typedef struct {
		glm::vec3 position;
		glm::vec3 normal;
		glm::vec2 textureCoordinate;
	} Vertex;
In my mesh class ("GeometryElement"):

Code: Select all

	const std::vector<Vertex>& 			vertices() const;
	const std::vector<Face>&			faces() const;
Code for creating the btIndexedMesh + btTriangleIndexVertexArray + btBvhTriangleMeshShape:

Code: Select all

	auto triangleIndexVertexArray = btTriangleIndexVertexArray();
	for (auto& element : geometry->elements()) {
		auto verts = element->vertices();
		auto faces = element->faces();

		auto indexedMesh = btIndexedMesh();

		indexedMesh.m_numTriangles = (int)faces.size();
		indexedMesh.m_triangleIndexBase = (const unsigned char *)&faces[0];
		indexedMesh.m_triangleIndexStride = sizeof(Face); // sizeof(Face), sizeof(int)?
		indexedMesh.m_indexType = PHY_INTEGER;
		indexedMesh.m_numVertices = (int)verts.size();
		indexedMesh.m_vertexBase = (const unsigned char *)&verts[0];
		indexedMesh.m_vertexStride = sizeof(Vertex); // sizeof(Vertex), sizeof(glm::vec3)?
		indexedMesh.m_vertexType = PHY_FLOAT;

		triangleIndexVertexArray.addIndexedMesh(indexedMesh);
	}

	auto shape = btBvhTriangleMeshShape(&triangleIndexVertexArray, true);
I am getting a segfault in btStridingMeshInterface::InternalProcessAllTriangles() when initializing the btBvhTriangleMeshShape. From the debugger gfxindextype is PHY_INTEGER, which leads me to believe it's getting hung up processing the vertex faces array.

Can anybody shed some light on this? Am I using btIndexedMesh incorrectly? Much thanks.
User avatar
goosesensor
Posts: 15
Joined: Tue Jul 17, 2018 3:50 am
Location: Santa Cruz, CA

Re: Using btIndexedMesh with btTriangleIndexVertexArray+btBvhTriangleMeshShape

Post by goosesensor »

Here is what I have found.

Recall my face/triangle and vertex data are declared in the GeometryElement class interface as:

Code: Select all

		std::vector<Vertex>					_vertices;
		std::vector<Face>					_faces;

		const std::vector<Vertex>& 			vertices() const;
		const std::vector<Face>&			faces() const;
I find that if I reference the base array addresses in either of these ways, it works:

Code: Select all

		auto vertsBase = element->vertices().data();
			auto facesBase = element->faces().data();
			
			// - OR --

			auto vertsBase = &element->vertices()[0];
			auto facesBase = &element->faces()[0];
			
			auto indexedMesh = make_shared<btIndexedMesh>();
			indexedMesh->m_numTriangles = (int)element->faces().size();
			indexedMesh->m_triangleIndexBase = (const unsigned char *)facesBase;
			indexedMesh->m_triangleIndexStride = sizeof(Face);
			indexedMesh->m_numVertices = (int)element->vertices().size();
			indexedMesh->m_vertexBase = (const unsigned char *)vertsBase;
			indexedMesh->m_vertexStride = sizeof(Vertex);
			indexedMesh->m_vertexType = PHY_FLOAT;
			
Yet if I reference them like this, the vector contents appears to be copied and disappears off the stack once scope of the iteration is lost, causing btBvhTriangleMeshShape's constructor to fail.

Code: Select all

		auto verts = element->vertices();
			auto faces = element->faces();
			auto vertsBase = verts.data();
			auto facesBase = faces.data();
Sorry to turn this topic into my own personal C++ tutoring session, but clearly there is something about C++ references I am not understanding. Can someone point out what is going on?
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Using btIndexedMesh with btTriangleIndexVertexArray+btBvhTriangleMeshShape

Post by drleviathan »

The following code makes verts a copy of the data:

Code: Select all

auto verts = element->vertices();
and is equivalent to:

Code: Select all

std::vector<Vertex> verts = elements->vertices();
Note, the vertices() method is declared const (it does not modify the class instance's data members) which is why it returns a const reference, and since the local variable being assigned is not a const reference... a copy happens. And you would be able to modify the contents of verts without offending the compiler.

This will make verts a const reference to the data:

Code: Select all

const auto& verts = elements->vertices();
and is equivalent to:

Code: Select all

const std::vector<Vertex>& verts = elements->vertices();
Under the hood verts is effectively a pointer, but the syntactic sugar of the "const reference" feature of C++ obscures that fact.
User avatar
goosesensor
Posts: 15
Joined: Tue Jul 17, 2018 3:50 am
Location: Santa Cruz, CA

Re: Using btIndexedMesh with btTriangleIndexVertexArray+btBvhTriangleMeshShape

Post by goosesensor »

Thank you!

That makes sense... sneaky. This language is no nuanced.