Ogre Mesh to Havok

Anything and everything that's related to OGRE or the wider graphics field that doesn't fit into the other forums.
Post Reply
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Ogre Mesh to Havok

Post by Mind Calamity »

Hello! I'm trying to make a wrapper for Havok and OGRE, and all is well except the mesh conversion, how the heck do you convert stuff into Havok's shape form ?

I have this:

Code: Select all

		static hkpRigidBody* createTriangleMesh(hkpWorld* pWorld, Ogre::Mesh* mesh, const Vector3& scale)
		{
			hkpExtendedMeshShape* meshShape = new hkpExtendedMeshShape(0.0f);

			Vector3* vertices;
			size_t vertex_count,index_count;
			unsigned int* indices;
			getMeshInformation(mesh, vertex_count, vertices, index_count, indices);

			hkVector4* hkVertices;

			for (int j = 0; j < vertex_count; j+=1 )
			{
				hkVertices[j] = hkVector4(vertices[j].x, vertices[j].y, vertices[j].z, 0);
			}

			hkpExtendedMeshShape::TrianglesSubpart part;

			part.m_vertexBase = (float*)hkVertices;
			part.m_vertexStriding = sizeof(float);
			part.m_numVertices = vertex_count;

			part.m_indexBase = indices;
			part.m_indexStriding = sizeof(unsigned int);
			part.m_numTriangleShapes = index_count/3;
			part.m_stridingType = hkpExtendedMeshShape::INDICES_INT16;

			meshShape->addTrianglesSubpart(part);

			hkpMoppCompilerInput* cmi = new hkpMoppCompilerInput();
			hkpMoppCode* code = hkpMoppUtility::buildCode(meshShape, *cmi);

			hkpMoppBvTreeShape* moppBvShape = new hkpMoppBvTreeShape(meshShape, code);

			hkpRigidBodyCinfo info;

			info.m_shape = moppBvShape;
			info.m_motionType = hkpMotion::MOTION_FIXED;

			hkpRigidBody* r = new hkpRigidBody(info);

			pWorld->addEntity(r);

			return r;
		}
I converted the code from some Irrlicht binding as close as I could, but the resulting shape is:

Image

If anyone is using Havok and has some conversion code, I'd be grateful if they would be willing to share it.

Thanks in advance!

P.S: Thread on the Havok section on the Intel forums.
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
Guardian121
Gnoblar
Posts: 9
Joined: Sun Nov 29, 2009 1:24 am
x 1

Re: Ogre Mesh to Havok

Post by Guardian121 »

your vertex striding is wrong, it should be

Code: Select all

part.m_vertexStriding = sizeof(hkVector4);//sizeof(float)*4
i dont know for the index striding but you might want to look into that too if its still wrong

m_indexStriding:
/// The byte offset between two indices triples.
/// - Eg. (Usually sizeof(hkUint16) if you use triangle strips
/// - or 3 * sizeof(hkUint16) if you use independent triangles
User avatar
Wolfmanfx
OGRE Team Member
OGRE Team Member
Posts: 1525
Joined: Fri Feb 03, 2006 10:37 pm
Location: Austria - Leoben
x 99
Contact:

Re: Ogre Mesh to Havok

Post by Wolfmanfx »

Where did you allocate the memory for you vertices?

Code: Select all

hkVector4* hkVertices;  // <-- no alloc here --> = new hkVector4[n];
for (int j = 0; j < vertex_count; j+=1 )  
{  
    hkVertices[j] = hkVector4(vertices[j].x, vertices[j].y, vertices[j].z, 0);  
}  

And why do you use a vector 4 for position vector3 should be enough. (i just checked the first few lines)
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Ogre Mesh to Havok

Post by Mind Calamity »

Thanks, but that didn't seem to solve the problem, I'll check the index striding too.

BTW:

Code: Select all

					//
					//	Vertex information
					//
					/// A pointer to the first vertex, defined by three floats.
					/// Must be aligned on a 16 byte boundary
				const hkReal*  m_vertexBase; //+nosave
