My own Grid3DSceneNode always rendering behind IMeshes

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
FyShu^
Posts: 6
Joined: Sun May 27, 2007 12:57 pm

My own Grid3DSceneNode always rendering behind IMeshes

Post by FyShu^ »

Hi there.

My problem is, I've created my Grid3DSceneNode, whose code is below...

Code: Select all

#ifndef GRID3DSCENENODE_H_
#define GRID3DSCENENODE_H_

#include <irrlicht.h>

using namespace irr;

class Grid3DSceneNode : public irr::scene::ISceneNode
{
public:
	//constructor takes three ints, the position of the grid, and
	//specifying the grid's dimensions, then a color.
	
	Grid3DSceneNode(scene::ISceneNode* parent, scene::ISceneManager *smgr,
		int rows, int columns, int depth, s32 id=-1, 
		core::vector3df pos = core::vector3df(0.0f,0.0f,0.0f), //default in centre of place
		video::SColor newCol = video::SColor(255,255,255,255 ));
		
	virtual ~Grid3DSceneNode();
	
	virtual	void render() //overrides pure virtual method render()=0
	{	
	//it is possible to render 2d grids with this one- if one dimension is given value zero.
		if (x<0 || y<0 || z<0)
			return; //not rendered.
			 
	
		video::IVideoDriver *driver = SceneManager->getVideoDriver();
		
		driver->setTransform(video::ETS_WORLD, core::matrix4());	
		//There are three planes: the xy plane, the yz plane and the xz plane.
		//draw on the xy plane, xy times, along z.
		for (int i = 0; i <= x; ++i) {
			for (int j = 0; j <= y; ++j) {
				driver->draw3DLine(
					core::vector3df(i,j,0) + getPosition(),
					core::vector3df(i,j,z) + getPosition(),
					col
				);
			}
		}	 
		
		//draw on the yz plane yz times, along x
		
		for (int j = 0; j <= y; ++j) {
			for (int k = 0; k <= z; ++k) {
				driver->draw3DLine(
					core::vector3df(0,j,k) + getPosition(),
					core::vector3df(x,j,k) + getPosition(),
					col
				);
			}
		}
			 
		//draw on the xz plane xz times, along y
		for (int i = 0; i <= x; i++) {
			for (int k = 0; k <= z; ++k) {
				driver->draw3DLine(
					core::vector3df(i,0,k) + getPosition(),
					core::vector3df(i,y,k) + getPosition(),
					col
				);		
			}
		}
	}
	
	
	virtual const core::aabbox3df& getBoundingBox() const
	{
		return Box;
	}
	
	virtual void OnRegisterSceneNode()
	{
		if (IsVisible)
    		SceneManager->registerNodeForRendering(this);

  		scene::ISceneNode::OnRegisterSceneNode();
	}
	
	virtual void resize(int newRows, int newColumns, int newDepth)
	{
		x = newRows;
		y = newColumns;
		z = newDepth;
		
		Box = core::aabbox3df(
				getPosition().X,getPosition().X+x,
				getPosition().Y,getPosition().Y+y,
				getPosition().Z,getPosition().Z+z
			);
	}
	
	virtual core::vector3df getCenter(){
		return ( core::vector3df(x/2,y/2,z/2)+getPosition() );
	}
	
	video::SColor getColor() const {
		return col;
	}
	
	void setColor(video::SColor newCol){
		col= newCol;
	}

		
private:
	int x,y,z;
	video::SColor col; //the color of this grid	
	core::aabbox3df Box; //the box!	
};

#endif /*GRID3DSCENENODE_H_*/
(the implementation was just put into the header for convenience of forum showing stuff.)

I built a little app to see it working in practise. It is basically the 04. Movement example without the animated mesh of sydney: There's a textured sphere and a cube orbiting it.

When I run my little app, with the main loop like the following:

Code: Select all

	video::SColor gridColor(129,255,255,255);
	
	Grid3DSceneNode *gridNode = new Grid3DSceneNode(smgr->getRootSceneNode(), smgr,5,4,3);
	gridNode->setColor(gridColor);
	
	while(device->run())
	{
		//Makes the driver ready for drawing
		driver->beginScene(true, true, video::SColor(255,113,113,133));
		smgr->drawAll(); // draw the 3d scene
		
		device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo)

		driver->endScene();

		fps = driver->getFPS();

		if (lastFPS != fps)
		{
			core::stringw tmp =L"Movement Example - Irrlicht Engine [";
			tmp += driver->getName();
			tmp += L"] fps: "; 
			tmp += fps;

			device->setWindowCaption(tmp.c_str());
			lastFPS = fps;
		}
	}
What I find is, even if the sphere or cube was behind the grid's position in 3D space, it's still drawn in front of the grid lines.

Why might that be?? It's not culling is it?

Note the grid is drawn with the infamous video driver method draw3DLine()... the world transform was set before the lines were drawn... etc.

Thanks!
Kimundi
Posts: 11
Joined: Sun Apr 01, 2007 11:04 am

Post by Kimundi »

Maybe zwrite is false?
Image
[Sorry for possible bad English]
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

You aren't setting the material properties before you render your lines, so the material from the previously rendered object is used. This could cause problems. I'd suggest adding something like this to your render() method...

Code: Select all

   video::SMaterial m;
   m.Lighting = false;
   driver->setMaterial(m);
I'd also suggest building up a vertex and index buffer and using drawVertexPrimitiveList() instead of the draw3DLine() call. It will be much more efficient.

