[2.1] Create Recast navigation mesh from Ogre mesh

Problems building or running the engine, queries about how to use features etc.
Post Reply
123iamking
Gremlin
Posts: 152
Joined: Sat Aug 12, 2017 4:16 pm
x 4

[2.1] Create Recast navigation mesh from Ogre mesh

Post by 123iamking »

I'm learning Recast & Detour. I have tried to read the Recast's Demo and see that the triangle & vertical is from the obj file (just a text file which can be read with notepad). I also check this article to find something simple to get started, but this example didn't provide any simple navigation mesh (as I understand).

So I wanna KISS (Keep-It-Simple-Stupid). Here in Ogre 2.1 has a pretty sample
Image
As you can see, in this sample, there is a simple plane for ground. All I want is create a recast navigate mesh for this plane, so that I can detour a character on this plane.

Any input is appreciated :)

Edit: Since Ogre 1.x already has help from Ogre Crowd, and this topic said more about Ogre 2.1, so I decide to add the tag [2.1] to this topic :)
Last edited by 123iamking on Wed Nov 15, 2017 12:20 pm, edited 1 time in total.
frostbyte
Orc Shaman
Posts: 737
Joined: Fri May 31, 2013 2:28 am
x 65

Re: Create Recast navigation mesh from Ogre mesh

Post by frostbyte »

D'oh!, you are too fast :lol:
code reference( for ogre 1.x ) is here https://bitbucket.org/ogreaddons/ogrerecastdemo
and a complete sample https://bitbucket.org/ogreaddons/ogrecrowd
the relevant code for building a recast mesh from ogre mesh should be similar/same for v1::meshes/entities
the woods are lovely dark and deep
but i have promises to keep
and miles to code before i sleep
and miles to code before i sleep..

coolest videos link( two minutes paper )...
https://www.youtube.com/user/keeroyz/videos
123iamking
Gremlin
Posts: 152
Joined: Sat Aug 12, 2017 4:16 pm
x 4

Re: Create Recast navigation mesh from Ogre mesh

Post by 123iamking »

@frostbyte: Thank frostbyte :) I have also read this OgreCrowd showcase, I didn't notice that it is under Ogre-addon umbrella too, cool :)
123iamking
Gremlin
Posts: 152
Joined: Sat Aug 12, 2017 4:16 pm
x 4

Re: Create Recast navigation mesh from Ogre mesh

Post by 123iamking »

I see that in Ogre Crowd Demo, the function NavMeshBuild() may be the answer :)

I'm really interesting in DrawDebug polygon for recast navigation mesh. May be that can be done with manual object.

There is some convert for Ogre 2.1 I made:
Ogre::Entity* srcMesh ---> Ogre::Item *itemPlane
const Ogre::AxisAlignedBox srcMeshBB = srcMesh->getBoundingBox(); -----> const Ogre::Aabb srcMeshBB = itemPlane->getLocalAabb(); (base on this article)


But I have problem in convert function getMeshInformation() for Ogre 2.1. Here is my progress so far for this function

Code: Select all

	void getMeshInformation(const Ogre::MeshPtr mesh,
		size_t &vertex_count,
		Ogre::Vector3* &vertices,
		size_t &index_count,
		unsigned long* &indices,
		const Ogre::Vector3 &position = Ogre::Vector3::ZERO,
		const Ogre::Quaternion &orient = Ogre::Quaternion::IDENTITY,
		const Ogre::Vector3 &scale = Ogre::Vector3::UNIT_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::v1::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::v1::VertexElement* posElem =
					vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);

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

				unsigned char* vertex =
					static_cast<unsigned char*>(vbuf->lock(Ogre::v1::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::v1::IndexData* index_data = submesh->indexData;
			size_t numTris = index_data->indexCount / 3;
			Ogre::v1::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;

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

			unsigned long* pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::v1::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;
		}
	}
