Introduction
After some digging around about grid systems and trying 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.
Table of contents
Screenshots
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 OgreGrid class and set the properties you want to, then call update()
Note that you MUST call update() after construction, as the grid is not generated, it's only setup to some maybe-reasonable defaults.
/*OgreGrid*/ grid = new OgreGrid(/*Ogre::SceneManager*/scene, /*Material name*/"BaseWhiteAlphaBlended"); //Attach it to some SceneNode grid->attachToNode(scene->getRootSceneNode()); //Generate the grid grid->update();
The next example gives the grid from the last screenshot:
/*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); //Re/generate the grid grid->update();
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 update() to update the grid manually. All options are public data members with the exception of some convenience setters.
Cell sizes
float csX, csY, csZ are used to control the master grid axes distance, per dimention. 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 setCellSize(float size) and setCellSize(float x, float y, float z) for this purpose.
Zero offset
float ofX, ofY, ofZ are used to move the center of the grid in each dimension. You can also use setOffset(float x, float y, float z)
Division count
int divX, divY, divZ are used to set the count of subdivisions in each dimension. You can also use setDivisions(int n) and setDivisions(int x,int y,int z) for this purpose. To show or hide the divisions and use only the master axes, set bool showDivisions
Grid range limitations
Our grid is limited to specified range in each dimension. 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 int xmin, xmax, ymin, ymax, zmin, zmax. 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 Jeroen Dierckx's EditorGridSystem instead.
Shown planes
You can set which grid plane is drawn by setting bool showXY, showXZ, showYZ as you like. By default, only the XY plane is shown. You can also use showPlanes(bool xy, bool xz, bool yz) for this purpose.
Colors
- colorMaster - The color of master lines. Master lines are drawn each cell size units.
- colorOffset - The color of the offset lines, e.g. these that pass thru (0,0,0)+Grid's offset
- colorDivision - 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:
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 } } }
Other notes
If you want just to set the grid's offset, you may directly set the position of the mOwnNode. 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:
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
So? Where can I get this?
Copy-paste from here:
The header file that you usually want to #include
/* ----------------------------------------------------------------------------- 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
And the implementation file that you must ADD to your project.
/* ----------------------------------------------------------------------------- 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); //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(); }