top of page

Diffuse lighting

  • itzvnodm
  • Nov 25, 2014
  • 4 min read

Purpose:

The assignment was to

  • Add ambient and directional lighting support to the engine.

Adding ambient and directional lighting:

Light determines the color and brightness of an object along with its material. For this assignment, I am adding Diffuse Lighting model support for my engine. Diffuse lighting model is the reflection of light from a surface such that an incident ray is reflected at many angles rather than at just one angle as shown below,

DiffuseSmooth.png

This makes the surface look smooth (matte). Which means a plane will look equally lit when looking from different camera directions.

DiffuseLight.png

In DirectX we reduce the surface brightness of an object which is facing away from the light. How do we know if an object is lit or is facing away from the light? For that, we need,

  • Direction of the light: since this is directional light, we don’t consider the position of the light source and assume that every ray of light falling on an object plane affects it equally.

  • Surface normal of every pixel on the object: Surface normal of a point on a plane is the perpendicular vector that is pointing outwards from the surface as shown in the below image. Surface normal can be used to determine the amount a directional light that can affect a point on an object. More parallel a surface normal is to the light direction, (Or technically Anti-Parallel, since light is facing inwards to object surface) more lit is the surface. As the surface normal moves away or surface bends or rotates away from the light, the darker it looks. Observe the sides of the surface that are darker than the central bulge (considering that the light is falling on the center).

Surface_normal.png

So we pretty much have light direction and the surface normal to determine the amount of light at a surface point. The below image better illustrates the explanation. Notice the angle between “Normal” and “Direction”, which can be used to determine how much a Point on a surface is lit. In other words, a Dot Product can be used to calculate the amount of light that affects a point given the normal and light direction.

  • Ambient light: In reality the ambient light is the light that affects an object surface and is reflected from multiple surfaces around it. This light, even if an object is not facing the directional light source, makes the surface of an object visible to a certain extent. Here we are using a dark light value to add to the actual directional light to simulate the effect of ambient lighting.

Implementation:

MayaExporter plugin outputs the model space normal as part of the mesh file. Vertex shader gets the normal in model coordinates of each vertex and calculates the normal in world coordinates. I pass in the normal in world coordinates to the fragment shader from the vertex shader. The whole lighting calculation happens in the fragment shader.

If you want to debug a rendered pixel, right click it, and select Debug This Pixel:

Which gives the debug info for that pixel,

If you click on the “Debug Pixel (546, 479)” hyperlink, you can see how the calculation of the final color is done. The comments in the fragment shader below explains each step for the final light calculation.

PixOUtPutOfShaderDebug.PNG

Final Output: (Modify the light direction using U, J, H, K)

FinalOutput.PNG

Extra:

  • Added Lua Helper: I did not want to hard-code the lighting data of the game. For that I wanted to create a Lua file just for lighting. Even before I considered writing a new Lua file, I wanted to remove all the duplicate Lua loading code that I had in my Material and mesh loading logic. I started writing a LuaHelper lib that had all the generic Lua load, parse, read and loop tables’ functions. Creating this was easier, the hard part was modifying the existing material and mesh load code to use the new functions. All the error checking, message display and most parts of the module had to be redone. I am happy I got this in, but then this took a ton of my time to get everything back to the way it was.

  • Added Scene / Level file and Level loader to load all actors and lighting data: Now that I had the Lua Helper, it was easy for me to create a Lua file for lighting. But then I argued against that and created a scene / level file. A level file not only stores the lighting data, but also stores all the actors’ information (Camera information, soon). This way multiple level files can have their own lighting data from which the game can load and set all the required details dynamically. Doing this removed all the hard-coded actor creation code in my Game. Below is the level file for the project.

  • Removed hard-coding of constant names: This helps when we want to have two different shaders of the same type with different constant names. For this, we need a common terminology to access the constants, rather than hard-coding them in code. Currently, I have six constants that are not specific to a material, but have hard coded names in shaders. The name value pairs below associates the “Global Name for a constant in material file’s shader table” to it's “Actual name in shader”.

  • ModelToWorld = "g_transform_modelToWorld",

  • WorldToView = "g_transform_worldToView",

  • ViewToScreen = "g_transform_viewToScreen",

  • AmbientLight = "g_lighting_ambient",

  • DiffuseLight = "g_lighting",

  • LightDirection = "g_light_direction",

The material now has all of these name value pairs in the corresponding Lua shader table as shown below,

material.PNG

Example flow for ambient light constant mapping: Whenever a light is created in the game, engine reads the name and value of AmbientLight from the level file and stores it in an object. While parsing the material file the engine then uses the same global name (AmbientLight) to get the shader constant name value (g_lighting_ambient) and eventually stores the handle and default value in memory. During material Set function of each render call, the engine sets the “constant by name (AmbientLight)”. Since we have AmbientLight mapped to g_lighting_ambient’s handle, it works perfectly.

Time Spent:

Adding directional lighting support: 4hrs

Extra: 9hrs

Write-up: 2hr

Total: 15hrs


 
 
 

Comments


Recent Posts
Archive
Search By Tags
bottom of page