SFML community forums

General => General discussions => Topic started by: Dee on November 21, 2014, 11:04:05 pm

Title: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on November 21, 2014, 11:04:05 pm
Hey guys,

Even though I am not sure if there is already a full implementation of dynamic lighting for SFML, I know there have been some very promising experiments in this forum, particularly with the GLLight2D project.

In this context, I'd like to introduce the tool I am currently working on.
Sprite DLight generates voluminous normal maps from 2D sprites in one click, which allows for quick and easy dynamic lighting effects in 2D games. The project is currently running a pretty successful Kickstarter campaign here : http://kck.st/11fs6g5 (http://kck.st/11fs6g5)
The basic funding goal has been smashed within 17 hours and we are currently approaching the second stretch goal: a Mac version.

(http://1.bp.blogspot.com/-9q2PiFIWBLI/VGdzcbJdSuI/AAAAAAAABek/LATDbcQyYAI/s600/Sprite_DLight_Infograph_Kickstarter.png) (https://www.kickstarter.com/projects/2dee/sprite-dlight-instant-normal-maps-for-2d-graphics)

At the time of this post, there are 20 days left to back the project and to get in on the beta, which will start shortly after the campaign.

(http://3.bp.blogspot.com/-10JTHdQCS8s/VEOY6Uog8zI/AAAAAAAABao/OjRwPosh0cU/s224/Sprite_DLight_Ghost_Pizza.gif)
"Ghost Pizza", ©2010-2014 AlbertoV (DYA Games), normal map generated by Sprite DLight, dynamic lighting preview recorded in the Sprite Lamp shader

I would like to learn more about a possible integration with SFML and I appreciate any kind of feedback.


-Dennis
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on November 25, 2014, 11:59:32 pm
A small update: The tool will be available for Mac, the second stretch goal has been reached today.

(http://1.bp.blogspot.com/-_SH9uLv8IA4/VHT08dDNP_I/AAAAAAAABg0/OArS1gAxCwI/s600/Sprite_DLight_Mac.png) (https://www.kickstarter.com/projects/2dee/sprite-dlight-instant-normal-maps-for-2d-graphics/posts/1064199)
Title: AW: Sprite DLight - Instant normal maps for 2D graphics
Post by: eXpl0it3r on November 26, 2014, 10:26:04 am
You know that I've already backed you. I'm really glad for that it's running so smoothly. ;)
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Lo-X on November 26, 2014, 02:23:50 pm
I think that tool is awesome but I still have trouble to see how to integrate the texture into the game to have te 3D effect, with a shader ?
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: infinitebox on November 28, 2014, 01:01:42 am
I backed sprite lamp a long time ago. Just wondering what this adds?
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on November 28, 2014, 01:09:18 am
I know, Lukas, and I appreciate that, just like your tweets :)

Lo-X: Yes, you need a basic bump mapping shader to integrate the normal maps.

@infinitebox:
Sprite DLight is targeted to projects with larger numbers of sprites, where you just don't have the time to draw everything by hand (for Sprite Lamp, you have to draw 2-5 lighting profiles, which can result in a better quality, but takes a lot of time).
Think of animated characters. You would just process the sprite sheet in one click, resulting in quick normal maps that are all calculated with the same settings.
So Sprite Lamp is about maximum control and making your work easier, while Sprite DLight is about doing the work for you.
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on November 28, 2014, 01:11:44 am
I have just updated the project with a new feature: an animated dynamic lighting preview for sprite sheets.
To see the full update, including a video clip of the new feature, click the animation:

(http://2.bp.blogspot.com/-2hxB4vheuWM/VHe30QF5_nI/AAAAAAAABhE/OfGv5vbuAOE/s600/Sprite_DLight_Thanksgiving_Preview.gif) (https://www.kickstarter.com/projects/2dee/sprite-dlight-instant-normal-maps-for-2d-graphics/posts/1064477)
"Selen Run Animation", ©2014 Lunar Ray Games (http://timespinnergame.com), animated dynamic lighting preview of the sprite sheet in Sprite DLight
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Nexus on November 28, 2014, 11:22:49 am
That looks really interesting. For a lot of your examples, the original character textures are already quite polished and sometimes even have a shading/relief effect (e.g. the pumpkin guy). Do you have an example where you start with a very "flat" texture that has no lighting or relief at all, and show how you can enhance it using Sprite DLight? :)

Out of interest, is your software written using OpenGL directly?

By the way, this is not a general discussion about SFML, as such the projects forum would fit better ;)
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on November 29, 2014, 10:35:00 pm
Sorry if I posted in the wrong forum. I considered it a match for SFML general discussion, as I am asking about the status of dynamic lighting with SFML.

Feel free to send me any sprite you want me to test with the tool.

Sprite DLight is not using OpenGL, it doesn't use the CPU for the preview at all (which is kind of ineffective, but helps with the portability).
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Jabberwocky on November 30, 2014, 03:20:44 am
Very nice work, Dee.
Kickstarted.
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: lolz123 on November 30, 2014, 07:55:08 am
Hello Dee,

Quote
as I am asking about the status of dynamic lighting with SFML.

I don't know if you have seen this, but I am working on a remake of my original 2D dynamic shadows lighting system called Let There Be Light: http://en.sfml-dev.org/forums/index.php?topic=16895.0 (http://en.sfml-dev.org/forums/index.php?topic=16895.0)

Perhaps we can work together somehow and create the ultimate 2D lighting system!  8)
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: DJuego on November 30, 2014, 03:07:19 pm
Perhaps we can work together somehow and create the ultimate 2D lighting system!  8)

Boys! I am sure that something like that would attract tons of attention! The forum would collapse with the new subscriptions!! The video-game scene would change forever!!! ;D I am sure!

DJuego


Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on December 01, 2014, 12:32:09 am
Thank you, Jabberwocky, I appreciate your support :)

lolz123, when looking into SFML and shaders, I came across GLLight2D and LTBL.
I didn't know you were working on LTBL2, though, I thought, GLLight2D would be the successor of LTBL.

Anyway, the screenshots of your remake already look amazing. I cannot wait to see more!
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Mario on December 05, 2014, 06:34:00 pm
Feel free to send me any sprite you want me to test with the tool.

How about trying the SFML logo? It's rather flat, but it got that shiny courve as well as some minimal shading.
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on December 06, 2014, 01:16:13 am
Wonderful idea!

(http://3.bp.blogspot.com/-g2fToEmUDvk/VIJKZCeezbI/AAAAAAAABmA/CYb7QeG5CZI/s390/SFML_Normals.png)

(http://4.bp.blogspot.com/-5VDGT4IwlVQ/VIJKH_hNLUI/AAAAAAAABl4/viSfc6VYDxs/s390/SFML_Logo_Dynamic_Lighting.gif)
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: eXpl0it3r on December 06, 2014, 01:52:39 am
Nice! :)

I wonder how my avatar would do.

(https://i.imgur.com/kCzHHci.png)
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on December 06, 2014, 10:53:37 am
Your avatar is not a good match for the tool, because there is no plain background and no overall shape, so all I could do was to deactivate the shape detection and treat it like a tileable texture, which resulted in this:
(http://4.bp.blogspot.com/-ldCdZ7v9B5A/VILQsu0L_4I/AAAAAAAABmk/eq223hj7CP4/s200/Sprite_DLight_Lukas_Avatar_Normals.png)
(http://3.bp.blogspot.com/-MYgISlnYtS4/VILQyF222cI/AAAAAAAABms/VliuIhmDI2k/s200/Sprite_DLight_Lukas_Avatar.gif)
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on December 06, 2014, 08:17:11 pm
I am currently re-working the GUI, the flat map generation buttons have been replaced by shiny orbs, reflecting the style of the maps.

(http://2.bp.blogspot.com/-HKdUtEd3y54/VIM8hPKd6vI/AAAAAAAABnU/rsoS6gczQ04/s700/Sprite_DLight_UI_Normals.png)

Any feedback is appreciated.
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on December 11, 2014, 08:08:27 pm
The final countdown is running: 26 hours left to grab the tool at the Kickstarter backer price and to jump in for the beta. Thanks for your samples and help.
I really hope there will be some more progress with LTBL2 soon :)

(https://s3.amazonaws.com/ksr/assets/003/033/349/93de999f27770b425f1e5fc867c309ec_large.gif?1418246645)
"Skull Plant", ©2013 Kevin Chaloux (http://kaiseto.deviantart.com), normal map and dynamic lighting preview of Sprite DLight
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Jesper Juhl on December 11, 2014, 10:23:22 pm
Hi there

All the examples I've seen so far hav been Sprite DLight working on quite nice graphics. I'm currious what it could do with more primitive graphics.

For example; the game I'm currently working on features a "flattened cube" seen from above that players can roll across a board. It's very simple, it looks like this:
(http://images.chaosbits.net/sprite-dlight/cube.png)
And when it's coloured in-game it looks like this:
(http://images.chaosbits.net/sprite-dlight/cube-coloured.png)

I also have a few pick-up items like a heart for extra lives: (http://images.chaosbits.net/sprite-dlight/heart.png) a gem: (http://images.chaosbits.net/sprite-dlight/gem.png) and a coloured version of the gem: (http://images.chaosbits.net/sprite-dlight/gem-coloured.png)

What could the tool do with such primitive graphics?
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on December 12, 2014, 02:22:19 pm
Hi Jesper,

I tried your sprites with the tool, this is the result in the same order as you posted the sprites:
(http://1.bp.blogspot.com/-iT3NfF5ysQ8/VIrqeA0LvBI/AAAAAAAABpE/UQ6-g4LmpDY/s1600/Gems_Normals.png)

You see, there is not much of a difference between the grayscale sprites and the colored versions.
I didn't add the last gem because the background didn't consist of a single color, so the tool interpreted all the background noise as part of the object, which pretty much messed up the shape.
However, with a transparent or plain background, the normals would have looked quite similar to those of the gray version.
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: infinitebox on December 15, 2014, 01:39:40 am
Just realised the KickStarter campaign has finished and I forgot to pledge  :'(
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on December 15, 2014, 12:51:10 pm
That is not a problem, infinitebox, you can still pledge via PayPal here : http://2dee-art.blogspot.com/p/sprite-dlight.html (http://2dee-art.blogspot.com/p/sprite-dlight.html).
I slightly increased the price (and will furtherly increase it gradually), so KS backers who actively helped to make the project and the stretch goals possible, are rewarded for that.
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Tank on December 16, 2014, 09:06:20 am
The tool looks nice, well done. However it's sad that it's another nice piece which doesn't work in the GNU/Linux world. :(
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: select_this on December 16, 2014, 10:41:34 am
The tool looks nice, well done. However it's sad that it's another nice piece which doesn't work in the GNU/Linux world. :(

The Kickstarter says "Sprite DLight will be available for Windows, Mac and Linux systems."
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Tank on December 16, 2014, 11:15:43 am
Oh, I only saw "Mac version" in the stretch goals. Sorry then, and awesome that it comes to Linux! :)
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Dee on December 16, 2014, 12:57:23 pm
Of course it will work in Linux!
The tool was initially planned for Windows and Linux, and the Mac version was added after a lot of people asked for it.
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: Tank on December 16, 2014, 11:47:04 pm
Thanks for clarifying. :)
Title: Re: Sprite DLight - Instant normal maps for 2D graphics
Post by: SpeCter on December 21, 2014, 03:59:44 pm
Until LTBL2 people can play around with this.Basically it is a little deferred renderer.
At the moment it is only able to display light without ambient occlusion(easy to add through another pass for example) and specularity
Main.cpp
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Shader.hpp>
#include <SFML/Graphics/RenderTexture.hpp>
#include <memory>


const int width  = 800;
const int height = 600;
struct Light
{
   Light(sf::Vector3f col,sf::Vector3f pos,sf::Vector3f att) : color(col),
       position(pos),
       attenuation(att)
   {
   }
   sf::Vector3f color;
   sf::Vector3f position;
   sf::Vector3f attenuation;
};

int main()
{
   sf::RenderWindow window({width, height}, "Dynamic Lighting Test");

   // Front and backbuffer as Pointer for std::swap
   std::unique_ptr<sf::RenderTexture> front,back;
   sf::RenderTexture pass_normals,pass_diffuse;
   sf::Texture normal_map, diffuse_map;

   front    = std::unique_ptr<sf::RenderTexture>(new sf::RenderTexture());
   back     = std::unique_ptr<sf::RenderTexture>(new sf::RenderTexture());

   front->create(width, height);
   back->create(width, height);

   pass_normals.create(width, height);
   pass_diffuse.create(width, height);

   normal_map.loadFromFile("rock_normal.png");
   diffuse_map.loadFromFile("rock_diffuse.png");

   sf::Sprite sprite(diffuse_map);

   sf::Shader lights_shader;
   sf::Shader normals_shader;

   // Add a "warm" light, color needs to be in 0 - 1 range
   Light light(sf::Vector3f(255/255.0,214/255.0,170/255.0),
               sf::Vector3f(0,0,0.02),
               sf::Vector3f(0.5,0.5,0.5));


   lights_shader.loadFromFile("light.frag", sf::Shader::Fragment);
   normals_shader.loadFromFile("normals.frag",sf::Shader::Fragment);

   // Center Sprite
   sprite.setOrigin(150.0f,112.5f);
   sprite.setPosition(400,300);

   // Environmental variables
   float ambient_intensity = 0.7;
   sf::Vector3f falloff(0.5,0.5,0.5);

   while (window.isOpen())
   {
       sf::Event event;
       while (window.pollEvent(event))
       {
           if (event.type == sf::Event::Closed) window.close();

           // controls for environment
           // mousewheel to control height of the controlled light
           // + and - to control ambient light intensity
           // x and y to control controlled light falloff
           if (event.type == sf::Event::MouseWheelMoved)
           {
               light.position.z += event.mouseWheel.delta * 0.01;
           }

           if(event.type == sf::Event::KeyPressed)
           {
               if(event.key.code == sf::Keyboard::Add)
               {
                   ambient_intensity += 0.05f;
               }
               if(event.key.code == sf::Keyboard::Subtract)
               {
                   ambient_intensity -= 0.05f;
               }
               if(event.key.code == sf::Keyboard::Y)
               {
                   falloff /= 0.5f;
               }
               if(event.key.code == sf::Keyboard::X)
               {
                   falloff *= 0.5f;
               }
           }
       }

       // Clear renderbuffers
       back->clear();
       front->clear();
       pass_diffuse.clear();
       // Set normals buffer to neutral color
       pass_normals.clear(sf::Color(128,128,255));
       window.clear();

       // set light position, and adjust for different coordinate systems
       light.position.x = sf::Mouse::getPosition(window).x;
       light.position.y = 600 - sf::Mouse::getPosition(window).y;

       // Diffuse Pass, feed every sprite to draw here before display
       pass_diffuse.draw(sprite);
       pass_diffuse.display();

       // Normals Pass, feed every normal map which should be rendered here
       // For more then one repeat the next 2 steps before displaying
       normals_shader.setParameter("sampler_normal",normal_map);
       pass_normals.draw(sprite,&normals_shader);
       pass_normals.display();

       // Light Pass, renders every light into a rendertexture
       lights_shader.setParameter("resolution",sf::Vector2f(width, height));
       lights_shader.setParameter("sampler_normal",pass_normals.getTexture());
       lights_shader.setParameter("ambient_intensity",ambient_intensity);
       lights_shader.setParameter("falloff",falloff);

       // For more lights put the next 6 lines into a loop
       lights_shader.setParameter("sampler_light",front->getTexture());
       lights_shader.setParameter("light_pos",light.position);
       lights_shader.setParameter("light_color",light.color);
       back->draw(sf::Sprite(pass_diffuse.getTexture()),&lights_shader);
       back->display();
       std::swap(back,front);

       // Draw diffuse color
       window.draw(sf::Sprite(pass_diffuse.getTexture()));
       // Blend lighting over
       window.draw(sf::Sprite(front->getTexture()),sf::BlendMultiply);
       // Finally display it
       window.display();
   }

   return 0;
}
 

light.frag
#version 120
uniform vec2 resolution;
uniform sampler2D sampler_normal;
uniform sampler2D sampler_light;
uniform vec3 light_pos;
uniform vec3 light_color;
uniform vec3 ambient_color = vec3(0.5,0.5,0.5);
uniform float ambient_intensity = 0.5;
uniform vec3 falloff;

void main()
{

    vec2 coord = gl_TexCoord[0].xy;
    vec3 normal_map = texture2D(sampler_normal, coord).rgb;
    vec3 light_map = texture2D(sampler_light,coord).rgb;
    vec3 lightDir = vec3((light_pos.xy - gl_FragCoord.xy) / resolution.xy, light_pos.z);
    lightDir.x *= resolution.x / resolution.y;

    float D = length(lightDir);
    vec3 N = normalize(normal_map * 2.0 - 1.0);
    vec3 L = normalize(lightDir.xyz);

    vec3 diffuse = light_color.rgb * max(dot(N,L),0.0);
    vec3 ambient = ambient_color * ambient_intensity;

    float attenuation = 1.0 / (falloff.x + (falloff.y * D) + falloff.z*D*D);

    vec3 intensity = ambient + diffuse * attenuation;

    gl_FragColor = vec4(light_map + intensity, 1.0 );
}
 

normals.frag
uniform sampler2D sampler_normal;

void main(void)
{
    vec3 normal_map = texture2D(sampler_normal, gl_TexCoord[0].xy).rgb;
    gl_FragColor = vec4(normal_map,1.0);
}
 

This is what it looks like:
(https://dl.dropboxusercontent.com/u/1114083/dl.gif)

Depending on how the normals are generated you have to change:
vec3 N = normalize(normal_map * 2.0 - 1.0);

to:

vec3 N = -1.0 * normalize(normal_map * 2.0 - 1.0);

in the lights.frag

Ambient intensity can be controlled with + and -
Height of the controlled light with your mousewheel
The falloff of the light with x(higher) and y(lower)

Sorry for the long post and the large gif.

Edit: Link to gif hopefully fixed.