What would be the equivalent for that in OGRE ? Does this mean converting each vertex's vector into a set of 3 floats ? I'll try that too.
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Ogre Mesh to Havok

Post by Mind Calamity »

Update:

Well I tried the 3 float vector thing, and here are the results, they're kinda closer to what I need:

Image

Code: Select all

		static hkpRigidBody* createTriangleMesh(hkpWorld* pWorld, Ogre::Mesh* mesh, const Vector3& scale)
		{
			hkpExtendedMeshShape* meshShape = new hkpExtendedMeshShape(0.0f);

			Vector3* vertices;
			size_t vertex_count,index_count;
			unsigned int* indices;
			getMeshInformation(mesh, vertex_count, vertices, index_count, indices);

			hkVector4* hkVertices;
			hkReal* vertexBuffer;
			int tmpCounter = 0;
			for (int j = 0; j < vertex_count; j+=1 )
			{
				vertexBuffer[tmpCounter]	= vertices[j].x * scale.x;
				vertexBuffer[tmpCounter+1]	= vertices[j].y * scale.y;
				vertexBuffer[tmpCounter+2]	= vertices[j].z * scale.z;

				tmpCounter += 3;
			}

			for (int i = 0; i < index_count; i++)
			{
				//indices[i] = i;
				std::cout << indices[i] << "\n";
			}
			hkpExtendedMeshShape::TrianglesSubpart part;

			part.m_vertexBase = vertexBuffer;
			part.m_vertexStriding = sizeof(float) * 3;
			part.m_numVertices = vertex_count;

			part.m_indexBase = indices;
			part.m_indexStriding = sizeof(unsigned int);
			part.m_numTriangleShapes = index_count;
			part.m_stridingType = hkpExtendedMeshShape::INDICES_INT16;

			meshShape->addTrianglesSubpart(part);

			hkpMoppCompilerInput* cmi = new hkpMoppCompilerInput();
			hkpMoppCode* code = hkpMoppUtility::buildCode(meshShape, *cmi);

			hkpMoppBvTreeShape* moppBvShape = new hkpMoppBvTreeShape(meshShape, code);

			hkpRigidBodyCinfo info;

			info.m_shape = moppBvShape;
			info.m_motionType = hkpMotion::MOTION_FIXED;

			hkpRigidBody* r = new hkpRigidBody(info);

			pWorld->addEntity(r);

			return r;
		}
^^^ Updated Code ^^^

Now the indices seem to be a problem... I have no idea how to order them or fix the code at

-------------------------------------------------------

Here's the original Irrlicht source, if anyone can convert it to OGRE more properly than me:

Code: Select all

hkpRigidBody* createTriangleMesh(hkpWorld* pWorld, irr::scene::IMesh* mesh, irr::core::vector3df scale)
{
	hkpExtendedMeshShape* meshShape = new hkpExtendedMeshShape(0.0f);

	for (irr::u32 i = 0; i < mesh->getMeshBufferCount(); i++)
	{
		irr::scene::IMeshBuffer* mb = mesh->getMeshBuffer(i);

		irr::video::S3DVertex2TCoords* vertices = (irr::video::S3DVertex2TCoords*)mb->getVertices();

		irr::f32* vertexBuffer = new irr::f32[mb->getVertexCount() * 3];
		irr::u16* indexBuffer = mb->getIndices();

		int tmpCounter = 0;

		for (irr::u32 x = 0; x < mb->getVertexCount(); x++)
		{
			vertexBuffer[tmpCounter] = vertices[x].Pos.X * scale.X;
			vertexBuffer[tmpCounter+1] = vertices[x].Pos.Y * scale.Y;
			vertexBuffer[tmpCounter+2] = vertices[x].Pos.Z * scale.Z;

			tmpCounter += 3;
		}

		hkpExtendedMeshShape::TrianglesSubpart part;

		part.m_vertexBase = vertexBuffer;
		part.m_vertexStriding = sizeof(float) * 3;
		part.m_numVertices = mb->getVertexCount();

		part.m_indexBase = indexBuffer;
		part.m_indexStriding = sizeof(unsigned short)*3;
		part.m_numTriangleShapes = mb->getIndexCount()/3;
		part.m_stridingType = hkpExtendedMeshShape::INDICES_INT16;

		meshShape->addTrianglesSubpart(part);
	}

	hkpMoppCompilerInput* cmi = new hkpMoppCompilerInput();
	hkpMoppCode* code = hkpMoppUtility::buildCode(meshShape, *cmi);

	hkpMoppBvTreeShape* moppBvShape = new hkpMoppBvTreeShape(meshShape, code);

	hkpRigidBodyCinfo info;

	info.m_shape = moppBvShape;
	info.m_motionType = hkpMotion::MOTION_FIXED;

	hkpRigidBody* r = new hkpRigidBody(info);

	pWorld->addEntity(r);

	return r;
}
Wolfmanfx wrote:Where did you allocate the memory for you vertices?

