Exposed VolumeLightSceneNode mesh buffer

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.

Exposed VolumeLightSceneNode mesh buffer

Postby Ion Dune » Sat Jan 31, 2009 10:07 pm

I noticed that the creation of volume light scene nodes was a bit expensive, and since for my purposes I needed to create multiple volume lights at run time but all of them were exactly the same, I exposed the mesh buffer of volume light scene nodes so I could use it with many nodes. Anyway, here's the patch:

Code: Select all
Index: include/IVolumeLightSceneNode.h
===================================================================
--- include/IVolumeLightSceneNode.h   (revision 2174)
+++ include/IVolumeLightSceneNode.h   (working copy)
@@ -8,6 +8,7 @@
 #define __I_VOLUME_LIGHT_SCENE_NODE_H_INCLUDED__
 
 #include "ISceneNode.h"
+#include "IMeshBuffer.h"
 
 namespace irr
 {
@@ -38,6 +39,8 @@
 
       virtual video::SColor getFootColour () const =0;
       virtual video::SColor getTailColour () const =0;
+
+      virtual IMeshBuffer *getMeshBuffer() =0;
    };
 
 } // end namespace scene
Index: source/Irrlicht/CVolumeLightSceneNode.h
===================================================================
--- source/Irrlicht/CVolumeLightSceneNode.h   (revision 2174)
+++ source/Irrlicht/CVolumeLightSceneNode.h   (working copy)
@@ -71,6 +71,8 @@
       virtual video::SColor getFootColour () const { return FootColour; }
       virtual video::SColor getTailColour () const { return TailColour; }
 
+      virtual IMeshBuffer *getMeshBuffer() { return Buffer; }
+
    private:
       void addToBuffer(const video::S3DVertex& v);
       void constructLight();


And sample usage:

Code: Select all
      scene::IVolumeLightSceneNode * Glow = Scene->addVolumeLightSceneNode( 0 , -1 , 32 , 32 , video::SColor( 64 , 255 , 255 , 220 ) , video::SColor( 0 , 0 , 0 , 0 ) ) ;
      scene::IMeshBuffer * MeshBuffer = Glow->getMeshBuffer() ;

      scene::SMesh * Mesh = new scene::SMesh() ;
      Mesh->addMeshBuffer( MeshBuffer ) ;

      scene::SAnimatedMesh * AnimatedMesh = new scene::SAnimatedMesh() ;
      AnimatedMesh->addMesh( Mesh ) ;

      Scene->getMeshCache()->addMesh( "GoldenGlow" , AnimatedMesh ) ;
      Glow->remove() ;
      Mesh->drop() ;
      AnimatedMesh->drop() ;

...

      scene::IVolumeLightSceneNode * VolumeLightNode = Scene->addAnimatedMeshSceneNode( Scene->getMesh( "GoldenGlow" ) ) ;
Ion Dune
 
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA

Postby rogerborg » Sat Jan 31, 2009 10:46 pm

Fair enough. Committed to the trunk in SVN 2175, thanks for the patch.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
User avatar
rogerborg
Admin
 
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh

Postby hybrid » Sat Jan 31, 2009 11:35 pm

Hmm, I'd have preferred a derivation from IMeshSceneNode or an addition to the geometry creator instead. Just adding special methods might make the API a little too clumsy.
hybrid
Admin
 
Posts: 13972
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany

Postby Ion Dune » Sat Jan 31, 2009 11:48 pm

hybrid wrote:Hmm, I'd have preferred a derivation from IMeshSceneNode or an addition to the geometry creator instead. Just adding special methods might make the API a little too clumsy.


I considered this, but took the lazy route route because I planned on more of an optional workaround for people who need it then an addition to the engine, which is why I just posted it here instead of the patch tracker.

Anyway, I'm writing up an addition to the geometry creator to accomplish this as a better addition to the API, and I'll post it here when I'm done. Sorry for the inconvenience :oops: .


EDIT:

