RFC on new flexible ILightManager
OK, I'll take a look at this. I need a light manager...
Irrlicht Demos: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=6&t=45781
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
Great, thanks. Suggestions will be very gratefully received.
I'd imagine that most people won't need it, but if you need 'local' lights, it might be useful.
I'd imagine that most people won't need it, but if you need 'local' lights, it might be useful.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
light manager, quake level, my Doom3 MD5 model loader, IrrAI, Newton physics...should be interesting...
Irrlicht Demos: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=6&t=45781
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
I'd also like to have some kinf of a light manager for the ogl-es driver, because standard ogl-es 1.x only supports two lights. So it requires a lot more handling of light sources than usual drivers...
Could you please announce any progress of the patch, because the tracker doesn't show updates recognizable in the summary.
Could you please announce any progress of the patch, because the tracker doesn't show updates recognizable in the summary.
first of all, thanks rogerborg!
just a note that the current patch file i downloaded (289338: managed-lights.patch) has duplicated code (like someone hit paste twice for the entire file contents) in the included example's .vcproj files and main.cpp
after deleting the extra, they compile and run fine though.
just a note that the current patch file i downloaded (289338: managed-lights.patch) has duplicated code (like someone hit paste twice for the entire file contents) in the included example's .vcproj files and main.cpp
after deleting the extra, they compile and run fine though.
Deferred shading is another option but that requires shaders. A 100 or even a 1000 lights could be drawn in one batch. It would be an interesting exercise for a Quake3 level, especially since we can now get a list of lights from the loader - though this light list is very useful for the LightManager.
Anyway, I've got rogerborg's LightManager working. When I have something I'll post a demo.
I'm also working on the Doom3 MD5 loader. The bump/parallax shaders need light sources to look good, so the LightManager will be used to drive the light input.
Anyway, I've got rogerborg's LightManager working. When I have something I'll post a demo.
I'm also working on the Doom3 MD5 loader. The bump/parallax shaders need light sources to look good, so the LightManager will be used to drive the light input.
Irrlicht Demos: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=6&t=45781
This is pretty awesome
I made a few changes so that we could have both zone lights and others. Performance is great! I added a manageType to ILightSceneNode.
I added a little doo dad to play with attenuation. See below.
And I changed the OnNodePreRender routine down to one loop.
And then OnRenderPassPostRender is no longer needed to turn off all the lights.
Here's some of the helper functions
We've been using it for about month now with out problems and fast frame rates. I think ILightManager would make a strong addition to the Irrlicht core IMHO And I'd be more then happy to add it to the latest SVN if people want
Thanks rogerborg! saved me a lot time
I made a few changes so that we could have both zone lights and others. Performance is great! I added a manageType to ILightSceneNode.
I added a little doo dad to play with attenuation. See below.
Code: Select all
void KE_LightManager::setupLight(scene::ILightSceneNode * lnode, KE_LIGHT_TYPE inType)
{
if (!lnode)
return;
video::SLight &l = lnode->getLightData();
lnode->manageType = LIGHTS_NEAREST_NODE; //default
f32 constantAttenuation = 0.0f;
f32 linearAttenuation = 0.0f;
f32 quadraticAttenuation = 0.0f;
switch (inType) {
case KE_LIGHT_NEARLINEAR_FASTFALLOFF:
constantAttenuation = 1.0f;
if(l.Radius > 0.0f)
linearAttenuation = (10.0f / l.Radius);
else
linearAttenuation = 0.0f;
l.ke_type = KE_LIGHT_NEARLINEAR_FASTFALLOFF;
break;
case KE_LIGHT_NEARLINEAR:
constantAttenuation = 1.0f;
if(l.Radius > 0.0f)
linearAttenuation = (1.0f / l.Radius);
else
linearAttenuation = 0.0f;
l.ke_type = KE_LIGHT_NEARLINEAR;
break;
case KE_LIGHT_INVSQUARE_FASTFALLOFF:
constantAttenuation = 1.0f;
if(l.Radius > 0.0f)
quadraticAttenuation = (10.0f / (l.Radius * l.Radius));
else
quadraticAttenuation = 0.0f;
l.ke_type = KE_LIGHT_INVSQUARE_FASTFALLOFF;
break;
case KE_LIGHT_INVSQUARE:
constantAttenuation = 1.0f;
if(l.Radius > 0.0f)
quadraticAttenuation = (1.0f / (l.Radius * l.Radius));
else
quadraticAttenuation = 0.0f;
l.ke_type = KE_LIGHT_INVSQUARE;
break;
case KE_LIGHT_ADVANCED:
if(l.Radius > 0.0f)
linearAttenuation = (6.0f / l.Radius);
else
linearAttenuation = 0.0;
l.ke_type = KE_LIGHT_ADVANCED;
break;
case KE_LIGHT_ORIGINAL:
default:
if(l.Radius > 0.0f)
quadraticAttenuation = (1.0f / (l.Radius * l.Radius));
else
quadraticAttenuation = 0.0f;
l.ke_type = KE_LIGHT_ORIGINAL;
}
l.Attenuation.X = constantAttenuation; //ConstantAttenuation
l.Attenuation.Y = linearAttenuation; //LinearAttenuation
l.Attenuation.Z = quadraticAttenuation; //QuadraticAttenuation
}
Code: Select all
void KE_LightManager::OnNodePreRender(ISceneNode* node)
{
if (!node || Mode == NO_MANAGEMENT)
return;
//must always use node->setMaterialFlag(video::EMF_LIGHTING, true/false);
if (!node->getNeedsLight()) //Varmint: dooh know??
return;
ISceneNode * zoneLight = isZoneLit(node);
if (zoneLight)
Mode = LIGHTS_IN_ZONE;
else
Mode = LIGHTS_NEAREST_NODE;
CurrentSceneNode = node;
if (AmbientColour.toSColor() != SceneManager->getAmbientLight().toSColor()) {
SceneManager->setAmbientLight(AmbientColour);
SceneManager->getVideoDriver()->setAmbientLight(AmbientColour);
}
//Varmint: might be interesting to use camera pos for terrain
if (node->getType() == ESNT_TERRAIN)
node = SceneManager->getActiveCamera();
s32 activeZoneLights = 0;
if(LIGHTS_IN_ZONE == Mode && zoneLight)
{
//this makes it zone lights only
for(u32 i = 0; i < SceneLightList->size(); ++i) {
ILightSceneNode* lightNode = static_cast<ILightSceneNode*>((*SceneLightList)[i]);
lightNode->setVisible(false);
}
//this makes it zone lights only
activeZoneLights = turnZoneLightsOn(zoneLight);
Mode = LIGHTS_NEAREST_NODE;
return; //this makes it zone lights only
}
if(LIGHTS_NEAREST_NODE == Mode)
{
// This is a naive implementation that prioritises every light in the scene
// by its proximity to the node being rendered. This produces some flickering
// when lights orbit closer to a cube than its 'zone' lights.
const vector3df nodePosition = node->getAbsolutePosition();
// Sort the light list by prioritising them based on their distance from the node
// that's about to be rendered.
array<LightDistanceElement> sortingArray;
sortingArray.reallocate(SceneLightList->size());
u32 i;
for(i = 0; i < SceneLightList->size(); ++i)
{
ILightSceneNode* lightNode = static_cast<ILightSceneNode*>((*SceneLightList)[i]);
if (zoneLight && zoneLight == lightNode)
continue;
core::vector3df lightPos = lightNode->getAbsolutePosition();
SLight & lightData = lightNode->getLightData();
lightNode->setVisible(false);
if (lightNode->manageType == LIGHTS_IN_ZONE) {
if (!zoneLight)
continue;
if (zoneLight && !isLightInZone(zoneLight, lightNode))
continue;
}
f64 distance = 0.01f;
if (!lightData.staticEnviromentLight)
distance = lightPos.getDistanceFromSQ(nodePosition);
if (lightNode->manageType == LIGHTS_IN_ZONE)
distance *= 0.5f;
else if (!lightNode->isStaticLight)
distance *= 10.0f;
sortingArray.push_back(LightDistanceElement(lightNode, distance));
}
sortingArray.sort();
// The list is now sorted by proximity to the node.
// Turn on the three nearest lights, and turn the others off.
if ((maxHardwareLights-activeZoneLights) > 0) {
for(i = 0; i < sortingArray.size(); ++i) {
if (i > (u32)maxHardwareLights-1-activeZoneLights)
break;
sortingArray[i].node->setVisible(true);
}
}//if ((maxHardwareLights-activeZoneLights) > 0)
sortingArray.clear();
}
}
Code: Select all
void KE_LightManager::OnRenderPassPostRender(E_SCENE_NODE_RENDER_PASS renderPass)
{
//for(u32 i = 0; i < SceneLightList->size(); ++i)
//{
// ILightSceneNode* lightNode = static_cast<ILightSceneNode*>((*SceneLightList)[i]);
// lightNode->setVisible(false);
//}
//this setVisible is now done in the main loops of OnNodePrreRender
}
Code: Select all
#define MAXZONELIGHTS 5
ISceneNode* KE_LightManager::isZoneLit(ISceneNode* node)
{
if (!node)
return NULL;
scene::ISceneNode *parent = node->getParent();
for (u32 i = 0; i < MAXZONELIGHTS; i++) {
if (!parent)
return NULL;
if (parent->getType() == ESNT_EMPTY &&
parent->getName() &&
strcmp(parent->getName(), "zone") == 0)
return parent;
parent = parent->getParent();
}//for (u32 i = 0; i < MAXZONELIGHTS; i++)
return NULL;
}
s32 KE_LightManager::turnZoneLightsOn(ISceneNode* node)
{
if (!node)
return 0;
s32 activeZoneLights = 0;
const core::list<ISceneNode*>& tmpList = node->getChildren();
if (tmpList.getSize()) {
core::list<ISceneNode*>::ConstIterator it = tmpList.begin();
for (; it != tmpList.end(); ++it) {
if ((*it)->getType() == ESNT_LIGHT) {
ILightSceneNode* lightNode = (ILightSceneNode*)(*it);
lightNode->setVisible(true);
activeZoneLights++;
}//if ((*it)->getType() == ESNT_LIGHT)
}//for (; it != tmpList.end(); ++it)
}//if (tmpList.getSize())
return activeZoneLights;
}
bool KE_LightManager::isLightInZone(ISceneNode* zoneNode, ISceneNode* lightNode)
{
if (!zoneNode || !lightNode)
return false;
const core::list<ISceneNode*>& tmpList = zoneNode->getChildren();
if (tmpList.getSize()) {
core::list<ISceneNode*>::ConstIterator it = tmpList.begin();
for (; it != tmpList.end(); ++it) {
if ((*it) == lightNode)
return true;
}//for (; it != tmpList.end(); ++it)
}//if (tmpList.getSize())
return false;
}
Thanks rogerborg! saved me a lot time
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
Well, you're a dev team member, so go ahead If you want to discuss some things first do so here or on the dev ML
Maybe the Light setup method should go into ILightSceneNode? I was also thinking about a change there and add a setRadius method (in favor of the SLight value for radius, which would also set the attenuation initially). This was suggested by (sorry, don't remember ATM, maybe BlindSide?). This sounds reasonable and would make the lights more reliable across the drivers.
Oh, another request on this topic: Can someone write a nice tutorial for light effects and light nodes. I'd like to put a new tutorial up concerning these things (maybe including shadows, also good for testing )
Maybe the Light setup method should go into ILightSceneNode? I was also thinking about a change there and add a setRadius method (in favor of the SLight value for radius, which would also set the attenuation initially). This was suggested by (sorry, don't remember ATM, maybe BlindSide?). This sounds reasonable and would make the lights more reliable across the drivers.
Oh, another request on this topic: Can someone write a nice tutorial for light effects and light nodes. I'd like to put a new tutorial up concerning these things (maybe including shadows, also good for testing )
How do you solve the issue of occlusion? One of the "nearest" may be the other side of a wall, for example.We've been using it for about month now with out problems and fast frame rates
How about if no lights are "nearest"? [Yes, this is a valid concern - I saw it in a GI paper a few weeks ago]
Irrlicht Demos: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=6&t=45781
-
- Posts: 1638
- Joined: Mon Apr 30, 2007 3:24 am
- Location: Montreal, CANADA
- Contact: