Recast - Open Source Alternative to PathEngine

A place for Ogre users to discuss non-Ogre subjects with friends from the community.
User avatar
koirat
Orc
Posts: 446
Joined: Mon Feb 25, 2008 7:56 pm
x 13

Re: Recast - Open Source Alternative to PathEngine

Post by koirat »

jacmoe wrote:Right. :)
I think it's because rc and dt is meant to be some sort of namespace-like prefix; 'rc' is the library and the rest is the typename.
If you view it that way, it ought to make sense. :wink:
http://www.ogre3d.org/forums/viewtopic. ... ra#p151165
jacmoe wrote: by jacmoe » Thu May 25, 2006 2:20 pm
Generally, prefixing classes is not a good idea (IMO).
Just call them what they are, and put them in a namespace.
Then they become:
ac::CameraManager, ac::ViewportManager and ac::System.
I see you have became more tolerant as years has passed. :wink:

Could not resist posting it here,
even risking being an asshole :P.
This is a block of text that can be added to posts you make. There is a 255 character limit.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: Recast - Open Source Alternative to PathEngine

Post by jacmoe »

:lol:
Alright, you win. :)
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
amina
Gnoblar
Posts: 6
Joined: Wed Dec 16, 2009 1:19 pm

Re: Recast - Open Source Alternative to PathEngine

Post by amina »

Hi,
Thanks to Mikko for his code, it's very interesting.I would like to integrate recast to Ogre but i need some help.
User avatar
KungFooMasta
OGRE Contributor
OGRE Contributor
Posts: 2087
Joined: Thu Mar 03, 2005 7:11 am
Location: WA, USA
x 16
Contact:

Re: Recast - Open Source Alternative to PathEngine

Post by KungFooMasta »

I've made some posts that might help you if you're trying to integrate Sinbad's new Terrain system with Recast:

http://groups.google.com/group/recastna ... 39f64ece58

I'm still working on it, and I only put in a few hours a week so progress is slow, but if I do eventually get a solution, I'll probably post it up here or on wiki or somewhere, in case people want to use it as reference. :)

