OgreCrowd: a crowd component for Ogre using Recast/Detour

A place to show off your latest screenshots and for people to comment on them. Only start a new thread here if you have some nice images to show off!
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by duststorm »

Good catch!
That code has indeed a tendency to go out of scope. Strange how gcc seems to be very forgiving for these types of mistakes. Maybe it notices stack allocation is not wishful for such a large object and heap allocates it instead.
I committed your fix.
Developer @ MakeHuman.org
User avatar
cbibejs
Kobold
Posts: 31
Joined: Wed Feb 08, 2012 1:00 pm

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by cbibejs »

Hi.First i want to say thnx for sharing your works Mikko Mononen and duststorm.
I've just implement save and load Tilecache functions to my game and i want to share with you.NavMesh save load functions are just copy paste from recast Sample_TileMesh demo.
OgreDetourTileCache.h

Code: Select all

        void buildTilesLive(InputGeom *inputGeom,const Ogre::AxisAlignedBox *areaToUpdate = NULL);
	void saveAllCache(const char* path, const dtTileCache* mesh);
	dtTileCache* loadAllCache(const char* path);
	dtTileCache *getTileCache(){return m_tileCache;};
OgreDetourTileCache.cpp

Code: Select all

struct TileCacheSetHeader
{
        int magic;
        int version;
        int numTiles;
        dtTileCacheParams params;
		
};

Code: Select all

struct TileCacheHeader
{
        dtTileRef tileRef;
        int dataSize;
		
};

Code: Select all

void OgreDetourTileCache::buildTilesLive(InputGeom *inputGeom, const Ogre::AxisAlignedBox *areaToUpdate)
{
    // Use bounding box from inputgeom if no area was explicitly specified
    Ogre::AxisAlignedBox updateArea;
    if(!areaToUpdate)
        updateArea = inputGeom->getBoundingBox();
    else
        updateArea = *areaToUpdate;

    // Reduce bounding area a little with one cell in size, to be sure that if it was already tile-aligned, we don't select an extra tile
    updateArea.setMinimum( updateArea.getMinimum() + Ogre::Vector3(m_cellSize, 0, m_cellSize) );
    updateArea.setMaximum( updateArea.getMaximum() - Ogre::Vector3(m_cellSize, 0, m_cellSize) );

    // Select tiles to build or rebuild (builds a tile-aligned BB)
    TileSelection selection = getTileSelection(updateArea);


    // Debug drawing of bounding area that is updated
    // Remove previous debug drawn bounding box of rebuilt area
    if(mDebugRebuiltBB) {
        mDebugRebuiltBB->detachFromParent();
		m_recast->mSceneMgrz->destroyManualObject(mDebugRebuiltBB);
        mDebugRebuiltBB = NULL;
    }
    if(DEBUG_DRAW_REBUILT_BB)
		mDebugRebuiltBB = InputGeom::drawBoundingBox(selection.bounds,mSceneMgr);
    // Build tiles
       for (int ty = selection.minTy; ty <= selection.maxTy; ty++) {
        for (int tx = selection.minTx; tx <= selection.maxTx; tx++) {
          m_tileCache->buildNavMeshTilesAt(tx,ty,m_navMesh);
        }
    }
}

Code: Select all

void OgreDetourTileCache::saveAllCache(const char* path, const dtTileCache* mesh)
{
        if (!mesh) return;
       
        FILE* fp = fopen(path, "wb");
        if (!fp)
                return;
      
        // Store header.
        TileCacheSetHeader header;
        header.magic = NAVMESHSET_MAGIC;
        header.version = NAVMESHSET_VERSION;
		header.numTiles = 0;
		for (int i = 0; i < mesh->getTileCount(); ++i)
        {
			const dtCompressedTile* tile = mesh->getTile(i);
                if (!tile || !tile->header || !tile->dataSize) continue;
                header.numTiles++;
        }
        memcpy(&header.params, mesh->getParams(), sizeof(dtTileCacheParams));
        fwrite(&header, sizeof(TileCacheSetHeader), 1, fp);

        // Store tiles.
        for (int i = 0; i < mesh->getTileCount(); ++i)
        {
                const dtCompressedTile* tile = mesh->getTile(i);
                if (!tile || !tile->header || !tile->dataSize) continue;

				
                TileCacheHeader tileHeader;
                tileHeader.tileRef = mesh->getTileRef(tile);
                tileHeader.dataSize = tile->dataSize;
				
                fwrite(&tileHeader, sizeof(tileHeader), 1, fp);

                fwrite(tile->data, tile->dataSize, 1, fp);
        }

        fclose(fp);
}

