History: Peter's Grid System
Source of version: 17
Copy to clipboard
!! Introduction
After some digging around about grid systems and trying ((EditorGridSystem|Jeroen Dierckx's EditorGridSystem)), We decided to write our own grid system with different feature set and release it to the community, because Ogre is si cool.
{maketoc}
!! Screenshots
||{img fileId="2182" thumb="y" width="400" rel="box[g]"}|{img fileId="2183" thumb="y" width="400" rel="box[g]"}
{img fileId="2185" thumb="y" width="400" rel="box[g]"}|{img fileId="2184" thumb="y" width="400" rel="box[g]"}||
!! Features
Following features are supported by Peter's Grid System:
* This grid have three planes support - XY, XZ, YZ that can be visible/hidden
* Grid is generated/updated by request, uses ManualObject
* Limitations in each dimension
* Cell size per dimension
* Grid Offset
* Colors for offset, master and division axis,
* Does NOT depend from the camera type used,
* Not limited to one instance (no named items used!)
* Not built in, the Snap to grid feature's code is in this wiki page
!! Usage
First, get the source from below and just add __OgreGrid.cpp__ in your project. Include __OgreGrid.h__ and enjoy.
To create a grid, just create an instance of the {MONO()}OgreGrid{MONO} class and set the properties you want to, then call {MONO()}update(){MONO}
{FADE(label="View C++ code")}
{CODE(wrap="1", colors="c++")}
/*OgreGrid*/ grid = new OgreGrid(/*Ogre::SceneManager*/scene, /*Material name*/"BaseWhiteAlphaBlended");
//Where to draw the grid?
grid->drawQueue = Ogre::RENDER_QUEUE_OVERLAY;
//Attach it to some SceneNode
grid->attachToNode(scene->getRootSceneNode());
//Some grid settings
grid->setCellSize(0.5);
grid->ymin = -9;
grid->ymax = 2;
grid->ofY = 2;
grid->zmin = -2;
grid->zmax = 1;
grid->showXZ = true;
grid->showXY = true;
grid->showYZ = true;
grid->setDivisions(10);
grid->colorDivision = Ogre::ColourValue(0,1,0,0.3);
grid->colorOffset = Ogre::ColourValue(0,0,1,1);
grid->colorMaster = Ogre::ColourValue(1,0,0,0.7);
//Regenerate the grid
grid->update();
{CODE}
{FADE}
!! Options
After creating an instance to the grid class, you can set the options of the grid you want to. After you change option, you must call {MONO()}update(){MONO} to update the grid manually. All options are public data members with the exception of some convenience setters.
!!!!Cell sizes
{MONO()}float csX, csY, csZ{MONO} are used to control the master grid axes distance, per dimaneion. You may have a grid with cell size 2x1 in the X/Y dimension. You can use grid sizes such as 0.5x0.5. You can also use {MONO()}setCellSize(float size){MONO} and {MONO()}setCellSize(float x, float y, float z){MONO} for this purpose.
!!!!Zero offset
{MONO()}float ofX, ofY, ofZ{MONO} are used to move the center of the grid in each dimension. You can also use {MONO()}setOffset(float x, float y, float z){MONO}
!!!!Division count
{MONO()}int divX, divY, divZ{MONO} are used to set the count of subdivisions in each dimension. You can also use {MONO()}setDivisions(int n){MONO} and {MONO()}setDivisions(int x,int y,int z){MONO} for this purpose. To show or hide the divisions and use only the master axes, set {MONO()}bool showDivisions{MONO}
!!!!Grid range limitations
Our grid is limited to certain values in each division. If axis is limited from -5 to +5, only these cells that are in this range will be drawn for the given dimension. Limitations are set via {MONO()}int xmin, xmax, ymin, ymax, zmin, zmax{MONO}. Note that the default limitations are from -5 to +5, and the system does not support infinite grids still. In the future, I may decide to implement infinite planes. Also, setting huge limitations will generate too much lines and may affect performance, especially if there are too much divisions, as well. If you want infinite 2D grid, you should consider ((EditorGridSystem|Jeroen Dierckx's EditorGridSystem)) instead.
!!!!Shown planes
You can set which grid plane is drawn by setting {MONO()}bool showXY, showXZ, showYZ{MONO} as you like. By default, only the XY plane is shown. You can also use {MONO()}showPlanes(bool xy, bool xz, bool yz){MONO} for this purpose.
!!!!Colors
* {MONO()}colorMaster{MONO} - The color of master lines. Master lines are drawn each cell size units.
* {MONO()}colorOffset{MONO} - The color of the offset lines, e.g. these that pass thru (0,0,0)+Grid's offset
* {MONO()}colorDivision{MONO} - The color of the division lines. You usually want to set lighter color for these.
Please note that the default material, "BaseWhiteNoLighting", does not support alpha from the vertex colors. Peter's Grid System uses vertex colors for grid lines color, and all this is within 1 section in 1 ManualObject. If you want alpha, you can use the following material:
{FADE(label="View material")}
{CODE(wrap="1", colors="C++")}
material "BaseWhiteAlphaBlended"
{
receive_shadows on
transparency_casts_shadows off
technique
{
lod_index 0
scheme Default
pass
{
lighting off
max_lights 8
start_light 0
iteration once
point_size 4
point_sprites off
point_size_attenuation off
point_size_min 0
point_size_max 0
scene_blend alpha_blend
depth_check on
alpha_rejection always_pass 0
alpha_to_coverage off
transparent_sorting on
depth_write on
depth_func less_equal
depth_bias 0 0
iteration_depth_bias 0
light_scissor off
light_clip_planes off
cull_hardware clockwise
cull_software back
shading gouraud
polygon_mode solid
polygon_mode_overrideable on
normalise_normals off
fog_override false
}
}
}
{CODE}
{FADE}
!! Other notes
If you want just to set the grid's offset, you may directly set the position of the {MONO()}mOwnNode{MONO}. If you call update(), this will be lost, however. This way, it's faster that setting the offset and updating, as it didn't regenerate the grid. You may also need the global transform of mOwnNode.
If you want to snap something to the grid, you can use the following code (only snaps to master lines):
{FADE(label="Snap this C++ code to the grid...")}
{CODE(wrap="1", colors="C++")}
Ogre::Vector3 r = /*the point you need, in world space*/;
//should we snap to divisions or just to master lines?
bool snapToDivs = true;
Ogre::Vector3 divs = snapToDivs ? Ogre::Vector3(grid->divX, grid->divY, grid->divZ) : Ogre::Vector3(1,1,1);
//undo the scale, translation and rotation of the Grid Plane and multiply to division count
r = grid->mOwnNode->_getFullTransform().inverse() * r;
r *= divs;
//snap the point! Just a round!
r.x = round(r.x);
r.y = round(r.y);
r.z = round(r.z);
//divide the divisions, redo the scale, translation and rotation of the Grid Plane
r /= divs;
r = grid->mOwnNode->_getFullTransform() * r;
//and use r as you like. It's now snapped to the nearest grid point.
//Note that it does not mean grid line, as the third coordinate is also respected!
//If you draw the XY plane at z=0, but the point is in z=9,87, the snapped point's z will be 10
{CODE}
{FADE}
!! So? Where can I get this?
Copy-paste from here:
{FADE(label="OgreGrid.h")}
{CODE(wrap="1", colors="C++")}
/*
-----------------------------------------------------------------------------
This source file is supposed to be used with OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
And this grid is 3D-enabled, but limited with min/max, and
not a FrameListener... you can make it a frameListener if you want to!
Copyright (c) 2013 Peter Petrov, Pi-Dev, Bulgaria
Inspired by Jeroen Dierckx's EditorGridSystem, but rewritten from scratch.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#ifndef OGRE_GRID_SYSTEM_H
#define OGRE_GRID_SYSTEM_H
// Includes
#include <Ogre.h>
/*
Ogre Grid by PeterSvP
• This grid have three planes support - XY, XZ, YZ,
• limitations in each dimension (required)
• cell size per dimension
• offset
• colors for offset, master and division axis,
• does NOT depend from the camera used,
• not limited to one instance (NO NAMED items used!)
If you need infinite 2D grid, write code that alters the min and max on the fly,
OR use the Jeroen Dierckx's grid system
*/
class OgreGrid //: public RenderTargetListener - if you want to, I didn't needed this
{
private:
OgreGrid(); //Do NOT copy and create directly...
public:
explicit OgreGrid(Ogre::SceneManager* scene, Ogre::String materialName="BaseWhiteNoLighting");
~OgreGrid();
//The grid's ManualObject
Ogre::ManualObject* mGrid;
/*
mOwnNode - under this node is the manual object.
The Cell size is achieved by scaling this node.
The Offset is achieved by translating this node.
use attachToNode() function to attach the grid to your own node.
mAttachedNode is the node that the grid is attached.
mOwnNode is created by this grid, you should not destroy it.
mAttachedNode is node from your own application.
To transform and rotate the grid, you should manipulate your own node.
The Grid's Zero offset and Cell Size are grid features despite the fact that their imlementation
is done by just translation and scaling mOwnNode.
You may need to access the mOwnNode itself to get its transfrmation if you need to, but altering it
will be lost on next call to update().
An example snapping function is provided in the Ogre's wiki and forum post
*/
Ogre::SceneNode *mOwnNode, *mAttachedNode;
//The Scene Manager.
Ogre::SceneManager* mScene;
//The material to use for the ManualObject.
//Note that BaseWhiteNoLighting does not support alpha blending
Ogre::String material;
//These are the grid settings.
// After you complete them, call update() to regenerate the grid.
// These are public data members as intended, don't blame me for not using setters/getters
//Cell sizes
float csX, csY, csZ;
//Grid's (0,0,0) offset
float ofX, ofY, ofZ;
//Number of divisions in each dimension
int divX, divY, divZ;
//Will the divisions be shown?
bool showDivisions;
//The grid is limited in each dimension, and these are its min and max limiters
int xmin, xmax,
ymin, ymax,
zmin, zmax;
// Which planes to show? You can show only planes you need
bool showXY, showXZ, showYZ;
//offset color is the color of (0,0,0) axis
//master color is the usual master color
//division color is the color of the subdivisions
Ogre::ColourValue colorMaster, colorOffset, colorDivision;
//The Ogre RenderQueue where to draw the grid - RENDER_QUEUE_MAIN/OVERLAY/BACKGROUND/ any int
int drawQueue;
// These setters are for convenience only, you MUST call update() after use!
inline void setCellSize(float size){csX=csY=csZ=size;}
inline void setCellSize(float x, float y, float z){csX=x;csY=y,csZ=z;}
inline void setOffset(float x, float y, float z){ofX=x,ofY=y,ofZ=z;}
inline void setDivisions(int n){divX=divY=divZ=n;}
inline void setDivisions(int x,int y,int z){divX=x;divY=y;divZ=z;}
inline void showPlanes(bool xy, bool xz, bool yz){showXY=xy;showXZ=xz;showYZ=yz;}
//Attach the grid to your provided sceneNode.
void attachToNode(Ogre::SceneNode* node);
//After setup, call this to regenerate the Grid.
void update();
//Grid's visibility
void hide();
void show();
};
#endif // OGRE_GRID_SYSTEM_H
{CODE}
{FADE}
{FADE(label="OgreGrid.cpp")}
{CODE(wrap="1", colors="C++")}
/*
-----------------------------------------------------------------------------
This source file is supposed to be used with OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
And this grid is 3D-enabled, but limited with min/max, and
not a FrameListener... you can make it a frameListener if you want to!
Copyright (c) 2013 Peter Petrov, Pi-Dev, Bulgaria
Inspired by Jeroen Dierckx's EditorGridSystem, but rewritten from scratch.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
// Includes
#include "OgreGrid.h"
#include <Ogre.h>
using namespace Ogre;
OgreGrid::OgreGrid(SceneManager *scene, String name):
mScene(scene),
mAttachedNode(0),
material(name)
{
assert(scene);
mOwnNode = scene->createSceneNode();
mGrid = scene->createManualObject();
mGrid->setDynamic(true);
mOwnNode->attachObject(mGrid);
ManualObject* o = mGrid;
//now set the default settings, the default grid will be xy plane, -5 to +5 with 10 divisions
drawQueue = 1; //assuming that Background is not always the best place
csX = csY = csZ = 1; //cell sizes
ofX = ofY = ofZ = 0; //offsets
xmin = ymin = zmin = -5;
xmax = ymax = zmax = 5;
showXY = true;
showXZ = showYZ = false;
colorOffset = ColourValue(0,0,0,1);
colorMaster = ColourValue(0,0,0,0.4);
colorDivision = ColourValue(0,0,0,0.1);
showDivisions = true;
divX = divY = divZ = 10;
//unfortunately, you MUST call update() when you complete the set-up! No mesh id generated still, just these default settings
}
void OgreGrid::attachToNode(SceneNode *node)
{
//if already attached, deattach it first
if(mAttachedNode)mAttachedNode->removeChild(mOwnNode);
//attach to the new node
mAttachedNode = node;
node->addChild(mOwnNode);
}
OgreGrid::~OgreGrid()
{
//deattach
if(mAttachedNode)
mAttachedNode->removeChild(mOwnNode);
//remove the manualobject and the own node
mScene->destroyManualObject(mGrid);
mScene->destroySceneNode(mOwnNode);
}
void OgreGrid::hide()
{
mOwnNode->setVisible(false);
}
void OgreGrid::show()
{
mOwnNode->setVisible(true);
}
void OgreGrid::update()
{
//Generate the grid mesh
ManualObject* o = mGrid;
//set the render queue
o->setRenderQueueGroup(drawQueue);
//offset and cell size
mOwnNode->setPosition(ofX,ofY,ofZ);
mOwnNode->setScale(csX,csY,csZ);
Ogre::ColourValue* cl;
Real r;
//Clear the manual object to completely regenerate it
o->clear();
o->begin(material, RenderOperation::OT_LINE_LIST);
if(showXY)
{
//major lines
//X
for(int x=xmin;x<=xmax;++x)
{
if(x==0) cl = &colorOffset;
else cl = &colorMaster;
o->position(x,ymin,0);
o->colour(*cl);
o->position(x,ymax,0);
o->colour(*cl);
//divisions
if(x<xmax && showDivisions && divX)
{
for(int d=1;d<divX;++d)
{
r = x+ (1.0/Real(divX))*Real(d);
o->position(r,ymin,0);
o->colour(colorDivision);
o->position(r,ymax,0);
o->colour(colorDivision);
}
}
}
//Y
for(int y=ymin;y<=ymax;++y)
{
if(y==0) cl = &colorOffset;
else cl = &colorMaster;
o->position(xmin,y,0);
o->colour(*cl);
o->position(xmax,y,0);
o->colour(*cl);
//divisions
if(y<ymax && showDivisions && divY)
{
for(int d=1;d<divY;++d)
{
r = y+ (1.0/Real(divY))*Real(d);
o->position(xmin,r,0);
o->colour(colorDivision);
o->position(xmax,r,0);
o->colour(colorDivision);
}
}
}
}
if(showXZ)
{
//major lines
//X
for(int x=xmin;x<=xmax;++x)
{
if(x==0) cl = &colorOffset;
else cl = &colorMaster;
o->position(x,0,zmin);
o->colour(*cl);
o->position(x,0,zmax);
o->colour(*cl);
//divisions
if(x<xmax && showDivisions)
{
for(int d=0;d<divX;++d)
{
r = x+ (1.0/Real(divX))*Real(d);
o->position(r,0,zmin);
o->colour(colorDivision);
o->position(r,0,zmax);
o->colour(colorDivision);
}
}
}
//Z
for(int z=zmin;z<=zmax;++z)
{
if(z==0) cl = &colorOffset;
else cl = &colorMaster;
o->position(xmin,0,z);
o->colour(*cl);
o->position(xmax,0,z);
o->colour(*cl);
if(z<zmax && showDivisions)
{
//divisions
for(int d=0;d<divZ;++d)
{
r = z+ (1.0/Real(divZ))*Real(d);
o->position(xmin,0,r);
o->colour(colorDivision);
o->position(xmax,0,r);
o->colour(colorDivision);
}
}
}
}
//YZ
if(showYZ)
{
//major lines
//Y
for(int y=ymin;y<=ymax;++y)
{
if(y==0) cl = &colorOffset;
else cl = &colorMaster;
o->position(0,y,zmin);
o->colour(*cl);
o->position(0,y,zmax);
o->colour(*cl);
//divisions
if(y<ymax && showDivisions)
{
for(int d=0;d<divY;++d)
{
r = y+ (1.0/Real(divY))*Real(d);
o->position(0,r,zmin);
o->colour(colorDivision);
o->position(0,r,zmax);
o->colour(colorDivision);
}
}
}
//Z
for(int z=zmin;z<=zmax;++z)
{
if(z==0) cl = &colorOffset;
else cl = &colorMaster;
o->position(0,ymin,z);
o->colour(*cl);
o->position(0,ymax,z);
o->colour(*cl);
//divisions
if(z<zmax && showDivisions)
{
for(int d=0;d<divZ;++d)
{
r = z+ (1.0/Real(divZ))*Real(d);
o->position(0,ymin,r);
o->colour(colorDivision);
o->position(0,ymax,r);
o->colour(colorDivision);
}
}
}
}
o->end();
}
{CODE}
{FADE}