RFC on new flexible ILightManager

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
sio2
Competition winner
Posts: 1003
Joined: Thu Sep 21, 2006 5:33 pm
Location: UK

Post by sio2 »

OK, I'll take a look at this. I need a light manager...
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

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.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

My prayer would be to get that code into the next release.

That would really make it easier for me to simply use it without doing extra work on my part.

Amen!
Image
sio2
Competition winner
Posts: 1003
Joined: Thu Sep 21, 2006 5:33 pm
Location: UK

Post by sio2 »

light manager, quake level, my Doom3 MD5 model loader, IrrAI, Newton physics...should be interesting...
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

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.
ecsos
Posts: 30
Joined: Mon Feb 04, 2008 8:02 am

Post by ecsos »

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.
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

I would love to see that code in the next release.

That would bring the quality of my test programs to the next level.

Just look at the screenshot image below. The test program uses two lights and the cool part of this test some of the materials use video::EMT_PARALLAX_MAP_SOLID.

Way cool, man!

Image
Image
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

There's no need for a light manager with usual hw drivers and just two lights. Even not with ogl-es. The light manager will help once your scene has more than the supported number of lights...
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

That's just the first of the series of test though.

More test programs will be made targeting much larger quantities, say number of lights. Surely, more textures with bump and heightmaps as well.

Fun all the way.
Image
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yeah, I also just found sio2's post in the screenshot thread where he reminded of the fact that shader materials can also impose a light limit (different to that one of the general hw capabilities).
sio2
Competition winner
Posts: 1003
Joined: Thu Sep 21, 2006 5:33 pm
Location: UK

Post by sio2 »

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.
varmint
Posts: 46
Joined: Fri Oct 06, 2006 4:33 pm

Post by varmint »

This is pretty awesome :) :D

I made a few changes so that we could have both zone lights and others. Performance is great! :D 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
}
And I changed the OnNodePreRender routine down to one loop.

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();
	}
}
And then OnRenderPassPostRender is no longer needed to turn off all the lights.

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
}
Here's some of the helper functions

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;
}
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 :D And I'd be more then happy to add it to the latest SVN if people want :D

Thanks rogerborg! :D saved me a lot time
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Well, you're a dev team member, so go ahead :wink: If you want to discuss some things first do so here or on the dev ML 8)
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 :) )
sio2
Competition winner
Posts: 1003
Joined: Thu Sep 21, 2006 5:33 pm
Location: UK

Post by sio2 »

We've been using it for about month now with out problems and fast frame rates
How do you solve the issue of occlusion? One of the "nearest" may be the other side of a wall, for example.

How about if no lights are "nearest"? [Yes, this is a valid concern - I saw it in a GI paper a few weeks ago]
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Post by christianclavet »

I've just stumbled on this thread, and it's really interesting.

My current levels use around 100+ lights (most of them are baked). But in order to use shaders (normal maps/specular, etc). This lightmanager code could be a great solution!
Post Reply