Code: Select all

dtTileCache* OgreDetourTileCache::loadAllCache(const char* path)
{
        FILE* fp = fopen(path, "rb");
        if (!fp) return 0;
       
        // Read header.
        TileCacheSetHeader header;
        fread(&header, sizeof(TileCacheSetHeader), 1, fp);
        if (header.magic != NAVMESHSET_MAGIC)
        {
                fclose(fp);
                return 0;
        }
        if (header.version != NAVMESHSET_VERSION)
        {
                fclose(fp);
                return 0;
        }
       
        m_tileCache = dtAllocTileCache();
        if (!m_tileCache)
        {
                fclose(fp);
                return 0;
        }
		dtStatus status = m_tileCache->init(&header.params, m_talloc, m_tcomp, m_tmproc);
        if (dtStatusFailed(status))
        {
                fclose(fp);
                return 0;
        }
               
        // Read tiles.
        for (int i = 0; i < header.numTiles; ++i)
        {
                TileCacheHeader tileHeader;
                fread(&tileHeader, sizeof(tileHeader), 1, fp);
                if (!tileHeader.tileRef || !tileHeader.dataSize)
                        break;

                unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
                if (!data) break;
                memset(data, 0, tileHeader.dataSize);
                fread(data, tileHeader.dataSize, 1, fp);
               m_tileCache->addTile(data, tileHeader.dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0);
			  
        }
       
        fclose(fp);
       
        return m_tileCache;
}
usage for save;

Code: Select all

/InputGeom */mGeom = new InputGeom(mTerrainGroup,entities);
mDetourTileCache->TileCacheBuild(mGeom); 
mDetourTileCache->saveAll("./NavMeshCache/NavmeshTile.bin",m_navMesh);
mDetourTileCache->saveAllCache("./NavMeshCache/NavmeshTileCache.bin",mDetourTileCache->getTileCache());

for load;

Code: Select all

/InputGeom */mGeom = new InputGeom(mTerrainGroup,entities);
mDetourTileCache->configure(mGeom);
m_navMesh = mDetourTileCache->loadAll("./NavMeshCache/NavmeshTile.bin");
m_navQuery->init(m_navMesh, 2048);
mDetourTileCache->loadAllCache("./NavMeshCache/NavmeshTileCache.bin");

//and every frame.
areaToLoad.setMinimum(Ogre::Vector3(CameraPos.x-25,bmin[1],CameraPos.z-25));
areaToLoad.setMaximum(Ogre::Vector3(CameraPos.x+25,bmax[1],CameraPos.z+25));

mDetourTileCache->buildTilesLive(mGeom, &areaToLoad);  
Last edited by cbibejs on Wed Oct 03, 2012 3:27 pm, edited 1 time in total.
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by duststorm »

Thanks for sharing your solution.
I actually added functions for loading and saving all tiles a few days ago, check the bitbucket repo, the github one is a bit out of date (changed dev machine, git is not setup yet).
Bitbucket repo is the main one and will be most up to date.

Loading and unloading individual tiles is still todo, though.

Edit: I made an effort and github repo is back in sync :D
Last edited by duststorm on Wed Oct 03, 2012 3:31 pm, edited 1 time in total.
Developer @ MakeHuman.org
User avatar
cbibejs
Kobold
Posts: 31
Joined: Wed Feb 08, 2012 1:00 pm

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by cbibejs »

