[solved] Retrieve correct vertices data from animated mesh

Problems building or running the engine, queries about how to use features etc.
megatema
Halfling
Posts: 43
Joined: Fri Mar 09, 2007 12:59 pm
Location: Saint-Petersburg, Russia
x 2

[solved] Retrieve correct vertices data from animated mesh

Post by megatema »

How can I retrieve vertices and indices data from animated mesh? I tried to use raycast algorithm (http://www.ogre3d.org/phpBB2/viewtopic.php?t=23440), but vertices and indices arrays don’t update while animation playing.
Last edited by megatema on Mon Jun 18, 2007 11:31 am, edited 1 time in total.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Post by jacmoe »

The article covers that. For animated meshes, you have to grab the data whenever it animates.
Look at OgreOpcode to see how we do that. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
megatema
Halfling
Posts: 43
Joined: Fri Mar 09, 2007 12:59 pm
Location: Saint-Petersburg, Russia
x 2

Post by megatema »

jacmoe wrote:The article covers that. For animated meshes, you have to grab the data whenever it animates.
Look at OgreOpcode to see how we do that. :wink:
Hmmm… :-) I use code from wiki, but it doesn’t work. Vertices array always equal. May be there is some mistake?

Code: Select all

void CMainApplication::getMeshInformation(const Ogre::MeshPtr mesh,
                                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;

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

        Ogre::VertexData* 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;

			//toLogEx("\nMesh name: %s",mesh->getName().c_str());

            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;

				/*toLogEx("\n%d: %.2f %.2f %.2f",j,
					vertices[current_offset + j].x,
					vertices[current_offset + j].y,
					vertices[current_offset + j].z);*/
            }

            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;
    }
}
I tried to look OpCode too, may be it helps.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Post by jacmoe »

If you're using animated meshes using hardware skinning, you will need to tell Ogre to generate skeletal animation vertex data in software, otherwise it won't.
This is for performance reasons.

You start by issuing this command:

Code: Select all

mEntity->addSoftwareAnimationRequest(false);
Then use this:

Code: Select all

	//------------------------------------------------------------------------
	///////////////////////////////////////////////////////////////////////////////
	/// Counts how many indices (faces) and vertices an entity contains.
	/// @param[in]  entity Entity to count its data.
	/// @param[out] index_count  Number of indices.
	/// @param[out] vertex_count Number of vertices.
	/// @author Yavin from the Ogre4J team
	///////////////////////////////////////////////////////////////////////////////
	void MeshCollisionShape::countIndicesAndVertices(Entity * entity, size_t & index_count, size_t & vertex_count)
	{
		Mesh * mesh = entity->getMesh().getPointer();

		bool added_shared = false;
		index_count  = 0;
		vertex_count = 0;

		// Calculate how many vertices and indices we're going to need
		for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
		{
			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;
		}
	}


	//------------------------------------------------------------------------
	//////////////////////////////////////////////////////////////////////////
	/// Converts mesh vertex and face data into simple float arrays.
	/// If the buffer parameters are null then that data is not converted.
	/// @param[in]  entity              Entity to extract data from.
	/// @param[out] vertexBuf          Target vertex data array (can be null).
	/// @param[in]  size_t vertex_count Number of vertices.
	/// @param[out] faceData            Target face data array (can be null).
	/// @param[int] index_count         Number of indices.
	/// @author Yavin from the Ogre4J team
	//////////////////////////////////////////////////////////////////////////
	void MeshCollisionShape::convertMeshData(Entity * entity,
		float * vertexBuf, size_t vertex_count,
		size_t * faceBuf, size_t index_count)
	{
		//---------------------------------------------------------------------
		// CONVERT MESH DATA
		//---------------------------------------------------------------------
		MeshPtr mesh = entity->getMesh();
		bool added_shared = false;
		size_t current_offset = 0;
		size_t shared_offset = 0;
		size_t next_offset = 0;
		size_t index_offset = 0;
		int numOfSubs = 0;

		bool useSoftwareBlendingVertices = entity->hasSkeleton();

		if (useSoftwareBlendingVertices)
		{
			entity->_updateAnimation();
		}

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

			if (vertexBuf)
			{
				//----------------------------------------------------------------
				// GET VERTEXDATA
				//----------------------------------------------------------------
				const VertexData * vertex_data;
				if(useSoftwareBlendingVertices)
					vertex_data = useSharedVertices ? entity->_getSkelAnimVertexData() : entity->getSubEntity(i)->_getSkelAnimVertexData();
				else
					vertex_data = useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;

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

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

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

					unsigned char* vertex =
						static_cast<unsigned char*>(vbuf->lock(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 is
					//  comiled/typedefed as double:
					float* pReal;


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

						size_t n = current_offset*3 + j*3;

						vertexBuf[n + 0] = pReal[0];
						vertexBuf[n + 1] = pReal[1];
						vertexBuf[n + 2] = pReal[2];
					}

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

			if (faceBuf)
			{
				//----------------------------------------------------------------
				// GET INDEXDATA
				//----------------------------------------------------------------
				IndexData* index_data = submesh->indexData;
				size_t numTris = index_data->indexCount / 3;
				HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;

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

				uint32 *pLong = static_cast<uint32*>(ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
				uint16* pShort = reinterpret_cast<uint16*>(pLong);


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

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

				ibuf->unlock();
			}

			current_offset = next_offset;
		}
	}
Do not forget to remove the software animation request when done:

Code: Select all

mEntity->removeSoftwareAnimationRequest(false);
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
megatema
Halfling
Posts: 43
Joined: Fri Mar 09, 2007 12:59 pm
Location: Saint-Petersburg, Russia
x 2

Re: Retrieve correct vertices data from animated mesh

Post by megatema »

Thanx, I'll try it.
User avatar
Yavin
Bronze Sponsor
Bronze Sponsor
Posts: 140
Joined: Wed Mar 02, 2005 3:41 pm
Location: Lake Constance, Germany

Post by Yavin »

Hey, nice to see that code from me is still in use :wink: Already forgot that I published this snippets.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Post by jacmoe »

Nice code, Yavin! OgreOpcode simply wouldn't be the same without 'em! :)
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.