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.

Ogre Mesh to Havok

Postby Mind Calamity » Sat Feb 04, 2012 12:58 am

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.
User avatar
Mind Calamity
Ogre Magi
 
Posts: 1207
Kudos: 78
Joined: 25 Dec 2010
Location: Macedonia

Re: Ogre Mesh to Havok

Postby Guardian121 » Sat Feb 04, 2012 7:57 pm

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
Guardian121
Gnoblar
 
Posts: 7
Kudos: 0
Joined: 29 Nov 2009

Re: Ogre Mesh to Havok

Postby Wolfmanfx » Sat Feb 04, 2012 9:01 pm

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
Wolfmanfx
OGRE Team Member
OGRE Team Member
 
Posts: 1439
Kudos: 100
Joined: 03 Feb 2006
Location: Austria - Leoben

Re: Ogre Mesh to Havok

Postby Mind Calamity » Sat Feb 04, 2012 9:09 pm

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.
User avatar
Mind Calamity
Ogre Magi
 
Posts: 1207
Kudos: 78
Joined: 25 Dec 2010
Location: Macedonia

Re: Ogre Mesh to Havok

Postby Mind Calamity » Sun Feb 05, 2012 12:52 am

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.
User avatar
Mind Calamity
Ogre Magi
 
Posts: 1207
Kudos: 78
Joined: 25 Dec 2010
Location: Macedonia

Re: Ogre Mesh to Havok

Postby Guardian121 » Sun Feb 05, 2012 2:35 pm

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
Guardian121
Gnoblar
 
Posts: 7
Kudos: 0
Joined: 29 Nov 2009

Re: Ogre Mesh to Havok

Postby KungFooMasta » Mon Feb 06, 2012 8:09 pm

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!

For this message the author KungFooMasta has received kudos
User avatar
KungFooMasta
OGRE Contributor
OGRE Contributor
 
Posts: 2087
Kudos: 16
Joined: 03 Mar 2005
Location: WA, USA

Re: Ogre Mesh to Havok

Postby Mind Calamity » Mon Feb 06, 2012 8:37 pm

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...
User avatar
Mind Calamity
Ogre Magi
 
Posts: 1207
Kudos: 78
Joined: 25 Dec 2010
Location: Macedonia

Re: Ogre Mesh to Havok

Postby dark_sylinc » Thu Mar 15, 2012 4:02 am

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
dark_sylinc
OGRE Team Member
OGRE Team Member
 
Posts: 826
Kudos: 163
Joined: 21 Jul 2007
Location: Buenos Aires, Argentina

Re: Ogre Mesh to Havok

Postby Mind Calamity » Sat Mar 17, 2012 4:39 am

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!
User avatar
Mind Calamity
Ogre Magi
 
Posts: 1207
Kudos: 78
Joined: 25 Dec 2010
Location: Macedonia


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 5 guests