Ok, well I copied the code from constructLight() to a new method in the geometry creator, but I've still got a few issues when I replace the volume light scene node in example 8 with a mesh scene node. First, if shadows are enabled on the dwarf mesh, the the light mesh is darkened as well. Second, there seems to be some issue with ZBuffer (the water scene node is sometimes rendered on top of the light and setting ZWrite to true in the material makes it even worse). Since the mesh code is pretty much copied verbatim, I'm pretty sure these problems are due to differences between the very simple, straightforward render process of volume light scene nodes and the extended render process of the mesh scene node which I don't quite understand.
Anyway, the code works fine (at least as far as I can tell from my limited testing) as long as you don't use any WaterSurfaceSceneNodes or ShadowVolumeSceneNodes, so I don't know how useful it actually is. I'll continue to look into this and see if I can find a solution. I'll leave it up to you whether to include it, given its limited use. Either way, here is the patch:

Code: Select all
Index: include/ISceneManager.h
===================================================================
--- include/ISceneManager.h   (revision 2174)
+++ include/ISceneManager.h   (working copy)
@@ -953,6 +953,16 @@
             f32 radius=5.f, u32 polyCountX = 16,
             u32 polyCountY = 16) = 0;
 
+      //! Add a volume light mesh to the meshpool
+      /** \param name Name of the mesh
+      \return Pointer to the sphere mesh if successful, otherwise 0.
+      This pointer should not be dropped. See IReferenceCounted::drop() for more information.
+      */
+      virtual IAnimatedMesh* addVolumeLightMesh(const core::string<c16>& name,
+         const u32 SubdivideU = 32, const u32 SubdivideV = 32,
+         const video::SColor FootColour = video::SColor(51, 0, 230, 180),
+         const video::SColor TailColour = video::SColor(0, 0, 0, 0)) = 0;
+
       //! Gets the root scene node.
       /** This is the scene node which is parent
       of all scene nodes. The root scene node is a special scene node which

Index: source/Irrlicht/CGeometryCreator.cpp
===================================================================
--- source/Irrlicht/CGeometryCreator.cpp   (revision 2174)
+++ source/Irrlicht/CGeometryCreator.cpp   (working copy)
@@ -675,7 +675,157 @@
    return mesh;
 }
 
+void CGeometryCreator::addToBuffer(const video::S3DVertex& v, SMeshBuffer* Buffer)
+{
+   const s32 tnidx = Buffer->Vertices.linear_reverse_search(v);
+   const bool alreadyIn = (tnidx != -1);
+   u16 nidx = (u16)tnidx;
+   if (!alreadyIn) {
+      nidx = (u16)Buffer->Vertices.size();
+      Buffer->Indices.push_back(nidx);
+      Buffer->Vertices.push_back(v);
+   } else
+      Buffer->Indices.push_back(nidx);
+}
 
+IMesh* CGeometryCreator::createVolumeLightMesh(const u32 SubdivideU, const u32 SubdivideV,
+   const video::SColor FootColour,
+   const video::SColor TailColour)
+{
+   f32 LPDistance = 8.0f;
+   core::vector3df LightDimensions = core::vector3df(1.0f, 1.2f, 1.0f) ;
+   SMeshBuffer* Buffer = new SMeshBuffer();
+   Buffer->setHardwareMappingHint(EHM_STATIC);
+
+   const core::vector3df lightPoint(0, -(LPDistance*LightDimensions.Y), 0);
+   const f32 ax = LightDimensions.X * 0.5f; // X Axis
+   const f32 az = LightDimensions.Z * 0.5f; // Z Axis
+
+   Buffer->Vertices.clear();
+   Buffer->Vertices.reallocate(6+12*(SubdivideU+SubdivideV));
+   Buffer->Indices.clear();
+   Buffer->Indices.reallocate(6+12*(SubdivideU+SubdivideV));
+   //draw the bottom foot.. the glowing region
+   addToBuffer(video::S3DVertex(-ax, 0, az,  0,0,0, FootColour, 0, 1),Buffer);
+   addToBuffer(video::S3DVertex(ax , 0, az,  0,0,0, FootColour, 1, 1),Buffer);
+   addToBuffer(video::S3DVertex(ax , 0,-az,  0,0,0, FootColour, 1, 0),Buffer);
+
+   addToBuffer(video::S3DVertex(ax , 0,-az,  0,0,0, FootColour, 1, 0),Buffer);
+   addToBuffer(video::S3DVertex(-ax, 0,-az,  0,0,0, FootColour, 0, 0),Buffer);
+   addToBuffer(video::S3DVertex(-ax, 0, az,  0,0,0, FootColour, 0, 1),Buffer);
+
+   f32 tu = 0.f;
+   const f32 tuStep = 1.f/SubdivideU;
+   f32 bx = -ax;
+   const f32 bxStep = LightDimensions.X * tuStep;
+   // Slices in X/U space
+   for (u32 i = 0; i <= SubdivideU; ++i)
+   {
+      // These are the two endpoints for a slice at the foot
+      core::vector3df end1(bx, 0.0f, -az);
+      core::vector3df end2(bx, 0.0f, az);
+
+      end1 -= lightPoint;      // get a vector from point to lightsource
+      end1.normalize();      // normalize vector
+      end1 *= LightDimensions.Y;   // multiply it out by shootlength
+
+      end1.X += bx;         // Add the original point location to the vector
+      end1.Z -= az;
+
+      // Do it again for the other point.
+      end2 -= lightPoint;
+      end2.normalize();
+      end2 *= LightDimensions.Y;
+
+      end2.X += bx;
+      end2.Z += az;
+
+      addToBuffer(video::S3DVertex(bx , 0,  az,  0,0,0, FootColour, tu, 1),Buffer);
+      addToBuffer(video::S3DVertex(bx , 0, -az,  0,0,0, FootColour, tu, 0),Buffer);
+      addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z,  0,0,0, TailColour, tu, 1),Buffer);
+
+      addToBuffer(video::S3DVertex(bx , 0, -az,  0,0,0, FootColour, tu, 0),Buffer);
+      addToBuffer(video::S3DVertex(end1.X , end1.Y, end1.Z,  0,0,0, TailColour, tu, 0),Buffer);
+      addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z,  0,0,0, TailColour, tu, 1),Buffer);
+
+      //back side
+      addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z,  0,0,0, TailColour, tu, 1),Buffer);
+      addToBuffer(video::S3DVertex(-bx , 0,  -az,  0,0,0, FootColour, tu, 1),Buffer);
+      addToBuffer(video::S3DVertex(-bx , 0, az,  0,0,0, FootColour, tu, 0),Buffer);
+
+      addToBuffer(video::S3DVertex(-bx , 0, az,  0,0,0, FootColour, tu, 0),Buffer);
+      addToBuffer(video::S3DVertex(-end1.X , end1.Y, -end1.Z,  0,0,0, TailColour, tu, 0),Buffer);
+      addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z,  0,0,0, TailColour, tu, 1),Buffer);
+      tu += tuStep;
+      bx += bxStep;
+   }
+
+   f32 tv = 0.f;
+   const f32 tvStep = 1.f/SubdivideV;
+   f32 bz = -az;
+   const f32 bzStep = LightDimensions.Z * tvStep;
+   // Slices in Z/V space
+   for(u32 i = 0; i <= SubdivideV; ++i)
+   {
+      // These are the two endpoints for a slice at the foot
+      core::vector3df end1(-ax, 0.0f, bz);
+      core::vector3df end2(ax, 0.0f, bz);
+
+      end1 -= lightPoint;      // get a vector from point to lightsource
+      end1.normalize();      // normalize vector
+      end1 *= LightDimensions.Y;   // multiply it out by shootlength
+
+      end1.X -= ax;         // Add the original point location to the vector
+      end1.Z += bz;
+
+      // Do it again for the other point.
+      end2 -= lightPoint;
+      end2.normalize();
+      end2 *= LightDimensions.Y;
+
+      end2.X += ax;
+      end2.Z += bz;
+
+      addToBuffer(video::S3DVertex(-ax , 0, bz,  0,0,0, FootColour, 0, tv),Buffer);
+      addToBuffer(video::S3DVertex(ax , 0,  bz,  0,0,0, FootColour, 1, tv),Buffer);
+      addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z,  0,0,0, TailColour, 1, tv),Buffer);
+
+      addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z,  0,0,0, TailColour, 1, tv),Buffer);
+      addToBuffer(video::S3DVertex(end1.X , end1.Y, end1.Z,  0,0,0, TailColour, 0, tv),Buffer);
+      addToBuffer(video::S3DVertex(-ax , 0, bz,  0,0,0, FootColour, 0, tv),Buffer);
+
+      //back side
+      addToBuffer(video::S3DVertex(ax , 0, -bz,  0,0,0, FootColour, 0, tv),Buffer);
+      addToBuffer(video::S3DVertex(-ax , 0,  -bz,  0,0,0, FootColour, 1, tv),Buffer);
+      addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z,  0,0,0, TailColour, 1, tv),Buffer);
+
+      addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z,  0,0,0, TailColour, 1, tv),Buffer);
+      addToBuffer(video::S3DVertex(-end1.X , end1.Y, -end1.Z,  0,0,0, TailColour, 0, tv),Buffer);
+      addToBuffer(video::S3DVertex(ax , 0, -bz,  0,0,0, FootColour, 0, tv),Buffer);
+      tv += tvStep;
+      bz += bzStep;
+   }
+
+   Buffer->recalculateBoundingBox();
+

+   Buffer->Material.MaterialType = video::EMT_ONETEXTURE_BLEND;
+   Buffer->Material.MaterialTypeParam = pack_texureBlendFunc( video::EBF_SRC_COLOR, video::EBF_SRC_ALPHA, video::EMFN_MODULATE_1X );
+
+   Buffer->Material.Lighting = false;
+   Buffer->Material.ZWriteEnable = false;
+
+   Buffer->setDirty(EBT_VERTEX_AND_INDEX);
+
+   Buffer->recalculateBoundingBox();
+   SMesh* mesh = new SMesh();
+   mesh->addMeshBuffer(Buffer);
+   Buffer->drop();
+
+   mesh->recalculateBoundingBox();
+   return mesh;
+}
+
+
 } // end namespace scene
 } // end namespace irr
 
Index: source/Irrlicht/CGeometryCreator.h
===================================================================
--- source/Irrlicht/CGeometryCreator.h   (revision 2174)
+++ source/Irrlicht/CGeometryCreator.h   (working copy)
@@ -7,9 +7,9 @@
 
 #include "IMesh.h"
 #include "IImage.h"
+#include "SMeshBuffer.h"
 
 
 namespace irr
 {
 namespace video
@@ -24,6 +24,7 @@
 //! class for creating geometry on the fly
 class CGeometryCreator
 {
+   static void addToBuffer(const video::S3DVertex& v, SMeshBuffer* Buffer);
 public:
 
    static IMesh* createHillPlaneMesh(
@@ -48,6 +49,10 @@
    static IMesh* createCylinderMesh(f32 radius, f32 length, u32 tesselation, const video::SColor& color=video::SColor(0xffffffff), bool closeTop=true, f32 oblique=0.f);
 
    static IMesh* createConeMesh(f32 radius, f32 length, u32 tesselation, const video::SColor& colorTop=video::SColor(0xffffffff), const video::SColor& colorBottom=video::SColor(0xffffffff), f32 oblique=0.f);
+
+   static IMesh* createVolumeLightMesh(const u32 SubdivideU, const u32 SubdivideV,
+         const video::SColor FootColour,
+         const video::SColor TailColour);
 };
 
 
Index: source/Irrlicht/CSceneManager.cpp
===================================================================
--- source/Irrlicht/CSceneManager.cpp   (revision 2174)
+++ source/Irrlicht/CSceneManager.cpp   (working copy)
@@ -1013,7 +1013,38 @@
 }
 
 
+//! Adds a static volume light mesh to the mesh pool.
+IAnimatedMesh* CSceneManager::addVolumeLightMesh(const core::string<c16>& name,
+   const u32 SubdivideU, const u32 SubdivideV,
+   const video::SColor FootColour,
+   const video::SColor TailColour)
+{
+   if (MeshCache->isMeshLoaded(name))
+      return MeshCache->getMeshByFilename(name);
 
+   IMesh* mesh = CGeometryCreator::createVolumeLightMesh(SubdivideU, SubdivideV, FootColour, TailColour);
+   if (!mesh)
+      return 0;
+
+   SAnimatedMesh* animatedMesh = new SAnimatedMesh();
+   if (!animatedMesh)
+   {
+      mesh->drop();
+      return 0;
+   }
+
+   animatedMesh->addMesh(mesh);
+   mesh->drop();
+   animatedMesh->recalculateBoundingBox();
+
+   MeshCache->addMesh(name, animatedMesh);
+   animatedMesh->drop();
+
+   return animatedMesh;
+}
+
+
+
 //! Returns the root scene node. This is the scene node wich is parent
 //! of all scene nodes. The root scene node is a special scene node which
 //! only exists to manage all scene nodes. It is not rendered and cannot
Index: source/Irrlicht/CSceneManager.h
===================================================================
--- source/Irrlicht/CSceneManager.h   (revision 2174)
+++ source/Irrlicht/CSceneManager.h   (working copy)
@@ -221,6 +221,12 @@
       IAnimatedMesh* addSphereMesh(const core::string<c16>& name,
             f32 radius=5.f, u32 polyCountX=16, u32 polyCountY=16);
 
+      //! Adds a static volume light mesh to the mesh pool.
+      IAnimatedMesh* addVolumeLightMesh(const core::string<c16>& name,
+         const u32 SubdivideU = 32, const u32 SubdivideV = 32,
+         const video::SColor FootColour = video::SColor(51, 0, 230, 180),
+         const video::SColor TailColour = video::SColor(0, 0, 0, 0));
+
       //! Adds a particle system scene node.
       virtual IParticleSystemSceneNode* addParticleSystemSceneNode(
          bool withDefaultEmitter=true, ISceneNode* parent=0, s32 id=-1,
Ion Dune
 
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA

Postby Ion Dune » Sun Feb 01, 2009 2:02 am

More developments: I delved into the code of the OpenGL material renders (my only available test platform is OpenGL - the software renders can't render example 8, and I don't currently have a copy of the DirectX SDK) and found that the one texture blend material type - the one used by volume light scene nodes - claims to not be transparent. Granted, I have no idea if its supposed to be or not, but I assumed it was and the following change fixed all the aforementioned problems:

Code: Select all
Index: source/Irrlicht/COpenGLMaterialRenderer.h
===================================================================
--- source/Irrlicht/COpenGLMaterialRenderer.h   (revision 2174)
+++ source/Irrlicht/COpenGLMaterialRenderer.h   (working copy)
@@ -155,6 +155,12 @@
       glDisable(GL_ALPHA_TEST);
    }
 
+   //! Returns if the material is transparent.
+   virtual bool isTransparent() const
+   {
+      return true;
+   }
+
    private:
 
       u32 getGLBlend ( E_BLEND_FACTOR factor ) const


So the question is: isn't one texture blend a transparent material type?
Ion Dune
 
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA

Postby hybrid » Sun Feb 01, 2009 12:44 pm

Yes, I think it should usually be considered transparent. I'll check this later. Thanks for the update.
hybrid
Admin
 
Posts: 13972
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany

Postby Ion Dune » Wed Feb 04, 2009 7:45 pm

I hate to persist, but what's the verdict on onetexture_blend being transparent? I'm pretty sure it is, based on this topic, since if its blending with the pixels beneath it, isn't it by definition transparent?

Anyway, I found that my patches didn't work with the latest revision, so I made a new all-inclusive patch. I also noticed that there were transparency issues with both direct3d9 and opengl, so I made the change to both drivers' material renderers. Finally, I removed my old change (getMeshBuffer() in CVolumeLightSceneNode) since this new patch is a better way of accomplishing that. For simplicity's sake and to keep this thread from getting even more cluttered, I uploaded the patch to the tracker here.
Ion Dune
 
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA

Postby hybrid » Wed Feb 04, 2009 8:31 pm

Don't know if there's a problem left or not. Why do you think so?
Thanks for the new patch.
hybrid
Admin
 
Posts: 13972
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany

Postby Ion Dune » Wed Feb 04, 2009 9:07 pm

When using the mesh created addVolumeLightMesh(...), if EMT_ONETEXTURE_BLEND is not treated as transparent, there are graphical glitches when viewing the light in front of other objects, for example the dwarf and the water in example 8. In the VolumeLightSceneNode, the node registers itself as transparent automatically, but the AnimatedMeshSceneNode and MeshSceneNode both rely on what the material renderer says, which is what I changed in the patch.

Everything else is just removing the old method of retrieving the mesh buffer from a created VolumeLightSceneNode and adding methods for creating the mesh through the scene manager.
Ion Dune
 
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA


Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 0 guests