SLight Attenuation proper setup suggestion

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

SLight Attenuation proper setup suggestion

Post by arras »

Note: this is for OpenGL, I do not know how light attenuation works in DX.

I used to have hard time to set up my scene lights properly. It was mostly because I did not understood how attenuation works. It is also I think, because default ILightSceneNode attributes created by ISceneManager::addLightSceneNode() are not set very well.

SLight::Attenuation have three members(factors): constant, linear and quadratic.
Those are set by default to 0, 0.01, 0 in ILightSceneNode created by ISceneManager. Now formula which calculates light in OpenGL is this:

Code: Select all

attentuation = 1.0 / (constantAttenuation + linearAttenuation * distance + quadraticAttenuation * distance * distance);

final colour = colour * attenuation;
where colour is colour of pixel after all other calculations were made including light, material, texture.

With preset attributes we can see that attenuation at some distances can actually be larger that 1 (1 / 0.01*10 = 10 for example), multiplicating all other effects in process. This cause object at those distances bee lit by too strong light (those are near distances by default).

Attenuation should cause light effect to fade away with distance but never to increase its strength beyond values set in diffuse specular and ambient attributes. This of course requires, that attenuation is newer larger than 1. Given formula above it means that sum of constant, linear and quadratic attributes should newer be smaller than 1. If this sum is exactly 1, light do not fade over distance and is constant. So 1 should be default sum of those attributes.

My suggestion is that constant attenuation should be set at 1 by default as it is most logical value in relation to other two. If for example linear attenuation is then set to 0.01 (as it is now per default) it will cause light to decrease by 1% per unit of distance which is what would user expect I think.

Here is example I set up to demonstrate problem. Comment/uncomment line ldata->Attenuation.X = 1.f; to see the difference:

Code: Select all

#include <irrlicht.h>
using namespace irr;

int main()
{
   IrrlichtDevice *device = createDevice(video::EDT_OPENGL,
      core::dimension2d<u32>(640, 480), 16, false, false, false, 0);

   video::IVideoDriver* driver = device->getVideoDriver();
   scene::ISceneManager* smgr = device->getSceneManager();
   gui::IGUIEnvironment* guienv = device->getGUIEnvironment();

   // sphere
   scene::ISceneNode *sphere = smgr->addSphereSceneNode(5.f, 32);
   sphere->setPosition(core::vector3df(0.f,0.f,7.f));

   // light position marker
   scene::ISceneNode *lightMarker = smgr->addSphereSceneNode(0.2f);
   lightMarker->setMaterialFlag(video::EMF_WIREFRAME, true);
   lightMarker->setMaterialFlag(video::EMF_LIGHTING, false);

   // camera
   scene::ICameraSceneNode* camera = smgr->addCameraSceneNode();
   camera->setPosition(core::vector3df(10.f, 0.f, -5.f));

   // light
   scene::ILightSceneNode *light = smgr->addLightSceneNode();
   video::SLight *ldata = &light->getLightData();
   //ldata->Attenuation.X = 1.f;

   // some text
   gui::IGUIStaticText *text1 =
      guienv->addStaticText(0, core::rect<s32>(10,10,500,30));
   gui::IGUIStaticText *text2 =
      guienv->addStaticText(0, core::rect<s32>(10,30,500,60));

   u32 oldTime = 1000;

   while(device->run())
   {
      driver->beginScene(true, true, video::SColor(0,100,100,120));

      // move sphere away afther 1 second
      u32 time = device->getTimer()->getTime();

      if(time > 1000)
      {
         u32 deltaT = time - oldTime;
         if(deltaT) oldTime = time;

         sphere->setPosition(sphere->getPosition() +
            core::vector3df(0.f, 0.f, 0.005f * deltaT));
      }

      // point camera at sphere
      camera->setTarget(sphere->getPosition());

      // set text
      core::stringw str(L"Constant Attenuation = ");
      str += ldata->Attenuation.X;
      str += L"     Linear Attenuation = ";
      str += ldata->Attenuation.Y;
      str += L"     Quadratic Attenuation = ";
      str += ldata->Attenuation.Z;
      text1->setText(str.c_str());

      str = L"Distance: ";
      str += (s32)(sphere->getPosition()-light->getPosition()).getLength();
      text2->setText(str.c_str());

      smgr->drawAll();
      guienv->drawAll();

      driver->endScene();
   }

   device->drop();

   return 0;
}
Post Reply