Code: Select all

hkVector4* hkVertices;  // <-- no alloc here --> = new hkVector4[n];
for (int j = 0; j < vertex_count; j+=1 )  
{  
    hkVertices[j] = hkVector4(vertices[j].x, vertices[j].y, vertices[j].z, 0);  
}  

And why do you use a vector 4 for position vector3 should be enough. (i just checked the first few lines)
Because Havok doesn't have a Vector3 data type, the 4th value is optional - defaults to 0, and for some reason I copied the wrong code.
I changed the code to the one above, so it doesn't matter.
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
Guardian121
Gnoblar
Posts: 9
Joined: Sun Nov 29, 2009 1:24 am
x 1

Re: Ogre Mesh to Havok

Post by Guardian121 »

Have you tried to use what you get from getMeshInformation?

Code: Select all

        part.m_vertexBase = (Ogre::Real*)vertices;  //Vector3* vertices
        part.m_vertexStriding = sizeof(Ogre::Vector3);
        part.m_numVertices = vertex_count;

        part.m_indexBase = indices;  //unsigned int* indices
        part.m_indexStriding =  sizeof( unsigned int )*3; //maybe unsigned short? also, *3 for non triangle strips
        part.m_numTriangleShapes = index_count/3;

        part.m_stridingType = hkpExtendedMeshShape::INDICES_INT32;//if you get short from getMeshInformation use INDICES_INT16
Im not sure what can cause your problems, might be the mix of INDICES_INT16 and unsigned int in the m_indexStriding or maybe the model isn't triangles strip and you are missing the *3
m_indexStriding:
/// The byte offset between two indices triples.
/// - Eg. (Usually sizeof(hkUint16) if you use triangle strips
/// - or 3 * sizeof(hkUint16) if you use independent triangles
User avatar
KungFooMasta
OGRE Contributor
OGRE Contributor
Posts: 2087
Joined: Thu Mar 03, 2005 7:11 am
Location: WA, USA
x 16
Contact:

Re: Ogre Mesh to Havok

Post by KungFooMasta »

Here is what I did a long time ago. I'm going on vacation soon so it may not be very well organized.

Steps:
1. Get mesh data - vertices and indices:

Code: Select all

