[ODE] Re: Problems w/ tri-collider and ODE 0.035

Nate W coding at natew.com
Thu Jan 2 12:08:01 2003


On Thu, 2 Jan 2003, Chris Klein wrote:

> > > Also, if someone already has gotten ODE, tri-collider, OPCODE,
> > > Demeter, and OpenSceneGraph to play nice with each other, I would
> > > greatly appreciate seeing your source code.
> 
> (Paul, I also have some code which may help you get your combination of
> libs working.  I was using OSG and Demeter for a while though I am not
> anymore.  I expect you're trying to feed the demeter terrain into the
> tricollider - unless demeter's changed in the last few months you can't
> actually get enough data from demeter to get vertex and polygon
> information from it!  I had to hack demeter to give me access to the
> vertex data and tesselate it myself to give tricollider the tri's it
> wants. Email me separately and I'll see what I can dig up over the next
> few days.)

Sorry I'm late to this thread, but I got the ODE+TC+OPCODE+Demeter
combination to work together.  The code to convert data from Demeter to
tri-collider follows...

The main thing I had to do to get ODE and Demeter to work together was to
build vertex and triangle arrays using Demeter's heightmap.  Once I got
that taken care of, it basically "just worked."  

The conversion is done in two steps because Juice supports multiple
physics libraries.  First, I build the vertex and triangle arrays in a
simple physics-independent format, then I convert that data into the
format that ODE requires.  The first step is the interesting part, and it
takes place in a Terrain class that is basically just a wrapper for
Demeter:

void Terrain::vBuildArrays ()
{
	if (!m_pTerrain)
	{
		GenericUnexpected ("terrain disabled");
		return;
	}

	// m_pTerrain is a pointer to a Demeter::Terrain object
	const Demeter::Vector *pTerrainVertexArray = m_pTerrain->m_pVertices;

	if (!pTerrainVertexArray)
	{
		GenericUnexpected ("terrain disabled");
		return;
	}

	int iMaxX = 0, iMaxY = 0;

	// wrapper for Demeter::Terrain::GetWidth and GetHeight
	vGetDimensions (iMaxX, iMaxY);

	m_iVertexCount = iMaxX * iMaxY;
	m_iTriangleCount = (iMaxX - 1) * (iMaxY - 1) * 2;

	delete m_pVertexArray;
	delete m_pTriangleArray;

	// class Terrain::Vertex
	// {
	//	float x, y, z; // a trivial vector class
	// };
	m_pVertexArray = new Terrain::Vertex[m_iVertexCount];


	// class Terrain::Triangle
	// {
	//	int v1, v2, v3; // indices into a one-dimensional vertex array
	// };
	m_pTriangleArray = new Terrain::Triangle[m_iTriangleCount];

	for (int iVertex = 0; iVertex < m_iVertexCount; iVertex++)
	{
		m_pVertexArray[iVertex].x =
			pTerrainVertexArray[iVertex].x;
		m_pVertexArray[iVertex].y =
			pTerrainVertexArray[iVertex].y;
		m_pVertexArray[iVertex].z =
			pTerrainVertexArray[iVertex].z;
	}

	int iTriangle = 0;
	int iIndex = 0;

	for (int iY= 0; iY < iMaxY - 1; iY++)
	{
		for (int iX = 0; iX < iMaxX - 1; iX++)	
		{
			iTriangle = (iY * (iMaxY - 1) * 2) + (iX * 2);

			iIndex = (iY * iMaxX) + iX;
			m_pTriangleArray[iTriangle].v1 = iIndex;

			iIndex = (iY * iMaxX) + iX + 1;
			m_pTriangleArray[iTriangle].v2 = iIndex;
			
			iIndex = (iY * iMaxX) + iX + 1 + iMaxX;
			m_pTriangleArray[iTriangle].v3 = iIndex;

			iTriangle++;

			iIndex = (iY * iMaxX) + iX;
			m_pTriangleArray[iTriangle].v1 = iIndex;
			
			iIndex = ((iY * iMaxX) + iX) + 1 + iMaxX;
			m_pTriangleArray[iTriangle].v2 = iIndex;
			
			iIndex = ((iY * iMaxX) + iX) + iMaxX;
			m_pTriangleArray[iTriangle].v3 = iIndex;
		}
	}
}

Conversion to the ODE data structures is trivial:

void World::vCreateTerrain (Terrain *pTerrain)
{
	if (!pTerrain)
		return;

	Terrain::Vertex *pVertices = null;
	Terrain::Triangle *pTriangles = null;

	int iVertexCount = 0;
	int iTriangleCount = 0;

	// get vertex data from the terrain wrapper
	// vGetTriangles gets the data generated by Terrain::vBuildArrays
	pTerrain->vGetTriangles (&pVertices, &iVertexCount, &pTriangles, &iTriangleCount);

	if (!(pVertices && pTriangles))
		return;

	// convert vertex data to ODE's preferred format
	m_pVertices = new dcVector3[iVertexCount];

	for (int i = 0; i < iVertexCount; i++)
	{
		m_pVertices[i].x = (float) pVertices[i].x;
		m_pVertices[i].y = (float) pVertices[i].y;
		m_pVertices[i].z = (float) pVertices[i].z;
	}

	// create ODE's collision detection mesh object
	m_Terrain = dCreateTriList (m_SpaceID, null, null);

	// initialize the mesh with the vertex and triangle 
	// information taken from the terrain wrapper
	dGeomTriListBuild(m_Terrain, m_pVertices, iVertexCount, &(pTriangles->v1), iTriangleCount * 3);
}

--

Also, I talked a bit with Clay Fowler, the guy who made Demeter.  He said
that he was working on an ODE-Demeter collision detection system of his
own, not using tri-collider, so you might want to ask him about that.  
Tri-collider is for arbitrary meshes, so there are probably some
optimizations possible when using height-map meshes - including a way to
address the "infinitely thin" problem that came up a while ago.  If you
know you're dealing with a heightmap, then you should be able to compute
penetration depth somewhat more usefully than what tri-collider provides,
since, being a general-purpose mesh collider, it treats everything as a
thin mesh.

--

Nate Waddoups
Redmond WA USA
http://www.natew.com