Tutorial 11: Lighting Node

In this tutorial you will learn how to use lighting effects and mouse input.

Before starting this tutorial be sure to setup an empty project with the Setup Tutorial.

 

what are we going to get?

at the end of this tutorial we will have this code:

    Ness::SpritePtr back = scene->create_sprite("ness-engine/resources/gfx/forest_background.jpg");

    back->set_scale(1.5f);

That's it. :)

Now that you know about lighting, it's time to learn about particle nodes!
 
continue to next tutorial -->

#include <NessEngine.h>

 

int _tmain(int argc, _TCHAR* argv[])

{

    Ness::init();

    Ness::Renderer renderer("new project", Ness::Sizei(800,600));

 

    // create the scene and znode

    Ness::ScenePtr scene = renderer.create_scene();

    Ness::ZNodePtr node = scene->create_znode();

 

    // set sprite defaults

    Ness::Sprite::Defaults.anchor = Ness::Point(0.5f, 1.0f);

    Ness::Sprite::Defaults.alpha_channels = true;

 

    // create trees

    for (unsigned int i = 0; i < 25; i++)

    {

        Ness::SpritePtr tree = node->create_sprite("ness-engine/resources/gfx/tree.png");

        tree->set_position(Ness::Pointi(rand() % renderer.get_screen_size().x, rand() % renderer.get_screen_size().y));

        tree->set_zindex(tree->get_position().y);

    }

 

    // create the light node

    Ness::LightNodePtr lightNode = scene->create_light_node();

    lightNode->set_ambient_color(Ness::Color(0.0f, 0.2f, 0.4f, 1.0f));

 

    // create a light

    Ness::LightPtr light = lightNode->create_light("ness-engine/resources/gfx/light_round.jpg");

 

    // event handlers

    Ness::Utils::EventsPoller EventsPoller;

    Ness::Utils::ApplicationEvents app;

    EventsPoller.add_handler(app);

    Ness::Utils::Mouse mouse;

    EventsPoller.add_handler(mouse);

 

    // main loop

    while( !app.got_quit() )

    {

        EventsPoller.poll_events();

 

        // set light position

        light->set_position(mouse.position());

 

        // render

        renderer.start_frame();

        scene->render();

        renderer.end_frame();

    }

}

Ness::LightNodePtr lightNode = scene->create_light_node();

lightNode->set_ambient_color(Ness::Color(0.0f, 0.2f, 0.4f, 1.0f));

 

    Ness::init();

    Ness::Renderer renderer("new project", Ness::Sizei(800,600));

 

    // create the scene and znode

    Ness::ScenePtr scene = renderer.create_scene();

    Ness::ZNodePtr node = scene->create_znode();

 

    // set sprite defaults

    Ness::Sprite::Defaults.anchor = Ness::Point(0.5f, 1.0f);

    Ness::Sprite::Defaults.alpha_channels = true;

 

    // create trees

    for (unsigned int i = 0; i < 25; i++)

    {

        Ness::SpritePtr tree = node->create_sprite("ness-engine/resources/gfx/tree.png");

        tree->set_position(Ness::Pointi(rand() % renderer.get_screen_size().x, rand() % renderer.get_screen_size().y));

        tree->set_zindex(tree->get_position().y);

    }

Ness::LightPtr light = lightNode->create_light("ness-engine/resources/gfx/light_round.jpg");

Step 3: creating a light

Now let's create a light on the light node:

    Ness::Utils::EventsPoller EventsPoller;

    Ness::Utils::ApplicationEvents app;

    EventsPoller.add_handler(app);

    Ness::Utils::Mouse mouse;

    EventsPoller.add_handler(mouse);

 

    // main loop

    while( !app.got_quit() )

    {

        EventsPoller.poll_events();

 

        // set light position

        light->set_position(mouse.position());

 

        // render

        renderer.start_frame();

        scene->render();

        renderer.end_frame();

    }

}

