Time to give back to the community.
Here's a little class, inspired from this topic that I wrote for the current Terrain system.
For now, there is one known issue that I don't have time to solve: the class doesn't work with YZ alignment.
Any comments, advice and criticism is welcome.
Header:
Code: Select all
// OgreTerrainGrip.h v0.1
// This source file is supposed to be used with OGRE
// (Object-oriented Graphics Rendering Engine)
// For the latest info, see http://www.ogre3d.org/
// Copyright © 2014 Alain BAREILLE <firstname . name [AT] free.fr>
// This work is free. You can redistribute it and/or modify it under the
// terms of the Do What The Fuck You Want To Public License, Version 2,
// as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
#ifndef TERRAIN_GRID_H
#define TERRAIN_GRID_H
/// default value passed to constructor
#define DEFAULT_GRID_CELL_SIZE (Ogre::Real(1))
/// default value passed to constructor
#define DEFAULT_DISTANCE_FROM_TERRAIN (Ogre::Real(0.1))
namespace Ogre
{
class SceneManager;
class ManualObject;
class TerrainGroup;
}
/** The whole point of the pudding.
* Encapsulates a manual object that defines a grid geometry following the shape
* of an Ogre::Terrain.
*/
class TerrainGrid
{
public:
/** Constructor.
* Draws the geometry.
* \param grid_name a name for encapsulated manual object, must be unique
* \param material_name material applied to grid
* \param terrain_group group our target terrain is part of
* \param terrain_x coordinate of target terrain in terrain_group
* \param terrain_y coordinate of target terrain in terrain_group
* \param cell_size size in world units of the cells of the generated grid
* \param distance_from_terrain grid to terrain distance along the axis orthogonal \
* to alignment of terrain_group \see Ogre::TerrainGroup::getAlignment()
* \param offset grid start offset on both axis in world units
* \throws pretty much whatever Ogre or the STL want to throw
*/
TerrainGrid(const Ogre::String & grid_name,
const Ogre::String & material_name,
const Ogre::TerrainGroup * terrain_group,
long terrain_x, long terrain_y,
Ogre::Real cell_size = DEFAULT_GRID_CELL_SIZE,
Ogre::Real distance_from_terrain = DEFAULT_DISTANCE_FROM_TERRAIN,
Ogre::Real offset = 0);
/** Destructor.
* Collects allocated ressources.
*/
~TerrainGrid();
/// access encapsulated geometry
Ogre::ManualObject & grid() {return *mGrid;}
/// access encapsulated geometry
const Ogre::ManualObject & grid() const {return *mGrid;}
private:
/// Reference to scene manager, used at destruction to collect manual object
Ogre::SceneManager * const mSceneManager;
/// Manual object containing the grid geometry
Ogre::ManualObject * const mGrid;
/// Waiting for C++11
TerrainGrid(const TerrainGrid&);
};
#endif
Code: Select all
// OgreTerrainGrip.cpp v0.1
// This source file is supposed to be used with OGRE
// (Object-oriented Graphics Rendering Engine)
// For the latest info, see http://www.ogre3d.org/
// Copyright © 2014 Alain BAREILLE <firstname . name [AT] free.fr>
// This work is free. You can redistribute it and/or modify it under the
// terms of the Do What The Fuck You Want To Public License, Version 2,
// as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
#include <sstream>
#include <OgreManualObject.h>
#include <Terrain/OgreTerrainGroup.h>
#include "OgreTerrainGrid.h"
using Ogre::Real;
using Ogre::String;
using Ogre::Vector3;
using Ogre::SceneManager;
using Ogre::SceneNode;
using Ogre::Terrain;
using Ogre::TerrainGroup;
typedef Vector3 (*TerrainToWorldFunction)(Real u, Real v, Real height);
static Vector3 XZAlignement(Real u, Real v, Real height)
{
return Vector3(u, height, -v);
}
static Vector3 XYAlignement(Real u, Real v, Real height)
{
return Vector3(u, v, height);
}
static Vector3 YZAlignement(Real u, Real v, Real height)
{
return Vector3(height, v, -u);
}
static TerrainToWorldFunction terrainToWorldFunctionFactory(Terrain::Alignment alignment)
{
switch(alignment)
{
case Terrain::ALIGN_X_Z:
return &XZAlignement;
case Terrain::ALIGN_X_Y:
return &XYAlignement;
case Terrain::ALIGN_Y_Z:
return &YZAlignement;
}
return NULL;
}
TerrainGrid::TerrainGrid(const Ogre::String & grid_name,
const Ogre::String & material_name,
const TerrainGroup * terrain_group,
long terrain_x, long terrain_y,
Real cell_size,
Real distance_from_terrain,
Real offset)
: mSceneManager(terrain_group->getSceneManager())
, mGrid(mSceneManager->createManualObject(grid_name))
{
Terrain * terrain = terrain_group->getTerrain(terrain_x, terrain_y);
OgreAssert(terrain, "Trying to access unloaded terrain");
if(NULL == terrain)
{
Ogre::StringUtil::StrStreamType desc;
desc << "Trying to access unloaded terrain at ("
<< terrain_x << ',' << terrain_y << ')';
throw Ogre::InvalidParametersException(0xE2202,
desc.str(),
"Ogre::TerrainGrid::TerrainGrid",
__FILE__,
__LINE__);
}
const Real world_size = terrain->getWorldSize();
if(cell_size > world_size)
{
// do nothing
return;
}
const Real high_bound = (Real(terrain_x) + Real(0.5)) * world_size;
const Real low_bound = high_bound - world_size + offset;
mGrid->begin(material_name, Ogre::RenderOperation::OT_LINE_LIST);
TerrainToWorldFunction func = terrainToWorldFunctionFactory(terrain_group->getAlignment());
for(Real i = low_bound; i < high_bound; i += cell_size)
{
for(Real j = low_bound; j < high_bound; j += cell_size)
{
const Real next_i = i + cell_size;
const Real next_j = j + cell_size;
mGrid->position(func(i, j, terrain->getHeightAtWorldPosition(func(i, j , 0))));
mGrid->position(func(next_i, j, terrain->getHeightAtWorldPosition(func(next_i, j , 0))));
mGrid->position(func(i, j, terrain->getHeightAtWorldPosition(func(i, j , 0))));
mGrid->position(func(i, next_j, terrain->getHeightAtWorldPosition(func(i, next_j, 0))));
}
}
mGrid->end();
mSceneManager->getRootSceneNode()->createChildSceneNode(func(0, 0, distance_from_terrain))->attachObject(mGrid);
}
TerrainGrid::~TerrainGrid()
{
mSceneManager->destroyManualObject(mGrid);
}