(I wouldn't recommend waiting for me to come up with anything tho)
Creator of QuickGUI!
amina
Gnoblar
Posts: 6
Joined: Wed Dec 16, 2009 1:19 pm

Re: Recast - Open Source Alternative to PathEngine

Post by amina »

Thanks KungFooMasta, this is very helpful! :D
al2950
OGRE Expert User
OGRE Expert User
Posts: 1227
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 157

Re: Recast - Open Source Alternative to PathEngine

Post by al2950 »

Hi

Has anyone got anycode for converting an Ogre Mesh into verts and tris for use with recastnavigation. I have done an implementation and got it too work in Debug but for some reason it crashes in release and its driving me mad!!! I am new to the vertices and indicies, but i thought i had understood, i am using the getMeshInformation method from the ogre wiki.

Using debug it seems to work, and I create a manualObject of the generated Nav Mesh, but i cant tell if has been created correctly!!
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: Recast - Open Source Alternative to PathEngine

Post by jacmoe »

That's basically what I did.
Still trying to find my code..
Or some time to write a new demo from scratch. But I used that.
Look for init of your variables, things like that.
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
fatcoder2
Gnoblar
Posts: 6
Joined: Wed Jan 06, 2010 12:42 am

Re: Recast - Open Source Alternative to PathEngine

Post by fatcoder2 »

I'm wondering if Recast + Detour would be suitable for an RTS style game I'm working on. Can the navmesh be updated quickly when something is placed on the terrain, such as a building for example?

In my game, the player can lay down paths (i.e. like roads and footpaths for example). I give a weight or bias to the areas that have a road/footpath on them so that the pathfinding is more likely to follow them rather than cut through the wilderness for example. Can this be done with Recast/Detour? I've looked through the source but couldn't see anything obvious.
User avatar
Kyle_Katarn
Halfling
Posts: 92
Joined: Tue Jul 21, 2009 7:51 am
Location: Australia

Re: Recast - Open Source Alternative to PathEngine

Post by Kyle_Katarn »

I assume it could be, all you need to do is call the code that inits the navmesh again. Or just use raycasting on your unit models to make them avoid your buildings.
al2950
OGRE Expert User
OGRE Expert User
Posts: 1227
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 157

Re: Recast - Open Source Alternative to PathEngine

Post by al2950 »

**EDIT** Fixed the problem i had in this post, and i have changed the code to reflect the fix. It was due to the fact cfg.borderSize had not been initialised.
**EDIT #2** Code now takes a std::Vector of sceneNode pointers, converts all meshes attached to those nodes into a single recast tris and verts structure. It converts all verticies into world space relative to a parentSceneNode

This is how i have intergrated recast with Ogre, could someone have a look at it and make sure i am not doing any thing stupid! The problem is that my app crashes when it its run outside the visual studio enviroment which points to something reading past the end of an array but i have no way of finding where!
This code does work though, I will update it when i find a solution to the problem;

Create Nav Mesh (This is where my app crashes if not in the Visual Studio enviroment)

Code: Select all

		//SceneNodeList is just a std::vector<Ogre::SceneNode*>, parentSceneNode is the reference sceneNode for converting vertices to world space			
		void AIManager::createNavigationMesh(SceneNodeList sceneNodeList, Ogre::SceneNode *parentSceneNode)
		{
			float bmin[3];
			float bmax[3];
			int ntris = 0; //number of total triangles
			int *tris; //list of trinagles
			float *verts; //list of verticies
			int nverts = 0; //number of verticies
			
			bool keepInterResults = false; // make sure you delete intermediate results

			//config setup
			//default values
			float cellSize = 0.3f;
			float cellHeight = 0.2f;
			float agentHeight = 2.0f;
			float agentRadius = 0.6f;
			float agentMaxClimb = 0.2f;
			float agentMaxSlope = 45.0f;
			float regionMinSize = 50;
			float regionMergeSize = 20;
			float edgeMaxLen = 12.0f;
			float edgeMaxError = 1.3f;
			float vertsPerPoly = 6.0f;
			float detailSampleDist = 6.0f;
			float detailSampleMaxError = 1.0f;

			//setup rc config structure
			rcConfig cfg;
			cfg.cs = cellSize;
			cfg.ch = cellHeight;
			cfg.walkableSlopeAngle = agentMaxSlope;
			cfg.walkableHeight = (int)ceilf(agentHeight / cfg.ch);
			cfg.walkableClimb = (int)ceilf(agentMaxClimb / cfg.ch);
			cfg.walkableRadius = (int)ceilf(agentRadius / cfg.cs);
			cfg.maxEdgeLen = (int)(edgeMaxLen / cellSize);
			cfg.maxSimplificationError = edgeMaxError;
			cfg.minRegionSize = (int)rcSqr(regionMinSize);
			cfg.mergeRegionSize = (int)rcSqr(regionMergeSize);
			cfg.maxVertsPerPoly = (int)vertsPerPoly;
			cfg.detailSampleDist = detailSampleDist < 0.9f ? 0 : cellSize * detailSampleDist;
			cfg.detailSampleMaxError = cellHeight * detailSampleMaxError;
			cfg.borderSize = 0;

			//get all vertices and triangles
			// mesh data to retrieve
			const int numNodes = sceneNodeList.size();

			size_t *meshVertexCount = new size_t[numNodes];
			size_t *meshIndexCount = new size_t[numNodes];
	
			Ogre::Vector3 **meshVertices = new Ogre::Vector3*[numNodes];
			Ogre::uint32 **meshIndices = new Ogre::uint32*[numNodes];	

			for (int i = 0 ; i < numNodes ; i++)
			{
				//TODO: Iterate through all attached objects and also check that attache object is an entity
				Ogre::Entity *ent = (Ogre::Entity*)sceneNodeList[i]->getAttachedObject(0);
				this->getMeshInformation(ent->getMesh(), meshVertexCount[i], meshVertices[i], meshIndexCount[i], meshIndices[i]);

				//total number of verts
				nverts += meshVertexCount[i];
				//total number of indices
				ntris += meshIndexCount[i];
			}
			
			verts = new float[nverts*3];// *3 as verts holds x,y,&z for each vert in the array
			tris = new int[ntris];// tris in recast is really indicies like ogre

			//convert index count into tri count
			ntris = ntris/3; //although the tris array are indicies the ntris is actual number of triangles, ie indicies/3;

			//set the reference node
			Ogre::SceneNode *referenceNode;
			if (parentSceneNode == 0)
			{
				referenceNode = SEAVis::Core::getSingleton().getSceneManager()->getRootSceneNode();
			}
			else
			{
				referenceNode = parentSceneNode;
			}

			//copy all meshes verticies into single buffer and transform to world space relative to parentNode
			int vertsIndex = 0;
			int prevVerticiesCount = 0;
			int prevIndexCountTotal = 0;
			for (int i = 0 ; i < sceneNodeList.size() ; i++)
			{
				//find the transform between the reference node and this node
				Ogre::Matrix4 transform = referenceNode->_getFullTransform().inverse() *sceneNodeList[i]->_getFullTransform();
				Ogre::Vector3 vertexPos;
				for (int j = 0 ; j < meshVertexCount[i] ; j++)
				{
					vertexPos = transform*meshVertices[i][j];
					verts[vertsIndex] = vertexPos.x;
					verts[vertsIndex+1] = vertexPos.y;
					verts[vertsIndex+2] = vertexPos.z;
					vertsIndex+=3;
				}

				for (int j = 0 ; j < meshIndexCount[i] ; j++)
				{
					tris[prevIndexCountTotal+j] = meshIndices[i][j]+prevVerticiesCount;
				}
				prevIndexCountTotal += meshIndexCount[i];
				prevVerticiesCount = meshVertexCount[i];
			}

			//delete tempory arrays 
			//TODO These probably could member varibles, this would increase performance slightly
			for (int i = 0 ; i < numNodes ; i++)
			{
				delete [] meshVertices[i];
				delete [] meshIndices[i];
			}
			delete [] meshVertices;
			delete [] meshVertexCount;
			delete [] meshIndices;
			delete [] meshIndexCount;

			// Set the area where the navigation will be build.
			// Here the bounds of the input mesh are used, but the
			// area could be specified by an user defined box, etc.
			rcCalcBounds(verts, nverts, bmin, bmax);
			vcopy(cfg.bmin, bmin);
			vcopy(cfg.bmax, bmax);
			rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
                     
			//................. The rest of the code is straight out of the recast demo
The getMeshInformation method is from this page in the wiki a few minor changes;
http://www.ogre3d.org/wiki/index.php/RetrieveVertexData


Draw NavMesh

Code: Select all

		//displays a recast poly mesh and attaches it to parentSceneNode
		void AIManager::displayNavMesh(rcPolyMesh *polyMesh, Ogre::SceneNode *parentSceneNode)
		{
			// Create a manual object
			//TODO: Dont hardcode name!!!
			Ogre::ManualObject *obj = SEAVis::Core::getSingleton().getSceneManager()->createManualObject("NavMesh");
			obj->begin("NavMesh");
			
			const int nvp = polyMesh->nvp;
			const float cs = polyMesh->cs;
			const float ch = polyMesh->ch;
			const float* orig = polyMesh->bmin;
			
			int nvt = 0; // triangle verts

			for (int i = 0; i < polyMesh->npolys; ++i)
			{
				const unsigned short* p = &polyMesh->polys[i*nvp*2];
				unsigned short vi[3];
				for (int j = 2; j < nvp; ++j)
				{
					if (p[j] == 0xffff) break;
					vi[0] = p[0];
					vi[1] = p[j-1];
					vi[2] = p[j];
					for (int k = 0; k < 3; ++k)
					{
						const unsigned short* v = &polyMesh->verts[vi[k]*3];
						const float x = orig[0] + v[0]*cs;
						const float y = orig[1] + (v[1]+0.3)*ch; //+0.3 to set Nav mesh above Graphics mesh
						const float z = orig[2] + v[2]*cs;
						obj->position(x,y,z);
					}
				}
			}

			obj->end();
			if (parentSceneNode == 0)
			{
				SEAVis::Core::getSingleton().getSceneManager()->getRootSceneNode()->attachObject(obj);	
			}
			else
			{
				parentSceneNode->attachObject(obj);
			}
		}

As i said this code has a problem somewhere which leads to a crash, but i will update it when i fix it. Please feel free to use it to get yourself up and running

**EDIT** This is a first attempt piece of code, not my best code ever!! It can be optimized, having said that recastnavigation runs so fast its not needed yet!
Last edited by al2950 on Tue Jan 12, 2010 1:48 pm, edited 3 times in total.
User avatar
KungFooMasta
OGRE Contributor
OGRE Contributor
Posts: 2087
Joined: Thu Mar 03, 2005 7:11 am
Location: WA, USA
x 16
Contact:

Re: Recast - Open Source Alternative to PathEngine

Post by KungFooMasta »

al2950, please keep us posted, I'm also integrating recast into my RTS style game, but at a much slower pace. :)
Kyle_Katarn wrote:I assume it could be, all you need to do is call the code that inits the navmesh again. Or just use raycasting on your unit models to make them avoid your buildings.
You're forgetting trees, that are either destroyed or regrown, IMO they should alter the navmesh. I'm hoping the recast tile mesh is the solution for this.
Creator of QuickGUI!
al2950
OGRE Expert User
OGRE Expert User
Posts: 1227
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 157

Re: Recast - Open Source Alternative to PathEngine

Post by al2950 »

YAY!! Fixed my problem, good old printf's!!

Basically in the recast demos cfg.borderSize is never set, but for some reason when compiled it works (ie always = 0, even in release). I copied the demos so i also never set cfg.borderSize, however in my app, as with all uninitilaised values it was a crazy number and should have been 0.

I have changed my previous post and code so it will work.

On another note, as i am still new to recast and playing around with verticies and hardware buffers etc. Can anyone give me hand with the following prolbem;

I have multiple meshes of which i want to create a single NavMesh out of, but when you get the verticies out of a mesh there are in object space and not world space. So... is there a clever way to transform all the vertices into world space using the (Global) position and orientation of their parent scene node?
User avatar
xadhoom
Minaton
Posts: 973
Joined: Fri Dec 28, 2007 4:35 pm
Location: Germany
x 1

Re: Recast - Open Source Alternative to PathEngine

Post by xadhoom »

Hey, thanks for the update! Recast is a very interesting library. :D

To get global coordinates I think you have to add the derived position of the scene node to every vertex...

xad
al2950
OGRE Expert User
OGRE Expert User
Posts: 1227
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 157

Re: Recast - Open Source Alternative to PathEngine

Post by al2950 »

To get global coordinates I think you have to add the derived position of the scene node to every vertex...
Unfortuantley it is not quite that simple if you have rotations as well. I am worried that transforming all the verticies will actually take quite a long time, atleast the way i am thinking of doing it. Oh well, will post my results when i get it done!!
User avatar
xadhoom
Minaton
Posts: 973
Joined: Fri Dec 28, 2007 4:35 pm
Location: Germany
x 1

Re: Recast - Open Source Alternative to PathEngine

Post by xadhoom »

Ah, yes of course.
Best should be: Get the full transform matrix 4x3 (position/rotation) and multiply every local vertex position with it. I wouldn´t care too much about efficiency now.
You might use some matrix multiplication speedup with SSE later, though.

xad
al2950
OGRE Expert User
OGRE Expert User
Posts: 1227
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 157

Re: Recast - Open Source Alternative to PathEngine

Post by al2950 »

I have made a few changes to my code above, it now does the following;

1) Takes a list of sceneNodes
2) Retreives all mesh data from all the Nodes
3) Converts all mesh data into world space relative to a parent node
4) Puts world space mesh data into recast tris & verts structure for use with recast.
5) Displays the NavMesh created by recast and attaches it to parentNode in step 3.