Oh i was looking the github all the time.I was a bit slow:(.Anyway thnx for your time.
User avatar
tod
Troll
Posts: 1394
Joined: Wed Aug 02, 2006 9:41 am
Location: Bucharest
x 94

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by tod »

I integrated OgreRecast into my project and I though that RecastInputGeometry needed some performance/readability improvements. What I did is to store vertices/indices/normals in std::vector and pass the underlying array further to recast. This also eliminates nverts and ntris, they are now relative to array sizes, and also a lot of dynamic allocation of arrays and some loops that where used to transform vertices to world (recast?) space and to move the vertices from some buffer to another. I think it is also possible to reuse InputGeometry object, to take advantage of the already allocated vectors and get rid of future allocation/reallocations.

This is not usable directly as I only update one constructor, the others can be updated in a similar fashion. Also some code reuse could be nice, as they are mostly copy pasted. It also uses my own GameEntity class, but can be easily modified (pass Ogre entities instead of GameEntities, for example). Also I only use one terrain, as I expect each navmesh to be included in a single terrain. Anyway, I though I'd share it with the interested parties.

RecastInputGeometry.cpp changes:

Code: Select all

void InputGeom::addMeshToVertexIndexArray(const Ogre::MeshPtr mesh, Ogre::Matrix4 transform)
{
	// this is the offset for all indexes of this mesh
	size_t mesh_offset = getVertCount();
	
	bool added_shared = false;
	size_t current_offset = mesh_offset;
	size_t shared_offset = mesh_offset;
	size_t next_offset = mesh_offset;
	

	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;

			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]);
				pt = transform * pt;
				mVertices.push_back(pt.x);
				mVertices.push_back(pt.y);
				mVertices.push_back(pt.z);
			}

			vbuf->unlock();
		}

		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)
			{
				mIndices.push_back(pLong[k] + static_cast<unsigned long>(offset));
			}
		}
		else
		{
			for ( size_t k = 0; k < numTris*3; ++k)
			{
				mIndices.push_back(static_cast<unsigned long>(pShort[k]) +
					static_cast<unsigned long>(offset));
			}
		}

		ibuf->unlock();
		current_offset = next_offset;
	}
};


