Entropy Lighting Tutorial

From LagoonWiki

Jump to: navigation, search

This tutorial introduces the basics of lighting for Galaga/Entropy/Ogre3D.

Contents

Before You Start

Turn off your fog effects for now. You may also want to comment out any intensive particle effects that make the rendering sluggish.

Before you start working with the lights, define some colors to make life easier. This should go near the beginning of OgreApplication::createScene() in ogreApplication.cc:

ColourValue black(0.0,0.0,0.0);
ColourValue darkgrey(0.1,0.1,0.1);
ColourValue mediumgrey(0.5,0.5,0.5);
ColourValue lightgrey(0.9,0.9,0.9);
ColourValue white(1.0,1.0,1.0);

ColourValue brightred(1.0,0.0,0.0);
ColourValue brightgreen(0.0,1.0,0.0);
ColourValue brightblue(0.0,0.0,1.0);

You may also have a fogcolour already defined from an earlier tutorial.

Turn off the ambient lighting so that you will be able to see its effect more clearly when we add it back in. The line must be present for lighting to work correctly, so just set the color to black:

sceneManager->setAmbientLight(black);

Note: This line is already in the code, but the color it specifies will depend on when you checked the code out. Set it to black now, whatever it is.

Finally, turn off any direct lighting by commenting out the code that defines it. You may have one or two lights predefined, and they may be various colors, depending on when you checked the code out. Comment out any blocks of code that look similar to this:

//Light* sunLight1 = sceneManager->createLight("sunLight1");
//sunLight1->setType(Light::LT_DIRECTIONAL);
//Vector3 dir1(-1.0, -1.0, -1.0);
//dir1.normalise();
//sunLight1->setDirection(dir1);
//sunLight1->setDiffuseColour(white);
//sunLight1->setSpecularColour(white);

Provide an Object to View

So far we have not actually been using 3D lighting effects; the skybox, skyplane, ground, and particle systems have taken care of their own lighting. So to get started with lighting, we need to put a 3D model into the game. For present purposes we will just grab one from the entropy_dependencies directory; we will cover models in more detail later.

The following commands assume that you still have entropy_dependencies checked out, and your present working directory is the top-level entropy directory.

Create a directory to hold your models:

mkdir galaga/data/models/

Be sure to add it to resources.cfg so that anything you put there will be loaded when you start the engine.

Copy a robot model from entropy_dependencies:

cp ../entropy_dependencies/ogrenew/Samples/Media/models/robot.mesh galaga/data/models

The model is loaded and positioned with a scene node, very similarly to the way your particle effect system was. Add the following code to ogreApplication.cc near where you load your particle system:

Entity *robot1 = sceneManager->createEntity( "Robot1", "robot.mesh" );
SceneNode *robot1node = sceneManager->getRootSceneNode()->createChildSceneNode( "Robot1Node", Vector3( 600, 50, 900 ) );
robot1node->attachObject( robot1 );

Place it somewhat away from your particle system(s) so you will be able to see it clearly. The elevation will depend on how high your terrain is at that location; you can adjust it as we experiment with the lighting.

Now recompile and start the game, and spin your camera until you can see the robot. It should appear pitch black; if not, you have not turned all the lighting off correctly.

Sunlight

The first kind of light we will create is rendered as if it shines from an infinite distance. It is good for rendering sunlight. Uncomment one of the blocks of code that you just commented out, and set its values to look like this:

Light* sunLight = sceneManager->createLight("sunLight");
sunLight->setType(Light::LT_DIRECTIONAL);
Vector3 dir1(0.0, -1.0, 0.0);
dir1.normalise();
sunLight->setDirection(dir1);
sunLight->setDiffuseColour(lightgrey);
sunLight->setSpecularColour(white);

The code defines a light named "sunLight" and catches its handle in the variable sunLight1. It defines the lights type to LT_DIRECTIONAL, which is what makes it an infinitely distant source. It then defines the light's direction via a vector; in this example the light shines straight down. Then it sets the light's colors. The difuse color is what it generally lights things up with; the specular color is the color of any bright spots that reflect directly back at you, light the 'highlight' on a painting of an apple.

