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.
Post Reply
Ion Dune
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA
Contact:

Exposed VolumeLightSceneNode mesh buffer

Post by Ion Dune »

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" ) ) ;
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

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
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

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.
Ion Dune
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA
Contact:

Post by Ion Dune »

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
Contact:

Post by Ion Dune »

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?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yes, I think it should usually be considered transparent. I'll check this later. Thanks for the update.
Ion Dune
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA
Contact:

Post by Ion Dune »

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.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Don't know if there's a problem left or not. Why do you think so?
Thanks for the new patch.
Ion Dune
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA
Contact:

Post by Ion Dune »

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.
Post Reply