But I get the these errors
class "Ogre::Mesh" has no member "sharedVertexData"
class "Ogre::SubMesh" has no member "indexData"
class "Ogre::SubMesh" has no member "useSharedVertices"
class "Ogre::SubMesh" has no member "vertexData"
I have read this article but I still don't know how to replace these member variables for Ogre 2.1.
***Edit***
Wait a minute, I see that SolarPortal has the function getMeshInformation for Ogre 2.1 implemented, so convenient :)
SolarPortal wrote: Tue Jan 26, 2016 6:02 pm [...]

Here is the new v2 Mesh code that will work with Items and the newer mesh format.

Code: Select all

/*
	Get the mesh information for the given mesh in v2 Ogre3D format. This is a really useful function that can be used by many
	different systems. e.g. physics mesh, navmesh, occlusion geometry etc...

	Original Code - Code found on this forum link: http://www.ogre3d.org/wiki/index.php/RetrieveVertexData
	Most Code courtesy of al2950( thanks m8 :)), but then edited by Jayce Young & Hannah Young at Aurasoft UK (Skyline Game Engine) 
	to work with Items in the scene.
*/
void CollisionTools::getMeshInformation(const Ogre::MeshPtr			mesh,
	size_t					&vertex_count,
	Ogre::Vector3*			&vertices,
	size_t					&index_count,
	Ogre::uint32*			&indices,
	const Ogre::Vector3		&position,
	const Ogre::Quaternion	&orient,
	const Ogre::Vector3		&scale)
{
	//First, we compute the total number of vertices and indices and init the buffers.
	unsigned int numVertices = 0;
	unsigned int numIndices = 0;

	Ogre::Mesh::SubMeshVec::const_iterator subMeshIterator = mesh->getSubMeshes().begin();

	while (subMeshIterator != mesh->getSubMeshes().end())
	{
		Ogre::SubMesh *subMesh = *subMeshIterator;
		numVertices += subMesh->mVao[0][0]->getVertexBuffers()[0]->getNumElements();
		numIndices += subMesh->mVao[0][0]->getIndexBuffer()->getNumElements();

		subMeshIterator++;
	}

	vertices = new Ogre::Vector3[numVertices];
	indices = new Ogre::uint32[numIndices];

	vertex_count = numVertices;
	index_count = numIndices;

	unsigned int addedVertices = 0;
	unsigned int addedIndices = 0;

	unsigned int index_offset = 0;
	unsigned int subMeshOffset = 0;

	// Read Submeshes
	subMeshIterator = mesh->getSubMeshes().begin();
	while (subMeshIterator != mesh->getSubMeshes().end())
	{
		Ogre::SubMesh *subMesh = *subMeshIterator;
		Ogre::VertexArrayObjectArray vaos = subMesh->mVao[0];

		if (!vaos.empty())
		{
			//Get the first LOD level 
			Ogre::VertexArrayObject *vao = vaos[0];
			bool indices32 = (vao->getIndexBuffer()->getIndexType() == Ogre::IndexBufferPacked::IT_32BIT);

			const Ogre::VertexBufferPackedVec &vertexBuffers = vao->getVertexBuffers();
			Ogre::IndexBufferPacked *indexBuffer = vao->getIndexBuffer();

			//request async read from buffer 
			Ogre::VertexArrayObject::ReadRequestsArray requests;
			requests.push_back(Ogre::VertexArrayObject::ReadRequests(Ogre::VES_POSITION));

			vao->readRequests(requests);
			vao->mapAsyncTickets(requests);
			unsigned int subMeshVerticiesNum = requests[0].vertexBuffer->getNumElements();
			if (requests[0].type == Ogre::VET_HALF4)
			{
				for (size_t i = 0; i < subMeshVerticiesNum; ++i)
				{
					const Ogre::uint16* pos = reinterpret_cast<const Ogre::uint16*>(requests[0].data);
					Ogre::Vector3 vec;
					vec.x = Ogre::Bitwise::halfToFloat(pos[0]);
					vec.y = Ogre::Bitwise::halfToFloat(pos[1]);
					vec.z = Ogre::Bitwise::halfToFloat(pos[2]);
					requests[0].data += requests[0].vertexBuffer->getBytesPerElement();
					vertices[i + subMeshOffset] = (orient * (vec * scale)) + position;
				}
			}
			else if (requests[0].type == Ogre::VET_FLOAT3)
			{
				for (size_t i = 0; i < subMeshVerticiesNum; ++i)
				{
					const float* pos = reinterpret_cast<const float*>(requests[0].data);
					Ogre::Vector3 vec;
					vec.x = *pos++;
					vec.y = *pos++;
					vec.z = *pos++;
					requests[0].data += requests[0].vertexBuffer->getBytesPerElement();
					vertices[i + subMeshOffset] = (orient * (vec * scale)) + position;
				}
			}
			else
			{
				lprint("Error: Vertex Buffer type not recognised in MeshTools::getMeshInformation");
			}
			subMeshOffset += subMeshVerticiesNum;
			vao->unmapAsyncTickets(requests);

			////Read index data
			if (indexBuffer)
			{
				Ogre::AsyncTicketPtr asyncTicket = indexBuffer->readRequest(0, indexBuffer->getNumElements());

				unsigned int *pIndices = 0;
				if (indices32)
				{
					pIndices = (unsigned*)(asyncTicket->map());
				}
				else
				{
					unsigned short *pShortIndices = (unsigned short*)(asyncTicket->map());
					pIndices = new unsigned int[indexBuffer->getNumElements()];
					for (size_t k = 0; k < indexBuffer->getNumElements(); k++) pIndices[k] = static_cast<unsigned int>(pShortIndices[k]);
				}
				unsigned int bufferIndex = 0;

				for (size_t i = addedIndices; i < addedIndices + indexBuffer->getNumElements(); i++)
				{
					indices[i] = pIndices[bufferIndex] + index_offset;
					bufferIndex++;
				}
				addedIndices += indexBuffer->getNumElements();

				if (!indices32) delete[] pIndices;

				asyncTicket->unmap();
			}
			index_offset += vertexBuffers[0]->getNumElements();
		}
		subMeshIterator++;
	}
}

[...]
And I see that function getMeshInformation() is even on Wiki.
123iamking
Gremlin
Posts: 152
Joined: Sat Aug 12, 2017 4:16 pm
x 4

Re: Create Recast navigation mesh from Ogre mesh

Post by 123iamking »

Ok, so after I tweak a bit, I get the function NavMeshBuild() compile successfully for Ogre 2.1, yay :)
But now, I get the error: "ERROR: No contours created (Recast)!"
To fix this error, I must: (base on the comment)
You should probably tweak the parameters (at the top of this method)
Which are these variables (I guess)

Code: Select all

   m_cellSize = /*9.0 ;//*/0.3;         //*
   m_cellHeight = /*6.0 ;//*/0.2;       //*
   m_agentMaxSlope = /*45*/20;          //*
   m_agentHeight = /*64.0;*/1;        //*
   m_agentMaxClimb = 16;                //*
   m_agentRadius = /*16;*/0.5;          //*
   m_edgeMaxLen = 12/*512*/;
To set these variable right for my mesh, I have to draw the navigation mesh so that it can be viewed by bare human eyes, base on what Mikko Mononen said
Mikko Mononen wrote: No it's time to implement the debug draw interface :) Seriously, it is
the most easiest way to debug these things. There are debug draw
functions to display the data at every step along the pipeline.
So the needed thing now is a Ogre 2.1 DebugDraw struct that is derived from the
duDebugDraw struct. So that we can use the function duDebugDrawHeightfieldSolid() to draw debug navigation mesh. Since this is lead to debug to do thing right, I make a new topic about debug Recast Detour here.
Post Reply