InputGeom::InputGeom(const Ogre::AxisAlignedBox &tileBounds, Ogre::Terrain *trn, std::vector<GameEntity*> &entities)
    : bmin(0),
      bmax(0),
      m_offMeshConCount(0),
      m_volumeCount(0),
      m_chunkyMesh(0)
{
    
	// PARTS OF THE FOLLOWING CODE WERE TAKEN AND MODIFIED FROM AN OGRE3D FORUM POST

    // Set the area where the navigation mesh will be build to the tileBounds parameter.
    bmin = new float[3];
    bmax = new float[3];
    OgreRecast::OgreVect3ToFloatA(tileBounds.getMinimum(), bmin);
    OgreRecast::OgreVect3ToFloatA(tileBounds.getMaximum(), bmax);

    
    
	//---------------------------------------------------------------------------------
	// TERRAIN DATA BUILDING
	size_t trnCount = 0;

	// get height data, world size, map size
	float *mapptr = trn->getHeightData();
	float WorldSize = trn->getWorldSize();
	int MapSize = trn->getSize();
	// calculate where we need to move/place our vertices
	float DeltaPos = (WorldSize / 2.0f);

	 // Determine world offset position for this terrain tile
	 Ogre::AxisAlignedBox tileBox = trn->getWorldAABB();
	 float DeltaX = tileBox.getMinimum().x;
	 float DeltaZ = tileBox.getMaximum().z;

	 float Scale = WorldSize / (float)(MapSize - 1);

	// build vertices
	mVertices.reserve(MapSize*MapSize*3);

	 int max = MapSize; // i think i needed this for something before but now it's obviously redundant
	 int z = 0;
	 for(int x = 0;; ++x)
	 {
		 // if we've reached the right edge, start over on the next line
		 if(x == max)
		 {
			 x = 0;
			 ++z;
		 }
		 // if we reached the bottom/end, we're done
		 if(z == max)
			 break;

		 // add the vertex to the buffer
		 mVertices.push_back((Scale * x) + DeltaX);
		 mVertices.push_back(mapptr[(MapSize * z) + x]);
		 mVertices.push_back((Scale * -z) + DeltaZ);
	 }


	 // build indices
	 size_t size = ((MapSize*MapSize)-(MapSize*2)) * 6;
	 
	 mIndices.reserve(size);

	 for(int x = 0;;++x)
	 {
		 // skip rightmost vertices
		 if((x+1)%MapSize == 0)
		 {
			 ++x;
		 }

		 // make a square of 2 triangles
		 mIndices.push_back(x);
		 mIndices.push_back(x + 1);
		 mIndices.push_back(x + MapSize); 

		 mIndices.push_back(x + 1);
		 mIndices.push_back(x + 1 + MapSize);
		 mIndices.push_back(x + MapSize);

		 // if we just did the final square, we're done
		 if(x+1+MapSize == (MapSize*MapSize)-1)
			 break;

	 }

    //-----------------------------------------------------------------------------------------
    // ENTITY DATA BUILDING

    for(int i = 0; i < entities.size(); i++)
    {
		Ogre::Matrix4 transform;
		transform.makeTransform(entities[i]->getPosition(),Ogre::Vector3::UNIT_SCALE,entities[i]->getOrientation());
		Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().getByName (entities[i]->getClass()->getMeshName()+".mesh",ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME);
		
		addMeshToVertexIndexArray(mesh,transform);

    }

    //---------------------------------------------------------------------------------------------
    // RECAST **ONLY** NORMAL CALCS ( These are not used anywhere other than internally by recast)

	mNormals.resize(mIndices.size());

	for (int i = 0; i < mIndices.size(); i += 3)
	{
		const float* v0 = &mVertices[mIndices[i]];
		const float* v1 = &mVertices[mIndices[i+1]];
		const float* v2 = &mVertices[mIndices[i+2]];
		float e0[3], e1[3];
		for (int j = 0; j < 3; ++j)
		{
			e0[j] = (v1[j] - v0[j]);
			e1[j] = (v2[j] - v0[j]);
		}
		float* n = &mNormals[i];
		n[0] = ((e0[1]*e1[2]) - (e0[2]*e1[1]));
		n[1] = ((e0[2]*e1[0]) - (e0[0]*e1[2]));
		n[2] = ((e0[0]*e1[1]) - (e0[1]*e1[0]));

		float d = sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
		if (d > 0)
		{
			d = 1.0f/d;
			n[0] *= d;
			n[1] *= d;
			n[2] *= d;
		}	
	}


    // Build chunky tri mesh from triangles, used for tiled navmesh construction
    buildChunkyTriMesh();
}

int InputGeom::getVertCount()
{
    return mVertices.size()/3;
}

int InputGeom::getTriCount()
{
    return mIndices.size()/3;
}

int* InputGeom::getTris()
{
    return &mIndices[0];
}

float* InputGeom::getVerts()
{
    return &mVertices[0];
}

bool InputGeom::isEmpty()
{
    return getTriCount() <= 0 || getVertCount() <= 0;
}
RecastInputGeometry.h changes:

Code: Select all

 /**
      * Recast input vertices
      **/
	std::vector<float> mVertices;

    /**
      * Recast input tris
      * Tris are index references to verts array
      **/
	std::vector<int> mIndices;

    /**
      * Normals calculated for verts
      * Normals are not entirely accurate but good enough for recast use.
      * Size of the normals array is 3*nverts
      **/
	std::vector<float> mNormals;
lucky7456969
Gremlin
Posts: 156
Joined: Tue Sep 18, 2012 3:43 am

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by lucky7456969 »

It just can't get the source code to compile
src/OgrerecastApplication.h has a question mark on the project pane showing that the .h file is not found
I have put the source code in the OGRE folder where the system environment variable is pointing to.
Any help please?
Thanks
Jack
TheSHEEEP
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 972
Joined: Mon Jun 02, 2008 6:52 pm
Location: Berlin
x 65

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by TheSHEEEP »