Recompile and start your game, and examine the effects. (It may be difficult to get the camera into a position where you will actually see the specular color.)

Now change the colors and direction of the light several times, to make sure you understand what the code is doing.

Ambient Light

Notice that the side of the robot away from the light is still pitch black. That looks correct if your robot is standing on the Moon, but in an atmosphere the sun's light will scatter and light up even the back side somewhat.

In games we emulate that effect with ambient light. For this engine we do it with the line that we set to black earlier:

sceneManager->setAmbientLight(black);

Look carefully at your robot, then change the ambient light to another color such as dark grey, and compare the effect.

On our planet the atmosphere scatters the blue end of the spectrum most (which is why the sky looks blue), and leaves the sun looking yellowish due to the subtracted blue. Modify your colors to give the ambient light a blue tint and reduce the blue in the direct lighting.

Turn on a thick fog and zoom away from your robot in various directions to see how the fog and the lighting interact.

If your scene uses lots of fog, you may want to set the colors similar to the tint of the fog. Play with the colors of the sunlight and ambient light to create a nice effect for your scene.

In-Scene Lighting

You can use as many lights as you wish. A second light may help make your robot look 3D on the shadowy side. For this example we will make the light a point source located within the scene:

Light* pointLight = sceneManager->createLight("pointLight");
pointLight->setType(Light::LT_POINT);
pointLight->setPosition(Vector3(750,200,750));
pointLight->setDiffuseColour(brightblue);
pointLight->setSpecularColour(white);

Notice the new type, and the fact that you set a position rather than a direction. Otherwise the code is very similar.

Put the light near but not directly on the robot, and pick a color that contrasts with your sunlight. Turn the fog back off, recompile, and restart the engine. Move your camera around your robot to see how the colors and lighting effects change with the angle of view.

When you start creating 3D models you can make a lamp to put into your scene, and place a point light at the same location, so it will look like the lamp is actually lighting the scene.

You can also create spotlights, i.e. directional lights emitted from a place in the scene, but this tutorial does not cover them.

Shadows

Shadows can be turned on with a single line of code. However, at present you do not have anything to catch the robot's shadow - the sky and the terrain we are using are not rendered by the normal mechanism, and thus do not show shadows.

Create a new flat ground plane with this code, which you can put in ogreApplication.cc near where you created the skyplane:

Plane groundPlane(Vector3::UNIT_Y, 25);
MeshManager::getSingleton().createPlane("groundplane",
   ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, groundPlane,
   5000,5000,20,20,true,1,10,10,Vector3::UNIT_Z);

The first line creates a plane as before, but with simpler syntax to show its elevation and facing. The 25 is the elevation; make it the same as your robot's current elevation. The second line creates a mesh for the plane, and is not explained in this tutorial.

The rest of the code is similar to the code for creating particle effects, except that now we are creating an 'entity':

Entity *groundEntity = sceneManager->createEntity("GroundEntity", "groundplane");
sceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity);
groundEntity->setMaterialName("Ground");
groundEntity->setCastShadows(false);

The third line defines a material for the ground, and the fourth line causes this entity not to cast any shadows; there is no point in rendering shadows that will not be visible in the game.

The material script for the ground is very simple, and lacks all the special flags we used in earlier materials:

material Ground
{
   technique
   {
     pass
     {
        texture_unit
        {
           texture ground.png
        }
     }
   }
}

Comment out the line that creates your existing terrain, recompile, and check to make sure you see the robot standing on your new ground plane.

Now enable shadows in the engine with this line, which you can place where you create your lights:

sceneManager->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);

There are three shadow models for this engine. SHADOWTYPE_STENCIL_ADDITIVE does the most accurate rendering, but also places the most load on the engine at run time. SHADOWTYPE_TEXTURE_MODULATIVE is the least accurate and least resource intensive, and SHADOWTYPE_STENCIL_MODULATIVE lies in between the other two. Try all three types and compate their effects.