Ok, I've "solved" this, but I'm putting "solved" in quotes because it's not a very good solution. The real solution would be to tinker with the CSceneManager code itself and slightly change the order in which lights are handled.
The problem is exactly as you stated -- the render() function of CLightSceneNode has already happened before OnNodePreRender(), which means that addDynamicLight() has already happened for all the lights. So if you start changing light colors, etc, you're really doing nothing for the current render pass.
To work around, instead of storing CLightSceneNode pointers and sorting them, I store actual SLight objects. Then, my OnNodePreRender() becomes this:
Code: Select all
// Called before the specified scene node is rendered
virtual void OnNodePreRender(irr::scene::ISceneNode* node)
{
// Only calculate light distances during "solid" render pass
if (m_current_render_pass != irr::scene::ESNRP_SOLID)
{
return;
}
// The "m_sorted_lights" vector is sorted here, by distance ... [0] is now the closest and [1] is the farthest from the node
// Remove all lights from the driver
m_scene->getVideoDriver()->deleteAllDynamicLights();
s32 index;
// Enable the closest light, make it yellow
m_sorted_lights[0].m_light_data.DiffuseColor.set(1.0f, 1.0f, 0.0f);
index = m_scene->getVideoDriver()->addDynamicLight(m_sorted_lights[0].m_light_data);
m_scene->getVideoDriver()->turnLightOn(index, true);
// Disable the farthest light, make it cyan
m_sorted_lights[0].m_light_data.DiffuseColor.set(0.0f, 1.0f, 1.0f);
index = m_scene->getVideoDriver()->addDynamicLight(m_sorted_lights[0].m_light_data);
m_scene->getVideoDriver()->turnLightOn(index, true);
}
This works! I'm actually removing all the lights from the driver and then re-adding them in sorted order. There doesn't seem to be a huge performance hit with this approach.
In case anyone comes across this and wonders why anyone would want to do this... My initial idea was to just choose the eight lights closest to the current node and turn them on, while turning all other lights off. That way, I could have any number of lights in the scene, but each node would only be lit by the eight closest. When I tried this approach, I could see really severe "popping" of the lights. As one light moved just a little farther away than another, it would instantly turn off and the other light would turn on. The effect was very ugly and not realistic at all.
So, I thought, I could interpolate the color of the eighth closest light. As the ninth closest light got closer and closer, I would fade the color of the eighth light out, gradually, as the ninth light faded in. This failed because it's too late to change light colors. But now, I can modify light colors by dealing directly with the SLight data instead of the CLightSceneNode data.
Thanks.