Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Sprite DLight - Instant normal maps for 2D graphics  (Read 24803 times)

0 Members and 1 Guest are viewing this topic.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #15 on: December 06, 2014, 01:52:39 am »
Nice! :)

I wonder how my avatar would do.

Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Dee

  • Newbie
  • *
  • Posts: 22
    • View Profile
    • Sprite DLight - Instant normal maps for 2D graphics
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #16 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:


Dee

  • Newbie
  • *
  • Posts: 22
    • View Profile
    • Sprite DLight - Instant normal maps for 2D graphics
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #17 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.



Any feedback is appreciated.

Dee

  • Newbie
  • *
  • Posts: 22
    • View Profile
    • Sprite DLight - Instant normal maps for 2D graphics
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #18 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 :)


"Skull Plant", ©2013 Kevin Chaloux, normal map and dynamic lighting preview of Sprite DLight

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #19 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:

And when it's coloured in-game it looks like this:


I also have a few pick-up items like a heart for extra lives: a gem: and a coloured version of the gem:

What could the tool do with such primitive graphics?

Dee

  • Newbie
  • *
  • Posts: 22
    • View Profile
    • Sprite DLight - Instant normal maps for 2D graphics
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #20 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:


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.

infinitebox

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #21 on: December 15, 2014, 01:39:40 am »
Just realised the KickStarter campaign has finished and I forgot to pledge  :'(

Dee

  • Newbie
  • *
  • Posts: 22
    • View Profile
    • Sprite DLight - Instant normal maps for 2D graphics
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #22 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.
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.

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #23 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. :(

select_this

  • Full Member
  • ***
  • Posts: 130
  • Current mood: just ate a pinecone
    • View Profile
    • darrenferrie.com
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #24 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."
Follow me on Twitter, why don'tcha? @select_this

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #25 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! :)

Dee

  • Newbie
  • *
  • Posts: 22
    • View Profile
    • Sprite DLight - Instant normal maps for 2D graphics
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #26 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.

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #27 on: December 16, 2014, 11:47:04 pm »
Thanks for clarifying. :)

SpeCter

  • Full Member
  • ***
  • Posts: 151
    • View Profile
Re: Sprite DLight - Instant normal maps for 2D graphics
« Reply #28 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:


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.
« Last Edit: December 24, 2014, 01:41:19 pm by SpeCter »