void _getMeshInformation(Ogre::Entity* entity, size_t& vertex_count, Ogre::Vector3* &vertices, size_t& index_count, unsigned long* &indices, const Ogre::Vector3& position, const Ogre::Quaternion& orient, const Ogre::Vector3& scale)
{
	bool added_shared = false;
	size_t current_offset = 0;
	size_t shared_offset = 0;
	size_t next_offset = 0;
	size_t index_offset = 0;
	vertex_count = index_count = 0;

	Ogre::MeshPtr mesh = entity->getMesh();

	bool useSoftwareBlendingVertices = entity->hasSkeleton();

	if (useSoftwareBlendingVertices)
		entity->_updateAnimation();

	// Calculate how many vertices and indices we're going to need
	for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
	{
		Ogre::SubMesh* submesh = mesh->getSubMesh( i );

		// We only need to add the shared vertices once
		if(submesh->useSharedVertices)
		{
			if( !added_shared )
			{
				vertex_count += mesh->sharedVertexData->vertexCount;
				added_shared = true;
			}
		}
		else
			vertex_count += submesh->vertexData->vertexCount;

		// Add the indices
		index_count += submesh->indexData->indexCount;
	}

	// Allocate space for the vertices and indices
	vertices = new Ogre::Vector3[vertex_count];
	indices = new unsigned long[index_count];

	added_shared = false;

	// Run through the submeshes again, adding the data into the arrays
	for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
	{
		Ogre::SubMesh* submesh = mesh->getSubMesh(i);

	  //----------------------------------------------------------------
	  // GET VERTEXDATA
	  //----------------------------------------------------------------

		//Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
	  Ogre::VertexData* vertex_data;

	  //When there is animation:
	  if(useSoftwareBlendingVertices)
		 vertex_data = submesh->useSharedVertices ? entity->_getSkelAnimVertexData() : entity->getSubEntity(i)->_getSkelAnimVertexData();
	  else
		 vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;

		if((!submesh->useSharedVertices) || (submesh->useSharedVertices && !added_shared))
		{
			if(submesh->useSharedVertices)
			{
				added_shared = true;
				shared_offset = current_offset;
			}

			const Ogre::VertexElement* posElem =
				vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);

			Ogre::HardwareVertexBufferSharedPtr vbuf =
				vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());

			unsigned char* vertex =
				static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));

			// There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
			//  as second argument. So make it float, to avoid trouble when Ogre::Real will
			//  be comiled/typedefed as double:
			//      Ogre::Real* pReal;
			float* pReal;

			for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
			{
				posElem->baseVertexPointerToElement(vertex, &pReal);

				Ogre::Vector3 pt(pReal[0], pReal[1], pReal[2]);

				vertices[current_offset + j] = (orient * (pt * scale)) + position;
			}

			vbuf->unlock();
			next_offset += vertex_data->vertexCount;
		}

		Ogre::IndexData* index_data = submesh->indexData;
		size_t numTris = index_data->indexCount / 3;
		Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;

		bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);

		unsigned long*  pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
		unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong);

		size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset;

		if ( use32bitindexes )
		{
			for ( size_t k = 0; k < numTris*3; ++k)
			{
				indices[index_offset++] = pLong[k] + static_cast<unsigned long>(offset);
			}
		}
		else
		{
			for ( size_t k = 0; k < numTris*3; ++k)
			{
				indices[index_offset++] = static_cast<unsigned long>(pShort[k]) +
					static_cast<unsigned long>(offset);
			}
		}

		ibuf->unlock();
		current_offset = next_offset;
	}
}
2. Create hkpExtendedMeshShape

Code: Select all

			// Create Extended Mesh Shape
			hkpExtendedMeshShape* shape = new hkpExtendedMeshShape();
			mShape = shape;
			{
				hkpExtendedMeshShape::TrianglesSubpart part;
				part.m_numTriangleShapes	= mNumIndices;
				part.m_numVertices			= mNumVertices;
				part.m_vertexBase			= mVertices;
				part.m_stridingType			= hkpExtendedMeshShape::INDICES_INT32;
				part.m_vertexStriding		= sizeof(float) * 3;
				part.m_indexBase			= mIndices;
				part.m_indexStriding		= sizeof(unsigned long) * 3;
				part.m_numTriangleShapes	= mNumIndices/3;

				shape->addTrianglesSubpart( part );
			}
Creator of QuickGUI!
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Ogre Mesh to Havok

Post by Mind Calamity »

OK, progress, now at least Havok is spouting some info:

Code: Select all

Collide\Mopp\Builder\Splitter\hkpMoppDefaultSplitter.cpp(773): [0xABBA2344] Warning : Could not find splitting plane for child
I also tried using Irrlicht and it's data (with intent to serialize it later), but that seems to result in this exact same thing - the error message above.

Any ideas ?

I searched but, amazingly Google doesn't give any results related to Havok (or in any way remotely related to programming in general) at all.

Thank you very much KungFooMasta, that really helps.

I'm going to strugle for a little while more, before I actually switch back to Bullet because of the lack of time...
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Ogre Mesh to Havok