Uhm... IDE? Compiler line? Anything that would help us help you? :)
My site! - Have a look :)
Also on Twitter - extra fluffy
lucky7456969
Gremlin
Posts: 156
Joined: Tue Sep 18, 2012 3:43 am

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by lucky7456969 »

TheSHEEEP wrote:Uhm... IDE? Compiler line? Anything that would help us help you? :)
Sorry, I am using VS2010. Let me know if you need further info.
Thanks
Jack
drwbns
Orc Shaman
Posts: 788
Joined: Mon Jan 18, 2010 6:06 pm
Location: Costa Mesa, California
x 24

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by drwbns »

Click the file with the ? and press ALT + ENTER, then change it's path to the appropriate path for the file. That should get rid of the ?
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by duststorm »

tod wrote:I integrated OgreRecast into my project and I though that RecastInputGeometry needed some performance/readability improvements.
Thanks for sharing this! :D

I agree that there is a serious performance penalty in the inputGeometry class, and that it can be optimized a lot. It also needs an aesthetic reworking.
I will try to incorporate your improvements into it in a future version.
Developer @ MakeHuman.org
User avatar
tod
Troll
Posts: 1394
Joined: Wed Aug 02, 2006 9:41 am
Location: Bucharest
x 94

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by tod »

duststorm wrote: Thanks for sharing this! :D

I agree that there is a serious performance penalty in the inputGeometry class, and that it can be optimized a lot. It also needs an aesthetic reworking.
I will try to incorporate your improvements into it in a future version.
Glad you found it useful. PM me if you have questions. I also managed to only feed recast the terrain triangles that are in the bounding box (I use only one terrain, and I always suppose any navigation mesh is included in it, but I think it may work with more terrains, if my calculations are correct, but I wouldn't bet on it :) ). By the way, I am trying to regenerate navigation tiles at runtime, from Ogre geometry when some entities are destroyed, do you think this could work? Regarding performance I mean.

Code: Select all

	//---------------------------------------------------------------------------------
	// TERRAIN DATA BUILDING
	size_t trnCount = 0;

	// get height data, world size, map size
	float *mapptr = trn->getHeightData();
	float WorldSize = trn->getWorldSize();
	int MapSize = trn->getSize();
	// calculate where we need to move/place our vertices
	float DeltaPos = (WorldSize / 2.0f);

	 // Determine world offset position for this terrain tile
	 Ogre::AxisAlignedBox trnBox = trn->getWorldAABB();
	 float DeltaX = trnBox.getMinimum().x;
	 float DeltaZ = trnBox.getMaximum().z;

	 float Scale = WorldSize / (float)(MapSize - 1);

	// build vertices
	int maxX = (tileBounds.getMaximum().x + Scale < trnBox.getMaximum().x)? MapSize - (trnBox.getMaximum().x - tileBounds.getMaximum().x)/ Scale:MapSize - 1;
	int maxZ = (tileBounds.getMaximum().z + Scale < trnBox.getMaximum().z)? MapSize - (trnBox.getMaximum().z - tileBounds.getMaximum().z)/ Scale:MapSize - 1;
	int minX = (tileBounds.getMinimum().x > trnBox.getMinimum().x)?((tileBounds.getMinimum().x - trnBox.getMinimum().x) / Scale):0;
	int minZ = (tileBounds.getMinimum().z > trnBox.getMinimum().z)?((tileBounds.getMinimum().z - trnBox.getMinimum().z) / Scale):0;
	 
	 mVertices.reserve((maxX-minX +1)*(maxZ-minZ + 1)*3);

	 //Ogre::ManualObject *rahat =  GameManager::getSingleton().getSceneMgr()->createManualObject("onerahat");
	 //rahat->begin("recastdebug", Ogre::RenderOperation::OT_TRIANGLE_LIST) ;
		 for(int z = MapSize - maxZ; z <= MapSize - minZ; z++)
		 {
			 for(int x = minX; x <= maxX ; x++)
			 {			
				 mVertices.push_back((Scale * x) + DeltaX);
				 mVertices.push_back(mapptr[(MapSize * z) + x]);
				 mVertices.push_back((Scale * -z) + DeltaZ);
				 //rahat->position((Scale * x) + DeltaX, mapptr[(MapSize * z) + x] + 3.0,(Scale * -z) + DeltaZ);
				 //rahat->colour(Ogre::ColourValue::Red);
			 }
		 }
	

	 // build indices
	 size_t size = ((maxX-minX)*(maxZ-minZ)) * 6;
	 
	 mIndices.reserve(size);

	 for(int x = 0 ; x < (maxX-minX + 1)*(maxZ-minZ);++x)
	 {
		 if(x && (x + 2)%(maxX-minX + 1) == 0) 
		 {	
			 x++;
			 continue;
		 }
		 // make a square of 2 triangles
		 mIndices.push_back(x);
		 mIndices.push_back(x + 1);
		 mIndices.push_back(x + maxX - minX + 1); 

		 mIndices.push_back(x + 1);
		 mIndices.push_back(x + 1 + maxX - minX + 1);
		 mIndices.push_back(x + maxX - minX + 1);
		 
		 //rahat->triangle(x,x + 1, x + maxX - minX + 1);
		 //rahat->triangle(x + 1,x + 1 + maxX - minX + 1, x + maxX - minX + 1);
		

	 }

	 //rahat->end();
	 //GameManager::getSingleton().getSceneMgr()->getRootSceneNode()->createChildSceneNode()->attachObject(rahat);
User avatar
nevarim
Gnoll
Posts: 675
Joined: Mon Jul 05, 2010 6:16 pm
Location: Pavia Italy
x 4

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by nevarim »

a simple question: if i use heightmaps how i can decide where are walking place?


thanks

Nevarim
i'm a noob until proven otherwise :D
used in my project ;) and thanks to everyone :D
Ogre 3d
Mygui
Skyx
Hydrax
MOC
CCS
User avatar
tod
Troll
Posts: 1394
Joined: Wed Aug 02, 2006 9:41 am
Location: Bucharest
x 94

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by tod »

