1
\$\begingroup\$

So I have a scene, completely based on 2D sprites. I want to render "light sources" into a seperate frame buffer (so mostly dots around, for example, the centre of a flame) and then render that frame buffer with my "lighting" shader above my whole scene, causing the light sources to "tint" the surrounding pixels, mostly by blending a pixel with the light source's color dependant on it's distance to the nearest light source.

The question: What concepts should I apply here to get the results I want? What am I doing wrong right now?

I have here a few concept drawings:

The scene without lighting:

The scene without lighting

The framebuffer of the scene containing the light source (the top yellow pixel of the flame):

mention the small red dot

The result of rendering the framebuffer as a texture with the glow shader. I also "simulated" a 2nd buffer with a smaller radius and a yellow light at the same position.

the result

Alternatively, and closer to my first approach to the idea, imagine the whole framebuffer of the 2nd pixel transparent but the dot at the center.

also mind that this is a mockup and I want a gradient at the edge

What I wasn't able to mock up quickly was a gradient of the lighting, dimming it at the edges and having it brighter at the center.

The current idea needs to conform this fragment shader's layout:

#version 400 uniform sampler2D color_map; layout(std140) uniform Sprite { vec2 position; vec2 size; vec2 position_in_texture; vec2 size_in_texture; float rotation; }; in vec2 texture_coordinate; layout(std140) uniform Color { vec4 color; }; layout(location = 0) out vec4 out_color; void main(){ vec4 tex_color = texture2D(color_map, texture_coordinate); vec2 diff; vec2 norm; vec2 sample_coordinate; out_color = tex_color; int radius = 4; int count = 1; norm = vec2(radius/size.x, radius/size.y); for(int i=-radius; i < radius; i++){ //Sample each pixel around the one rendered right now and add it's color to the current one with a certain gradient factor for(int j=-radius; j < radius; j++){ diff = vec2(i/size.x, j/size.y); sample_coordinate = texture_coordinate + diff; if(0.0 <= sample_coordinate.x && sample_coordinate.x <= 1.0 && 0.0 <= sample_coordinate.y && sample_coordinate.y <= 1.0){ tex_color = texture2D(color_map, sample_coordinate); if(tex_color != vec4(0.0,0.0,0.0,0.0) && sample_coordinate != texture_coordinate && length(diff) <= length(norm)){ out_color = (out_color * count + tex_color * (1.0 - (length(diff) / length(norm)))) / (count+1); count++; } } } } }

I am planning on making the radius variable by passing it as another uniform element. With what I am doing there, I don't get the results I am looking for.

Though through experimenting I got this glow-shader, which I like, but the edges of the logo are still a bit too dark though (left the passed frame above the original, that is right):

a glow shader using a similar approach to the above

\$\endgroup\$
4
\$\begingroup\$

You're doing it wrong - very inefficiently. Instead of rendering lightsources to your "lighting framebuffer", render the lighting contribution. That would be a soft disk centered at your light source instead of a single pixel. Example disk:

enter image description here

... and you can render that as a sprite! (Additive blending, clamp to 1 for best results).

You can now bind that lighting framebuffer and just sample the texel location that you're interested in and you get the lighting contribution directly.

If you want to create the texture yourself, it's as easy as writing a shader like this: (run via shadertoy)

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;
    float d = length(uv - 0.5); // distance to center
    float c = 1.0-smoothstep(0.3,0.5,d); // apply smoothing curve
    fragColor = vec4(c,c,c,1.0);
}
\$\endgroup\$
  • \$\begingroup\$ The problem with that is that this image can not be scaled to a random radius with the same resolution of it's gradient. \$\endgroup\$ – salbeira Mar 2 '15 at 17:13
  • \$\begingroup\$ Basically, what I want my shader to do is creating exactly this image of yours. Just with the power of insane multiprocessing! \$\endgroup\$ – salbeira Mar 2 '15 at 17:25
  • \$\begingroup\$ I want to be able to use (amongst others) exactly the uniform buffers you see there. As such I find it difficult to create such an image. What would the code look like to create it in general, maybe I can apply it to my environment I want to work with. \$\endgroup\$ – salbeira Mar 2 '15 at 17:59
  • \$\begingroup\$ I think @Babis's approach could work well; you could have textured squares (triangle pairs) and scale them as geometry. Either by recomputing the vertexes (there aren't many, so should be cheap-ish) or with transforms. Should scale fine. \$\endgroup\$ – david van brink Mar 2 '15 at 18:01
  • 1
    \$\begingroup\$ Generating the image yourself is super-easy, I updated my answer. But really, you want a fixed image and scale that as david says. No reason to be generating textures all the time. You can use the power of insane multiprocessing to do other cooler stuff that need to be calculated on the fly :) \$\endgroup\$ – Babis Mar 2 '15 at 18:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.