Travis
FyShu^
Posts: 6
Joined: Sun May 27, 2007 12:57 pm

Post by FyShu^ »

How right you are, mr vitek- I neglected materials, a n00bish thing to do, but i shall remember it- now it works a charm! :)

I have read some of your other responses I made a fairly n00bish error there...

Excuse me for ignorance / not thinking too much- i've looked in the documentation for drawVertexPrimitiveList() but I didn't find it too helpful for grids, it's fair enough to have quads, but that doesn't "wrap" easily into a grid does it?

I can imagine drawing a cube- but as for a grid, it seems there'll be a load of repeated vertices, won't there? Plus, if it forms a quad, I've gotta make sure that it isn't shaded, because i actually want to see the lines "inside" of the grid.

:/ cheers for the help.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

You can use EPT_LINES to draw your grid. The benefit is that you need not call hundreds of times the draw3DLine method, but you only call one time the drawPrimitive method. This also means on ly one call to the GPU which saves a lot of time and lets the GPU do a better job (in general).
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Yes, there will be a few duplicated vertices. Really the only overlap is the vertices along the primary axes of the grid. If you consider the xy plane and the xz planes, the vertices that connect the edges of those two planes will be duplicated. The code is pretty similar to what you posted earlier...

Code: Select all

class Grid3DSceneNode : public irr::scene::ISceneNode 
{ 
public: 
  //constructor takes three ints, the position of the grid, and 
  //specifying the grid's dimensions, then a color. 

  Grid3DSceneNode(scene::ISceneNode* parent, scene::ISceneManager *mgr, 
    u32 x, u32 y, u32 z, video::SColor clr, s32 id = -1, 
    core::vector3df pos = core::vector3df(0.f, 0.f, 0.f),
    core::vector3df rot = core::vector3df(0.f, 0.f, 0.f),
    core::vector3df scl = core::vector3df(1.f, 1.f, 1.f))
    : scene::ISceneNode(parent, mgr, id, pos, rot, scl)
    , Color(clr)
  {
    setGridSize(x, y, z);
  }

  virtual ~Grid3DSceneNode()
  {
  }

  virtual void OnRegisterSceneNode()
  {
    if (IsVisible)
      SceneManager->registerNodeForRendering(this);

    ISceneNode::OnRegisterSceneNode();
  }

  virtual void render()
  {
    if (!Buffer.getIndexCount())
      return;

    video::IVideoDriver* driver = SceneManager->getVideoDriver(); 

    driver->setTransform(video::ETS_WORLD, getAbsoluteTransformation());
    driver->setMaterial (Buffer.getMaterial());

    driver->drawVertexPrimitiveList(
      Buffer.getVertices(), Buffer.getVertexCount(),
      Buffer.getIndices(), Buffer.getIndexCount() / 2,
      video::EVT_STANDARD, scene::EPT_LINES);

    if (DebugDataVisible & scene::EDS_BBOX ||
      DebugDataVisible & scene::EDS_BBOX_BUFFERS)
    {
      driver->draw3DBox( Buffer.BoundingBox, video::SColor(255, 255, 255, 0) );
    }
  } 

  virtual const core::aabbox3df& getBoundingBox() const 
  { 
    return Buffer.BoundingBox; 
  } 

  virtual u32 getMaterialCount()
  {
    return 1;
  }

  virtual video::SMaterial& getMaterial(u32 num)
  {
    return Buffer.Material;
  }

  void setGridSize(u32 x, u32 y, u32 z) 
  {
    Buffer.Vertices.set_used(0);
    Buffer.Indices .set_used(0);

    u32 i, j, k, n = 0;

    // draw on the xy plane xy times, along z
    video::S3DVertex v(0, 0, 0, 0, 0, 0, Color, 0, 0);
    for (i = 0; i <= x; ++i) { 
      for (j = 0; j <= y; ++j) { 
        v.Pos.set(i, j, 0.f);
        Buffer.Vertices.push_back(v);

        v.Pos.set(i, j, z);
        Buffer.Vertices.push_back(v);				
      } 
    }    

    //draw on the yz plane yz times, along x 
    for (j = 0; j <= y; ++j) { 
      for (k = 0; k <= z; ++k) { 
        v.Pos.set(0.f, j, k);
        Buffer.Vertices.push_back(v);

        v.Pos.set(x, j, k);
        Buffer.Vertices.push_back(v);				
      } 
    } 

    //draw on the xz plane xz times, along y 
    for (i = 0; i <= x; ++i) { 
      for (k = 0; k <= z; ++k) {
        v.Pos.set(i, 0.f, k);
        Buffer.Vertices.push_back(v);

        v.Pos.set(i, y, k);
        Buffer.Vertices.push_back(v);				
      }
    }

    for (n = 0; n < Buffer.Vertices.size(); ++n)
    {
      Buffer.Indices.push_back(n);
    }

    Buffer.BoundingBox.reset(0, 0, 0);
    Buffer.BoundingBox.addInternalPoint(x, y, z);
  }

private:
  video::SColor Color;
  scene::SMeshBuffer Buffer;
}; 
And you'd use it like you did before

Code: Select all

Grid3DSceneNode *gridNode = new Grid3DSceneNode(smgr->getRootSceneNode(), smgr, 20, 20, 20, video::SColor(255, 255, 0, 0)); 
gridNode->setMaterialFlag(video::EMF_LIGHTING, false);
Travis
Post Reply