The Code is NOT a finished product but it works. Make sure you look at all //TODO 's! It's unlikely i will change it any further, but i am happy to answer any questions anyone has about it!

**EDIT** Transforming all the vertices to world space does not seem cost much interms of performance, but i have not done any proper tests.
User avatar
KungFooMasta
OGRE Contributor
OGRE Contributor
Posts: 2087
Joined: Thu Mar 03, 2005 7:11 am
Location: WA, USA
x 16
Contact:

Re: Recast - Open Source Alternative to PathEngine

Post by KungFooMasta »

al2950, do you by chance use Havok? The docs and provided demos do not really mention support for mesh shapes, however if you search for meshshape you will find there is a hkMeshShape class, a hkMeshSection class, and a hkMeshVertexBuffer class, all seem to be related to each other as a way to create a shape from a mesh. It would be nice if there was a havok demo of how to create a mesh shape. :(
Creator of QuickGUI!
al2950
OGRE Expert User
OGRE Expert User
Posts: 1227
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 157

Re: Recast - Open Source Alternative to PathEngine

Post by al2950 »

No, sorry. I use PhysX :D. However in physics though you rarely want to create a physics mesh direclty from a graphics mesh, especially if its a dynamic physic object as the Physics engine will grind to a halt!
User avatar
syedhs
Silver Sponsor
Silver Sponsor
Posts: 2703
Joined: Mon Aug 29, 2005 3:24 pm
Location: Kuala Lumpur, Malaysia
x 51

Re: Recast - Open Source Alternative to PathEngine

Post by syedhs »

I have come across another blog entry which is related to navigation meshes aka what recast is all about.

An-Introduction-to-AI-in-Games-from-Phil-Carlisle2

If you read the blog entry, you will find another interesting link, which is long but full of facts...
Fixing Pathfinding Once and For All

Wohooo all I can say this whole thing (navigation mesh) is very interesting, but I just can't tackle it for now due to other commitments... we will see in the next coming months.. :mrgreen:
A willow deeply scarred, somebody's broken heart
And a washed-out dream
They follow the pattern of the wind, ya' see
Cause they got no place to be
That's why I'm starting with me
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: Recast - Open Source Alternative to PathEngine

Post by jacmoe »

Phil Carlisle is a very active member of AiGamedev where Recast was initially released to premium members only. :)

