Skip to main content

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}

        

History

Information Version
Fri 19 of Jul, 2013 06:21 GMT-0000 petersvp 29
Fri 19 of Jul, 2013 04:54 GMT-0000 petersvp 28
Fri 19 of Jul, 2013 04:40 GMT-0000 petersvp 27
Fri 19 of Jul, 2013 04:26 GMT-0000 petersvp 26
Fri 19 of Jul, 2013 04:20 GMT-0000 petersvp 25
Fri 19 of Jul, 2013 04:16 GMT-0000 petersvp 24
Fri 19 of Jul, 2013 04:12 GMT-0000 petersvp 23
Fri 19 of Jul, 2013 04:11 GMT-0000 petersvp 22
Fri 19 of Jul, 2013 03:21 GMT-0000 petersvp 21
Fri 19 of Jul, 2013 03:20 GMT-0000 petersvp 20
Fri 19 of Jul, 2013 03:18 GMT-0000 petersvp 19
Fri 19 of Jul, 2013 03:18 GMT-0000 petersvp 18
Fri 19 of Jul, 2013 03:10 GMT-0000 petersvp 17
Fri 19 of Jul, 2013 03:09 GMT-0000 petersvp 16
Fri 19 of Jul, 2013 02:27 GMT-0000 petersvp 15
Fri 19 of Jul, 2013 02:27 GMT-0000 petersvp 14
Fri 19 of Jul, 2013 02:21 GMT-0000 petersvp 13
Fri 19 of Jul, 2013 02:18 GMT-0000 petersvp 12
Fri 19 of Jul, 2013 02:17 GMT-0000 petersvp 11
Fri 19 of Jul, 2013 02:10 GMT-0000 petersvp 10
Fri 19 of Jul, 2013 02:10 GMT-0000 petersvp 9
Fri 19 of Jul, 2013 02:04 GMT-0000 petersvp 8
Fri 19 of Jul, 2013 02:01 GMT-0000 petersvp 7
Fri 19 of Jul, 2013 01:51 GMT-0000 petersvp 6
Fri 19 of Jul, 2013 01:35 GMT-0000 petersvp 5
  • «
  • 1 (current)
  • 2