(C++) Directional lights

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
nomad
Posts: 53
Joined: Thu Jan 05, 2006 12:35 pm
Location: Wales

(C++) Directional lights

Post by nomad »

A few tips on using the ELT_DIRECTIONAL light. Directional lights are computationally less expensive than point lights so they are worth using, but the documentation doesn't really explain how to use them. It took me some time to figure out how to get this light working as a scene node, so this may save some time and hair-pulling:

1) Directional lights don't work with the EDT_OPENGL driver (Irrlicht 1.0)

2) To create a directional light as a scene node, use addLightSceneNode() as normal, then set the Type to ELT_DIRECTIONAL:

Code: Select all

	ILightSceneNode*  pLight = pIrrDevice->getSceneManager()->addLightSceneNode();
	SLight & l = pLight->getLightData();
	l.Type = ELT_DIRECTIONAL;
3) Set the light angle by changing the position, not the rotation of the scene node (no need to set SLight::Position). The position should be a unit-length vector. Easiest way to do this is create an empty scene node, move the light to (0,0,1) and make it a child of the empty node. Then when the empty node is rotated, the light angle changes as the light node moves. But don't move (i.e. translate) the empty node.

Code: Select all

	ISceneNode* pNode = pIrrDevice->getSceneManager()->addEmptySceneNode();
	pLight->setPosition(vector3df(0,0,1)); //default is (1,1,0) for directional lights
	pLight->setParent(pNode);
	//now rotate pNode to set light angle

For the EDT_OPENGL driver, a directional light could be simulated by adding a point light instead, putting it at (0,0,Radius/2), then translating the empty node along with the camera.

4) Dynamic lights don't cast shadows properly. The shadows are cast from the actual position of the light. This needs a small change to the engine to fix:

http://irrlicht.sourceforge.net/phpBB2/ ... 7902#77902

Hope this is helpful!
:)
Phxx
Posts: 13
Joined: Wed May 10, 2006 7:55 pm

Post by Phxx »

Thanks man!
Keyosz
Posts: 4
Joined: Wed Jul 14, 2010 8:31 am
Location: Italy

Post by Keyosz »

Thank you Nomad,
your informations have been usefull, i have found tricky to understand how to use it by simply read the docs provided the first time and the included samples show only how to use point lights, anyway if you agree i would like to add a sample code i have made myself to explain the directional lights subject to a friend and i hope this could speed up beginners in the future :)

This is the video of the sample below (i dunno how to incorporate embedded version in this forum...):
http://www.youtube.com/watch?v=zK_MsOuKXzo

Code: Select all

void AddAxes(IrrlichtDevice *device, float scale);

