void AwarenessVisualizer::createRecastPolyMesh(const std::string& name, const unsigned short *verts, const int nverts, const unsigned short *polys, const int npolys, const unsigned char *areas, const int maxpolys, const unsigned short *regions, const int nvp, const float cs, const float ch, const float *orig, bool colorRegions) { // Demo specific parameters float m_navMeshOffsetFromGround = 0.2; //ch / 5; // Distance above ground for drawing navmesh polygons float m_navMeshEdgesOffsetFromGround = 0.5; //ch / 3; // Distance above ground for drawing edges of navmesh (should be slightly higher than navmesh polygons) // float m_pathOffsetFromGround = 1 + m_navMeshOffsetFromGround; // Distance above ground for drawing path debug lines relative to cellheight (should be higher than navmesh polygons) // Colors for navmesh debug drawing static Ogre::ColourValue m_navmeshNeighbourEdgeCol(0.9, 0.9, 0.9); // Light Grey static Ogre::ColourValue m_navmeshOuterEdgeCol(0, 0, 0); // Black static Ogre::ColourValue m_navmeshGroundPolygonCol(0, 0.7, 0); // Green static Ogre::ColourValue m_navmeshOtherPolygonCol(0, 0.175, 0); // Dark green static Ogre::ColourValue m_pathCol(1, 0, 0); // Red // When drawing regions choose different random colors for each region Ogre::ColourValue* regionColors = NULL; if (colorRegions) { regionColors = new Ogre::ColourValue[maxpolys]; for (int i = 0; i < maxpolys; ++i) { regionColors[i] = Ogre::ColourValue(Ogre::Math::RangeRandom(0, 1), Ogre::Math::RangeRandom(0, 1), Ogre::Math::RangeRandom(0, 1), 1); } } int nIndex = 0; if (npolys) { // start defining the manualObject with the navmesh planes Ogre::ManualObject* pRecastMOWalk; if (mSceneManager.hasManualObject("RecastMOWalk_" + name)) { pRecastMOWalk = mSceneManager.getManualObject("RecastMOWalk_" + name); pRecastMOWalk->clear(); } else { pRecastMOWalk = mSceneManager.createManualObject("RecastMOWalk_" + name); //Remove from the overhead map. pRecastMOWalk->setVisibilityFlags(pRecastMOWalk->getVisibilityFlags() & ~Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK); mTileSceneNode->attachObject(pRecastMOWalk); } pRecastMOWalk->begin("/common/base/authoring/awareness", Ogre::RenderOperation::OT_TRIANGLE_LIST); for (int i = 0; i < npolys; ++i) { // go through all polygons if (areas[i] == Navigation::POLYAREA_GROUND || areas[i] == DT_TILECACHE_WALKABLE_AREA) { const unsigned short* p = &polys[i * nvp * 2]; unsigned short vi[3]; for (int j = 2; j < nvp; ++j) // go through all verts in the polygon { if (p[j] == RC_MESH_NULL_IDX) break; vi[0] = p[0]; vi[1] = p[j - 1]; vi[2] = p[j]; for (int k = 0; k < 3; ++k) // create a 3-vert triangle for each 3 verts in the polygon. { const unsigned short* v = &verts[vi[k] * 3]; const float x = orig[0] + v[0] * cs; const float y = orig[1] + (v[1]/*+1*/) * ch; const float z = -orig[2] - v[2] * cs; pRecastMOWalk->position(x, y + m_navMeshOffsetFromGround, z); if (colorRegions) { pRecastMOWalk->colour(regionColors[regions[i]]); // Assign vertex color } else { if (areas[i] == Navigation::POLYAREA_GROUND) pRecastMOWalk->colour(m_navmeshGroundPolygonCol); else pRecastMOWalk->colour(m_navmeshOtherPolygonCol); } } pRecastMOWalk->triangle(nIndex, nIndex + 2, nIndex + 1); nIndex += 3; } } } pRecastMOWalk->end(); // Define manualObject with the navmesh edges between neighbouring polygons Ogre::ManualObject* pRecastMONeighbour; if (mSceneManager.hasManualObject("RecastMONeighbour_" + name)) { pRecastMONeighbour = mSceneManager.getManualObject("RecastMONeighbour_" + name); pRecastMONeighbour->clear(); } else { pRecastMONeighbour = mSceneManager.createManualObject("RecastMONeighbour_" + name); //Remove from the overhead map. pRecastMONeighbour->setVisibilityFlags(pRecastMONeighbour->getVisibilityFlags() & ~Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK); mTileSceneNode->attachObject(pRecastMONeighbour); } pRecastMONeighbour->begin("/common/base/authoring/awareness", Ogre::RenderOperation::OT_LINE_LIST); for (int i = 0; i < npolys; ++i) { const unsigned short* p = &polys[i * nvp * 2]; for (int j = 0; j < nvp; ++j) { if (p[j] == RC_MESH_NULL_IDX) break; if (p[nvp + j] == RC_MESH_NULL_IDX) continue; int vi[2]; vi[0] = p[j]; if (j + 1 >= nvp || p[j + 1] == RC_MESH_NULL_IDX) vi[1] = p[0]; else vi[1] = p[j + 1]; for (int k = 0; k < 2; ++k) { const unsigned short* v = &verts[vi[k] * 3]; const float x = orig[0] + v[0] * cs; const float y = orig[1] + (v[1]/*+1*/) * ch /*+ 0.1f*/; const float z = -orig[2] - v[2] * cs; //dd->vertex(x, y, z, coln); pRecastMONeighbour->position(x, y + m_navMeshEdgesOffsetFromGround, z); pRecastMONeighbour->colour(m_navmeshNeighbourEdgeCol); } } } pRecastMONeighbour->end(); // Define manualObject with navmesh outer edges (boundaries) Ogre::ManualObject* pRecastMOBoundary; if (mSceneManager.hasManualObject("RecastMOBoundary_" + name)) { pRecastMOBoundary = mSceneManager.getManualObject("RecastMOBoundary_" + name); pRecastMOBoundary->clear(); } else { pRecastMOBoundary = mSceneManager.createManualObject("RecastMOBoundary_" + name); //Remove from the overhead map. pRecastMOBoundary->setVisibilityFlags(pRecastMOBoundary->getVisibilityFlags() & ~Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK); mTileSceneNode->attachObject(pRecastMOBoundary); } pRecastMOBoundary->begin("/common/base/authoring/awareness", Ogre::RenderOperation::OT_LINE_LIST); for (int i = 0; i < npolys; ++i) { const unsigned short* p = &polys[i * nvp * 2]; for (int j = 0; j < nvp; ++j) { if (p[j] == RC_MESH_NULL_IDX) break; if (p[nvp + j] != RC_MESH_NULL_IDX) continue; int vi[2]; vi[0] = p[j]; if (j + 1 >= nvp || p[j + 1] == RC_MESH_NULL_IDX) vi[1] = p[0]; else vi[1] = p[j + 1]; for (int k = 0; k < 2; ++k) { const unsigned short* v = &verts[vi[k] * 3]; const float x = orig[0] + v[0] * cs; const float y = orig[1] + (v[1]/*+1*/) * ch /*+ 0.1f*/; const float z = -orig[2] - v[2] * cs; //dd->vertex(x, y, z, colb); pRecastMOBoundary->position(x, y + m_navMeshEdgesOffsetFromGround, z); pRecastMOBoundary->colour(m_navmeshOuterEdgeCol); } } } pRecastMOBoundary->end(); // if (STATIC_GEOM_DEBUG) { // // Render navmesh tiles more efficiently using staticGeometry // // // Early out if empty meshes drawn // if (m_pRecastMOWalk->getNumSections() == 0) // return; // // if (!m_sg) { // m_sg = m_pSceneMgr->createStaticGeometry("NavmeshDebugStaticGeom"); // Ogre::Vector3 bmin; // Ogre::Vector3 bmax; // Ogre::Vector3 bsize; // FloatAToOgreVect3(m_cfg.bmin, bmin); // FloatAToOgreVect3(m_cfg.bmax, bmax); // bsize = bmax - bmin; // m_sg->setRegionDimensions(bsize); // m_sg->setOrigin(bmin); // } // // m_pRecastMOWalk->convertToMesh("mesh_" + m_pRecastMOWalk->getName()); // Ogre::Entity *walkEnt = m_pSceneMgr->createEntity("ent_" + m_pRecastMOWalk->getName(), "mesh_" + m_pRecastMOWalk->getName()); // m_sg->addEntity(walkEnt, Ogre::Vector3::ZERO); // //// TODO line drawing does not work with staticGeometry // if (false && m_pRecastMONeighbour->getNumSections() > 0) { // m_pRecastMONeighbour->convertToMesh("mesh_" + m_pRecastMONeighbour->getName()); // Creating meshes from manualobjects without polygons is not a good idea! // Ogre::Entity *neighbourEnt = m_pSceneMgr->createEntity("ent_" + m_pRecastMONeighbour->getName(), "mesh_" + m_pRecastMONeighbour->getName()); // m_sg->addEntity(neighbourEnt, Ogre::Vector3::ZERO); // } // // if (false && m_pRecastMOBoundary->getNumSections() > 0) { // m_pRecastMOBoundary->convertToMesh("mesh_" + m_pRecastMOBoundary->getName()); // Ogre::Entity *boundaryEnt = m_pSceneMgr->createEntity("ent_" + m_pRecastMOBoundary->getName(), "mesh_" + m_pRecastMOBoundary->getName()); // m_sg->addEntity(boundaryEnt, Ogre::Vector3::ZERO); // } // // // Set dirty flag of solid geometry so it will be rebuilt next update() // m_rebuildSg = true; // } else { // Add manualobjects directly to scene (can be slow for lots of tiles) // } } // end areacount delete[] regionColors; }