I don't think Recast can handle heightmaps directly, you will have to feed it the terrain geometry you created from the heightmap.
User avatar
nevarim
Gnoll
Posts: 675
Joined: Mon Jul 05, 2010 6:16 pm
Location: Pavia Italy
x 4

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by nevarim »

so first i have to create geometry from heightmap and then give it to crowd?
i'm a noob until proven otherwise :D
used in my project ;) and thanks to everyone :D
Ogre 3d
Mygui
Skyx
Hydrax
MOC
CCS
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by duststorm »

nevarim wrote:a simple question: if i use heightmaps how i can decide where are walking place?
I you mean feeding heightmap data to recast, you need to generate triangles form the heightmap data in some way.
Since there is already an adaptation for Ogre::Terrain you could load the heightmaps with that and feed the terrain tiles to recast.

It might also be possible to create voxel data from the heightmap, and feed that directly to recast, but that would take a lot more work to get right.
Developer @ MakeHuman.org
ShortBus
Gnoblar
Posts: 8
Joined: Sun Jun 10, 2012 7:36 pm

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by ShortBus »

Hey there.

This component is fantastic, should be included in future releases of Ogre! However, I got a (hopefully) simple question:

Is there any way to add new input geometry to the already generated mesh? The reason I'm asking is because I got a paged terrain and I'd like the navmesh to be rebuilt for each page individually.

Thank you in advance!
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by Blender+C++ »

Hello guys,
I've been Reading the Recast and Detour lib for a while, and i decided to take a step ahead before i finish Reading and then create a sample out of the rc and dt source, so i just edited the ogrerecastterrainapplication.cpp and then added my own terrain built with artifex terra 3d a while ago,and also edited the characteranimatable.cpp file and added my own character ,also a few more things,well it worked when i left the terrain size to 1025 and the terrain world size to 12000.0f however if i leave that size of my artifex imported terrain ,it will look strechy in terms of height map, the mountains and some other stuff will be streched out since the standard arfifex terrain world size is 5000.0f,which is the size i use to load it, so the thing is if i set the terrain world size to 5000.0f the navmesh wont cover all the terrain areas and will look a little buggy like in the Picture below :
Image