And that article is awesome! :D
I have read it numerous times - IMO it's the best article on that subject ever.
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
KungFooMasta
OGRE Contributor
OGRE Contributor
Posts: 2087
Joined: Thu Mar 03, 2005 7:11 am
Location: WA, USA
x 16
Contact:

Re: Recast - Open Source Alternative to PathEngine

Post by KungFooMasta »

Thought I would share my solution for creating a mesh shape in Havok, especially since there doesn't seem to be many available examples.

Code: Select all

			Ogre::SceneManager* sm = mScene->_getOgreSceneManager();
			Ogre::Entity* entity = sm->createEntity(mGameObject->getName() + ".GCShapeMesh.Entity", mesh);
			
			// mesh data to retrieve         
			size_t vertexCount;
			size_t indexCount;
			Ogre::Vector3* vertices = NULL;
			unsigned long* indices = NULL;

			// get the mesh information
			_getMeshInformation(entity, vertexCount, vertices, indexCount, indices,
								Ogre::Vector3::ZERO,
								Ogre::Quaternion::IDENTITY,
								Ogre::Vector3::UNIT_SCALE);

			float* vertFloatArray = new float[vertexCount * 3];
			for(int i = 0; i < vertexCount; ++i)
			{
				Ogre::Vector3 v = vertices[i];
				vertFloatArray[(i * 3)] = v.x;
				vertFloatArray[(i * 3) + 1] = v.y;
				vertFloatArray[(i * 3) + 2] = v.z;
			}

			// Create cube shape
			hkpExtendedMeshShape* shape = new hkpExtendedMeshShape();
			{
				hkpExtendedMeshShape::TrianglesSubpart part;
				part.m_numTriangleShapes	= indexCount;
				part.m_numVertices			= vertexCount;
				part.m_vertexBase			= vertFloatArray;
				part.m_stridingType			= hkpExtendedMeshShape::INDICES_INT32;
				part.m_vertexStriding		= sizeof(float) * 3;
				part.m_indexBase			= indices;
				part.m_indexStriding		= sizeof(unsigned long) * 3;
				part.m_numTriangleShapes	= indexCount/3;

				shape->addTrianglesSubpart( part );
			}

			shape->setUserData((hkUlong)mGameObject);
			hkpShape* shapeUsed = shape;
			if(mMeshShapeDesc->offset != Vector3::ZERO)
				Gaia::Logger::getSingletonPtr()->throwException(Ogre::Exception::ERR_INVALIDPARAMS,"An offset was set, but MeshShape does not support an offset!","GCMeshShape::setMesh");

			sm->destroyEntity(entity);

			// Create rigid body
			hkpRigidBodyCinfo rbInfo;
			rbInfo.m_shape = shapeUsed;
			hkpInertiaTensorComputer::setShapeVolumeMassProperties(shape, mMeshShapeDesc->mass, rbInfo);
			rbInfo.m_motionType = (hkpMotion::MotionType)(mMeshShapeDesc->motionType);
			rbInfo.m_qualityType = mMeshShapeDesc->collidableQualityType;
			rbInfo.m_collisionFilterInfo = mMeshShapeDesc->collisionFlags;

			if(mGameObject->hasComponent("GCLocation"))
			{
				mLocation = mGameObject->getComponent<GCLocation>("GCLocation");
				Vector3 p = mLocation->getPosition();
				rbInfo.m_position.set(p.x,p.y,p.z);
			}
			else
				rbInfo.m_position.setZero4();


			if(mGameObject->hasComponent("GCOrientation"))
			{
				mOrientation = mGameObject->getComponent<GCOrientation>("GCOrientation");
				Quaternion q = mOrientation->getOrientation();
				rbInfo.m_rotation = hkQuaternion(q.x, q.y, q.z, q.w);
			}

			mRigidBody = new hkpRigidBody(rbInfo);
			shape->removeReference();

			// Add rigid body to world
			hkpWorld* world = mScene->_getHavokWorld();
			world->lock();
			world->addEntity(mRigidBody);
			world->unlock();
The 'getMeshInformation' function is from the wiki.
Creator of QuickGUI!
Post Reply