int main(int argc, char *argv[])
{
	int                     x,y,z;
	IrrlichtDevice         *device;
	IVideoDriver           *driver;
	ISceneManager          *smgr;
	IGUIEnvironment        *guienv;
    ICameraSceneNode       *camera;
	IAnimatedMesh          *dwarf_mesh;
	IAnimatedMeshSceneNode *dwarf_node;
    ILightSceneNode        *sun_node;
    SLight                  sun_data;
    ISceneNode             *sun_billboard;
    float                   sun_angle;

	//device=createDevice(video::EDT_DIRECT3D9,dimension2d<u32>(640,480),32,false,false,true,0);
	device=createDevice(video::EDT_OPENGL,dimension2d<u32>(640,480),32,false,false,true,0);
	if(!device)
	{
		return(1);
	}
	driver=device->getVideoDriver();
	smgr=device->getSceneManager();
	guienv=device->getGUIEnvironment();

    // An helper to show how coordinates goes in the scene
    AddAxes(device,100);

	// Add a camera to see the scene
	camera=smgr->addCameraSceneNodeFPS();
	camera->setPosition(vector3df(100,100,-100));
	camera->setTarget(vector3df(0,0,0));
    camera->setFarValue(1000.0f);
    camera->setNearValue(0.01f);

	// Loading a dwarf mesh and setup the node to reflect light
	dwarf_mesh=smgr->getMesh("dwarf.x");
	if(dwarf_mesh)
	{
        dwarf_node=smgr->addAnimatedMeshSceneNode(dwarf_mesh);
        if(dwarf_node)
        {
            int n,i;

            dwarf_node->setPosition(vector3df(0,0,-50));
            n=dwarf_node->getMaterialCount();
            for(i=0;i<n;i++)
            {
                SMaterial &mat=dwarf_node->getMaterial(i);

                mat.Lighting=true;
                mat.NormalizeNormals=true;
                mat.AmbientColor=SColor(255,255,255,255);
                mat.DiffuseColor=SColor(255,255,255,255);
                mat.EmissiveColor=SColor(255,0,0,0);
                mat.SpecularColor=SColor(255,255,255,255);
                switch(i)
                {
                case 0:
                    mat.setTexture(0,driver->getTexture("axe.jpg"));
                    break;
                default:
                case 1:
                    mat.setTexture(0,driver->getTexture("dwarf.jpg"));
                    break;
                }
            }
        }
	}

	// Add a cube of spheres usefull to see how directional light work from all sides
	// and how it have the same effect on different points in the scene
	for(x=0;x<4;x++)
	{
        for(y=0;y<4;y++)
        {
            for(z=0;z<4;z++)
            {
                IMeshSceneNode *sphere=smgr->addSphereSceneNode(10,16,0,-1,vector3df(0,0,0));
                sphere->setPosition(vector3df((x*100),50+(y*100),(z*100)));
                sphere->setMaterialFlag(EMF_NORMALIZE_NORMALS,true);
                sphere->setMaterialFlag(EMF_LIGHTING,true);
                sphere->setMaterialFlag(EMF_GOURAUD_SHADING,true);
            }
        }
	}

    // Setup the light source node
    sun_node=smgr->addLightSceneNode();
    sun_data.Direction=vector3df(0,0,0);
    sun_data.Type=video::ELT_DIRECTIONAL;
    sun_data.AmbientColor=video::SColorf(0.1f,0.1f,0.1f,1);
    sun_data.SpecularColor=video::SColorf(0.4f,0.4f,0.4f,1);
    sun_data.DiffuseColor=video::SColorf(1.0f,1.0f,1.0f,1);
    sun_data.CastShadows=false;
    sun_node->setLightData(sun_data);
    sun_node->setPosition(vector3df(0,0,0));
    sun_node->setRotation(vector3df(0,0,0));

    // Add a billboard that show how the sun angle change
    // the distance of the billboard from the origin (0,0,0) is set at 100
    // but do not alter how the sun cast rays on objects because it only depends by sun_angle
    sun_billboard=smgr->addBillboardSceneNode(sun_node,core::dimension2d<f32>(60, 60));
    if(sun_billboard)
    {
        sun_billboard->setPosition(vector3df(0,0,-100));
        sun_billboard->setMaterialFlag(video::EMF_LIGHTING,false);
        sun_billboard->setMaterialFlag(video::EMF_ZWRITE_ENABLE,false);
        sun_billboard->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
        sun_billboard->setMaterialTexture(0,driver->getTexture("particlewhite.bmp"));
    }

    // The main loop that emulate in a very simple way the day/night cicle just by rotating the sun node
    sun_angle=0;
    while(device->run())
	{
        sun_node->setRotation(vector3df(sun_angle,0,0));
        sun_angle+=0.5;
        if(sun_angle>=360) sun_angle=0;

		driver->beginScene(true,true,SColor(255,100,101,140));

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

		driver->endScene();
	}

	device->drop();

	return 0;
}


void AddAxes(IrrlichtDevice *device, float scale)
{
    ISceneNode *node;
    IGUIFont   *font=device->getGUIEnvironment()->getFont("bigfont.png");

    node=device->getSceneManager()->addMeshSceneNode(device->getSceneManager()->addArrowMesh("AddAxesMeshX",SColor(255,255,0,0),SColor(255,255,0,0),4,8,scale,scale*0.8f,scale*0.02f,scale*0.05f));
    node->setMaterialFlag(EMF_NORMALIZE_NORMALS,true);
    node->setMaterialFlag(EMF_LIGHTING,false);
    node->setMaterialFlag(EMF_GOURAUD_SHADING,true);
    node->setRotation(vector3df(0,0,-90));
    device->getSceneManager()->addTextSceneNode(font,L"+X",SColor(255,255,255,255),0,vector3df(scale,0,0));

    node=device->getSceneManager()->addMeshSceneNode(device->getSceneManager()->addArrowMesh("AddAxesMeshY",SColor(255,0,255,0),SColor(255,0,255,0),4,8,scale,scale*0.8f,scale*0.02f,scale*0.05f));
    node->setMaterialFlag(EMF_NORMALIZE_NORMALS,true);
    node->setMaterialFlag(EMF_LIGHTING,false);
    node->setMaterialFlag(EMF_GOURAUD_SHADING,true);
    node->setRotation(vector3df(0,0,0));
    device->getSceneManager()->addTextSceneNode(font,L"+Y",SColor(255,255,255,255),0,vector3df(0,scale,0));

    node=device->getSceneManager()->addMeshSceneNode(device->getSceneManager()->addArrowMesh("AddAxesMeshZ",SColor(255,0,0,255),SColor(255,0,0,255),4,8,scale,scale*0.8f,scale*0.02f,scale*0.05f));
    node->setMaterialFlag(EMF_NORMALIZE_NORMALS,true);
    node->setMaterialFlag(EMF_LIGHTING,false);
    node->setMaterialFlag(EMF_GOURAUD_SHADING,true);
    node->setRotation(vector3df(90,0,0));
    device->getSceneManager()->addTextSceneNode(font,L"+Z",SColor(255,255,255,255),0,vector3df(0,0,scale));
}
Post Reply