Uploaded with ImageShack.us

and im pretty sure my code is correct as you all can see :

Code: Select all

 mDetourTileCache = new OgreDetourTileCache(mRecast, 72);
        mDetourTileCache->configure(mGeom);
        Ogre::AxisAlignedBox areaToLoad;
        areaToLoad.setMinimum(mGeom->getBoundingBox().getMinimum());
        areaToLoad.setMaximum(mGeom->getBoundingBox().getMaximum());

        mDetourTileCache->buildTiles(mGeom, &areaToLoad);    
i know i could use the other way of building it but both ways wont work.....any clue of why this is happening? i want to have the navmesh for the entire terrain,just like when i leave the terrain world size in 12000.0f...
any help here is greatly appreciated and i look forward for repies!
Kind regards,
Romulo Romero

PS: Thanks cbibejs and Tod for sharing your implementations!!
i will add the save and load feature later as soon as i get my problem sorted :d
TheSHEEEP
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 972
Joined: Mon Jun 02, 2008 6:52 pm
Location: Berlin
x 65

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by TheSHEEEP »

So it does work with a terrain of size 12k but not 5k?
Have you tried numbers in between to see if there is a "breaking point"?

I guess you'll have to debug the recast/detour itself to see when things break in there.
There is also a google group for recast (the "official" forum), did you ask there? I'd imagine they may know more about it than people here.
My site! - Have a look :)
Also on Twitter - extra fluffy
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by Blender+C++ »

TheSHEEEP wrote:So it does work with a terrain of size 12k but not 5k?
Have you tried numbers in between to see if there is a "breaking point"?

I guess you'll have to debug the recast/detour itself to see when things break in there.
There is also a google group for recast (the "official" forum), did you ask there? I'd imagine they may know more about it than people here.

Hi TheSHEEEP first of all i appreciate your reply, and about the numbers attempts , yeah i have already tried several range of number but they all seem to result in the same navesh mesh drawn area, pretty weird actually..i sent DustStorm a pm lets see if he knows how to fix it but meanwhile i will take a look at the oficial forums and see if i can get any help from there!
thanks The SHEEEP and i look forward for more replies here in this thread :D
Kind regards,
Romulo Romero
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by Blender+C++ »

Hi folks,

im sorry bout bothering you but i found where the problem was, i had to fix it in the inputgeometry.cpp file these lines(i tried the ogre recast forums but Mikko also didnt detect where the issue was located at..then based on the navmesh geom i thought the problem could be related to the geom so..) :


Code: Select all

// TODO this hardcoded behaviour has to go! Supports only up to 4 terrain pages
switch(trnCount)
{
case 0:
DeltaX = -2500;
DeltaZ = 2500;
break;
case 1:
DeltaX = -2500;
DeltaZ = -2500;
break;
case 2:
DeltaX = 2500;
DeltaZ = 2500;
break;
case 3:
DeltaX = 2500;
DeltaZ = -2500;
break;
DeltaX = 0;
DeltaZ = 0;
}



they were set to -6000 and 6000 which explains why it was workin on a terrain size of 12000.0f hehe :D

i hope this can help someone else who may face the same problem!!

Thanks alot!

Kind regards,

Romulo Romero
drwbns
Orc Shaman
Posts: 788
Joined: Mon Jan 18, 2010 6:06 pm
Location: Costa Mesa, California
x 24

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by drwbns »

I'm sure there's a function to get the terrain size to pass that instead of the hardcoded 12000f. Just a thought...
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by Blender+C++ »

drwbns wrote:I'm sure there's a function to get the terrain size to pass that instead of the hardcoded 12000f. Just a thought...
Hi drwbns ,
Yeah it might have it but as i still consider myself a newbie and i havent studied all the recast and detour files, theres still a lot to learn from it ,but i have a general idea of how it Works already thats why i decided to build a sample out of it ...actually edited some files and the crwd sample file ^^
but if you find any function(before i finish Reading all the files) which gets the terrain size let us know please :D
All the best,
Romulo Romero
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by Blender+C++ »