Post by dark_sylinc »

For god sake.

Here's working code (may not compile as I just copy pasted as is, but it will work):

Code: Select all

std::vector<std::vector<float>>				*verticesOut;
std::vector<std::vector<unsigned short>>	*indicesOut;
MeshPtr mesh = MeshManager::getSingleton().load( "MyMeshName",
												ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );

Mesh::SubMeshIterator subMeshIt = mesh->getSubMeshIterator();
while( subMeshIt.hasMoreElements() )
{
	SubMesh *subMesh = subMeshIt.getNext();

	//Reserve enough memory for our vertex buffer
	verticesOut->push_back( std::vector<float>() );
	std::vector<float> &vertices = verticesOut->back();
	vertices.reserve( subMesh->vertexData->vertexCount * 3 );

	//Copy vertices
	const VertexElement *vertElement = subMesh->vertexData->vertexDeclaration->
													findElementBySemantic( VES_POSITION );
	const size_t vertexSize =
				subMesh->vertexData->vertexDeclaration->getVertexSize(vertElement->getSource());
	const HardwareVertexBufferSharedPtr &vertexBuf = subMesh->vertexData->vertexBufferBinding->
															getBuffer( vertElement->getSource() );

	unsigned char const *pBuffer = static_cast<unsigned char*>
										(vertexBuf->lock( HardwareBuffer::HBL_READ_ONLY ));
	for( size_t i=0; i<subMesh->vertexData->vertexCount; ++i )
	{
		float const *pPos = reinterpret_cast<float const*>(pBuffer + vertElement->getOffset());
		vertices.push_back( *pPos++ );
		vertices.push_back( *pPos++ );
		vertices.push_back( *pPos++ );
		pBuffer += vertexSize;
	}

	vertexBuf->unlock();

	//Reserve enough memory for our index buffer
	indicesOut->push_back( std::vector<unsigned short>() );
	std::vector<unsigned short> &indices = indicesOut->back();
	indices.reserve( subMesh->indexData->indexCount );

	//Copy indices
	const HardwareIndexBufferSharedPtr indexBuffer = subMesh->indexData->indexBuffer;
	unsigned short const *pIndices = static_cast<unsigned short*>
											(indexBuffer->lock( HardwareBuffer::HBL_READ_ONLY ));
	for( size_t i=0; i<subMesh->indexData->indexCount; ++i )
		indices.push_back( *pIndices++ );

	indexBuffer->unlock();
}

hkpExtendedMeshShape *meshShape = new hkpExtendedMeshShape();

for( size_t i=0; i<verticesOut.size(); ++i )
{
	hkpExtendedMeshShape::TrianglesSubpart part;
	part.m_vertexBase		= &verticesOut[i][0];
	part.m_vertexStriding	= sizeof( float ) * 3;
	part.m_numVertices		= verticesOut[i].size() / 3;

	part.m_indexBase		= &indicesOut[i][0];
	part.m_indexStriding	= sizeof( unsigned short ) * 3;
	part.m_numTriangleShapes= indicesOut[i].size() / 3;
	part.m_stridingType		= hkpExtendedMeshShape::INDICES_INT16;

	meshShape->addTrianglesSubpart( part );
}

hkpMoppCode* moppCode = hkpMoppUtility::buildCode( meshShape, hkpMoppCompilerInput() );

hkpMoppBvTreeShape *retVal = new hkpMoppBvTreeShape( meshShape, moppCode );
hkpMeshWeldingUtility::computeWeldingInfo( meshShape, retVal,
											hkpWeldingUtility::WELDING_TYPE_ANTICLOCKWISE );
moppCode->removeReference();
meshShape->removeReference();
It creates a MOPP based on the mesh (stored in retVal). Each Ogre submesh becomes a Havok "subpart"
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Ogre Mesh to Havok

Post by Mind Calamity »

Whoa, after almost a month, well for now I gave up on Havok Physics for my current project, but I definitely want to use it in the next, I'm going to try your code, and report back.

Thanks a lot!
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
Post Reply