which will produce the following window:

when moving the mouse the light will follow the mouse position.

 

Step 1: creating the background

First let's create the background, nothing new here:

note that we are using znode that will order the trees by their z-index. if you missed this subject, it is covered in this tutorial.

 

Step 2: creating the light node

Now it's time to create the lighting node:

it's important to create the light node last because the light node, like every entity in ness-engine, also has rendering order and will only cover things that are rendered under it.

 

note the second line: set_ambient_color(). ambient color is simply the color that will be shown where there are no lights, i.e. the "darkest" color.

 

How lighting node works?

Lighting node works in a very simple way: when created, the light node creates a texture in the size of the entire screen. this texture is filled with the ambient color (defaults to black), and when the light node is rendered it actually renders the texture all over the screen with modulate blend:

when adding "lights" to the light node, what you are actually adding is sprites that are rendered over the light node texture with additive blending, making it brighter.  because the light-node texture eventually renders on screen with mod effect, brighter means less visible. so if we rendered a light in the example above, it will look like this:

Transforming light node

Remember that eventually the light node is just a texture rendered on the entire screen, so transforming the light node actually transforms the light node texture.

for example, take a look at this:

at the left side is the original scene. at the right side we set the light node color to red (lightNode->set_color(Ness::Color::RED);), which was applied on the light node texture:

creating a light is just like creating a sprite (Light inherits from Sprite). so every transformation you can apply on a sprite you can also apply on a light. changing light color is done by using set_color().

 

you can add as many lights as you want.

 

Step 4: adding mouse controls

Now it's time to add mouse controls:

Mouse handler works just like Keyboard handler and setting light position is like setting sprite position.

 

Light node optimization

Light nodes basically have two things to render: first render the lights on the light texture itself, and then render the light texture over the screen.

To make the lighting more efficient, light nodes only redraw their texture when one of the visible lights changes. if for any reason you wish to drop this optimization, you can force the light node to always redraw by calling set_always_refresh().

 

Changing light-node color

When you change the color of a light node you basically change the color of the canvas the lights are rendered on. the result is effect on all existing lights + the ambient color. making the light node red will make the entire environment red, as long as the ambient color have enough red element in it.

 

Additive Lights

You might want to create additive lights for some special effects. additive lights are lights that actually make the lit areas brighter then they are. to make a light-node additive simply change its blend mode to BLEND_MODE_ADDITIVE.

 

A good way to create nice light effects is to create two light nodes: one for all the basic lights, and another for additive lights at special effects.

 

Shadows

You should know there is also a shadow-node that works just like the lights-node, but makes shadows (areas that are darker) instead of lights.

 
Creating a night-vision effect

the following is a quick snippet to create a cool night-vision like effect!

Ness::LightNodePtr lightNode = top_node->create_light_node();

lightNode->set_ambient_color(Ness::Color::GREEN * 0.35f);

lightNode->set_color(Ness::Color(0.1f, 2.0f, 0.1f));

 

Ness::LightPtr lines = lightNode->create_light("gfx/effects/horiz_lines.png");

lines->set_anchor(Ness::Point::ZERO);

lines->set_static(true);

lines->set_size(renderer.get_screen_size() + Ness::Point(0.0f, 50.0f));

What the snippet do is the following:

  1. we create a new lighting node.

  2. we set the ambient color to dark green (meaning the "dark" parts will actually be green)

  3. we set the node color to strong green with weak red and blue. this will affect all future lights we will add to the node and turn them bright-green.

  4. we create a light that will cover the entire screen from "horiz_lines.png" texture. this texture consist of black & white horizontal lines that will give a cool touch to the effect. the texture looks like this:

and to make the horizontal lines effect look more alive, inside the game main loop we change its position randomly:

lines->set_position(Ness::Pointi(0, -rand() % 50));

And the final result of this effect looks like this:

There are many cool effects you can create with the lighting node! just let your imagination go wild...

Help ness-engine grow!