Ok here i go again,
another error but this time it seems to be a little more complicated, ok i have a scene saved in a scene.scene file so what im trying to do is to generate first the navmesh geometry for the terrain and then right after its done,load the scene so when it starts creating the entities(scene objects like rocks ,trees etc..)right after the creation of every entity i want to get my geometry updated and recreate the recast input geometry data with terrain and all extra entities, however im having a little problem while doing that, it updates most of it but it crashes almost at the end of the scene objects..so what i noticed is that it usually crashes at the objects which their bounding boxes are inside another bb,usually for example a small plant bb inside a rock bb, the plants are very close to the rock almost touching it...i think this is the reason why its crashing...
the file that throws the exption is the throw.cpp and in this line :

Code: Select all

    // Hand it off to the OS:
        //

        EHTRACE_EXIT;
#if defined(_M_X64) && defined(_NTSUBSET_)
        RtlRaiseException( (PEXCEPTION_RECORD) &ThisException );
#else
        RaiseException( ThisException.ExceptionCode,
                        ThisException.ExceptionFlags,
                        ThisException.NumberParameters,
                        (PULONG_PTR)&ThisException.params );
#endif
}
so i tried a work around such as merging bounding boxes which intersects with each other like this :

Code: Select all

Ogre::AxisAlignedBox bb = InputGeom::getWorldSpaceBoundingBox(ent);
						if(bb.intersects(ent->getBoundingBox()))
							bb.merge(ent->getBoundingBox());
but to no avail, so the reason why i came to this conclusion is that when i added these lines :

Code: Select all

Ogre::AxisAlignedBox bb = InputGeom::getWorldSpaceBoundingBox(ent);
if(mGeom)
	delete mGeom;					
// Recreate recast input geometry data with terrain and all extra entities
mGeom = new InputGeom(mTerrainGroup, mNavmeshEnts);
							
if(bb.intersects(ent->getBoundingBox()))
   return;
// Rebuild tiles that touch bounding box
mDetourTileCache->updateFromGeometry(mGeom, &bb);
(i might be completely wrong but so far thats what i have in mind), so after doing something like the above i cant remember cause i already removed the code so this is what i can recall, then it rendered the scene "without a problem" however the entities which were intersecting with each other were not created since the node creation comes after the scope above..so it returns to the next entity before creating the node for the previous entity ,so thats why i think the issue kind of got to do with the entities bounding boxes and its geometries at the bottom!!
i hope any of you guys can help me out with this cause i spent a whole day yesterday up to 4AM trying to solve that problem and im stuck!!
any help is greatly appreciated !!!!!!!
All the best,
Romulo Romero
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by Blender+C++ »

ok so I was debugging it and set a couple of break points then checked to see where exactly it was crashing then this is the line :

Code: Select all

mGeom = new InputGeom(mTerrainGroup, mNavmeshEnts);
it seems to be something with memory allocation...maybe a memset issue..not sure..=(
HELP please ;(
thanks in advance for any reply!
Romulo Romero
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: OgreCrowd: a crowd component for Ogre using Recast/Detou

Post by Blender+C++ »

Hi guys i want to provide more details this time...

so i have the call stack sequence before the error occurrs and till it happens..

so here are the pictures sequence :

http://i1179.photobucket.com/albums/x40 ... uence1.jpg
http://i1179.photobucket.com/albums/x40 ... uence2.jpg
http://i1179.photobucket.com/albums/x40 ... uence3.jpg
http://i1179.photobucket.com/albums/x40 ... uence4.jpg
http://i1179.photobucket.com/albums/x40 ... uence5.jpg
http://i1179.photobucket.com/albums/x40 ... uence6.jpg


its in order, so it starts trying to build a chuncky tri mesh but then...it seems to be a bad memory allocation or maybe it runs out of memory...so i hope this time i can get some help with all those details!

Thanks in advance,

Romulo Romero