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
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,