Jump to content
  • Advertisement
Sign in to follow this  
Bogo

OpenGL 2D OpenGL lightning using shaders

This topic is 1054 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everybody smile.png

I've been following Ben Arnold's youtube channel tutorials (https://www.youtube.com/user/makinggameswithben) on making a game ( and a game engine ) ... He had a tutorial on making simple 2D lighting effects using shaders.
However, after implementing that, it doesn't really satisfy me :/ , I mean, the light barely looks like it really "lights up" the scene, and, my biggest problem is that i want the scene to be completely black, and the light will shine through and "reveal" the real texture color of the walls and ground and everything. But, when i set the walls color to black, or its alpha value, the light has no affect on it..

Should it be like that ? I've tried so many modifications to my shaders and played with them but could not get what i want..

 

That is what I have at the moment:

10fc5kw.png

 

As you can see, I do have a light that makes the surrounding bricks look brighter, but it doesn't look quite "correct", and also, as i have mentioned, if the entire scene is completely dark, the light wont make the texture light up in the darkness.

 

I want to achieve an effect similar to this: (for example pay attention to second 0:48 and forwards..)

 

Like in this video where if a place is dark, the light hits it and makes it visible in it colors again..

 

I have a separate shader for this light point and for the scene.. I can provide the code samples if needed ...
any help with that would be greatly appreciated, I am thoroughly confused smile.png

 

p.s. I did actually check out the source code from github, of the game in the video, but it is like so much more complicated and different than what i am doing, plus a lot of the code and the comments are in croatian ...

 

Share this post


Link to post
Share on other sites
Advertisement

Should it be like that ? I've tried so many modifications to my shaders and played with them but could not get what i want..

The texture and alpha should be as when the object is fully lit. It is the light that makes a scene bright or dark, not the scenery.

 

Then in the shader compute / sample a light value (some gray, usually, where black means unlit and white means full lit) and multiply (component by component) that light value with the texture color value. Regardless of the texture color value, when multiplied with the extreme 0,0,0,1 (no light) will yield in black, and multiply with extreme 1,1,1,1 (full light) will yield in the texture's color; anything in-between will yield in shades of the texture color.

Edited by haegarr

Share this post


Link to post
Share on other sites

Hello again smile.png

 

 

The texture and alpha should be as when the object is fully lit. It is the light that makes a scene bright or dark, not the scenery.

 

haegarr, thanks for that. I have returned the colors of the scenery to its "initial" color and alpha..

As you had advised, I have changed my shaders so that the "main" shader now has a sampler2D of both the light and of the original texture, however, I when I multiply the light with the initial color ... I get a completely black scene with nothing visible but a single light point that follows my mouse...

 

But, if i don't include the light sampler in the calculations, (thus the final calculation involved the original texture color, ambience, and the color passed from the vertex shader), then then i get the same result as in the screenshot in my previous post... why ?? blink.png

 

anyway, as i said previously, i have a separate shader for this light point, and a separate one for the scene, so, in the scene shader -  I have tried to remove the light sampler, instead do the light point calculations inside the scene sahder, and include it in the calculation with the texture sampler .... again, playing around with it gave me either a completely black screen, a black screen with a single light point, or the original scene with strange artifacts and is was like as if this little light point was sitting inside every brick texture, I don't know I cant even explain tongue.png ...

 

At the moment, that is how my shaders look:

 

scene.fs

#version 130

in vec2 fragmentPosition;
in vec4 fragmentColor;
in vec2 fragmentUV; 

uniform sampler2D texture; // base texture
uniform sampler2D lightMap; 

uniform vec4 ambientColor; // ambiemce

void main() {

    vec3 ambient = ambientColor.rgb * ambientColor.a;
    vec4 temp = texture2D(texture, fragmentUV);
    vec4 textureColor = texture2D(lightMap, fragmentUV);

    gl_FragColor = temp * vec4(ambient, 1) * fragmentColor;

}

pointLight.fs

#version 130

in vec2 fragmentPosition;
in vec4 fragmentColor;
in vec2 fragmentUV;

//uniform vec2 lightLocation;
//uniform sampler2D texture;

void main() {
    float distance = length(fragmentUV);
    vec4 color = vec4(fragmentColor.rgb - distance, fragmentColor.a);

    gl_FragColor = color;// * fragmentColor;
}

with these two i get the same result as in the screenshot from the previous post.. and, If i make the ambient light completely dark, then again, the light has no effect on the scene ...
And just a final question  -  In the video from the previous post, those completely dark areas - why are they dark ? I mean, is the original texture color black, or is it the ambient light that makes it look like that ? why then when light hits it, the original color is revealed, unlike in my case ?

 

I think I now understand less than before ?! wacko.png

Share this post


Link to post
Share on other sites

What you want to get in the end is something like

    screen_color := scene_color * clamped( ambient_light + spot_light )

           = clamped( scene_color * ambient_light + scene_color * spot_light )

for each pixel on the screen, so that when the sum of light is 1 the scene_color (read from texture) is fully visible, and if the sum of light is less then 1 (down to 0) then the screen becomes darker (down to black).

 

You try to do this in 2 passes with the main frame buffer as storage for the intermediate screen color, like so:

    screen_color := scene_color * ambient_light

    screen_color := blend(screen_color, spot_light)

 

I assume this because you do not sample a "screen" texture in the light pass shader. So, how have you configured the blending? It may be configured so that it simply overwrites the result from the first pass. It need to be configured so that the formula from the top of this post is implemented.

 

BTW: How is your fragmentColor computed?

 

However, I suggest you to unify both passes into one. That allows you to do the blending within the shader.

Share this post


Link to post
Share on other sites

hy :)

Thanks haegarr...

For your question -

In the scene vertex Shader I have 

in vec2 vertexColor;
out vec2 fragmentColor;

void main(){
    .... gl_Position stuff

    fragmentColor = vertexColor;
}

I think vertexColor gets to the shader from the vbo (right? I'm not keen enough to be sure)...

 

Now, Ive tried to unify both fragment shaders into one (the light shader and the scene).. doing the light calculations in the scene shader, and I got a really weired result:

I have use small .png picuters of bricks, for walls and floor, and, every brick texture was fully lit (i.e in its original color) at its top tight, and completely dark in bottom left.. and was mixed in between - well i hope you know what i mean ...

 

No matter how I twist it and play with the shaders - I end up with either the original thing, or this, or a single light point on a black screen, or nothing at all.. wacko.png

I'm sure its not as complicated, Its just that something is wrong uh ?

Which got me thinking, maybe its not a problem with the shaders, but with code I use in the game ?

In my draw function I do ClearColor, Clear depth and color bits, get projection matrix from the camera, and then:

shaderProgram.use();

get uniforms
glActiveTexture()
set uniforms

spriteBatch.begin()
draw map and people
spriteBatch.end()
spriteBatch.renderBatch()

shaderProgram.unuse();

I have the same for the light (but now its commented out because I unified both shaders)  only difference is that for the light i use a different instance of shaderProgram, and ActiveTexture() is set to GL_TEXTURE1 ...

 

maybe thats wrong ?? like.. Im not sure what to ask wacko.png

Share this post


Link to post
Share on other sites

hy smile.png

in vec2 vertexColor;
out vec2 fragmentColor;

void main(){
    .... gl_Position stuff

    fragmentColor = vertexColor;
}


Did you copy this directly from your shader or is the use "vec2" a typo?

Share this post


Link to post
Share on other sites

The code snippets you provided so far are not sufficient for an analysis. So I'll describe what to do, now with more details (the following is the most basic way; it can be fleshed out, of course):

 

1. You have a mesh, obviously shaped as a quad. Each vertex has the mandatory position and a texture co-ordinate.

 

2. You have a texture that stores the color as it looks like when being fully lit. This is because you can darken a color easily, but brighten it would introduce inaccuracies and is not possible at all if being black. Set this texture for sampling in the fragment shader.

 

3. You have a scene constant ambient light intensity given as RGB value. Set this value as uniform to the fragment shader.

 

4. You have a spot light with an intensity given as RGB, a position given in screen co-ordinates, and an radial extent given in screen co-ordinates. Set these values as uniforms to the fragment shader.

 

5. In the fragment shader, use the UV co-ordinates to sample the color texture.

 

6. Calculate the distance from the current fragment to the spot light position.

 

7. Attenuate the intensity triple of the spot light accordingly to the distance calculate in 6.

 

8. Add the ambient intensity triple to the result of 7.

 

9. Clamp the result of 8. to (1,1,1).

 

10. Multiply the result of 9. by the sampled texture color.

 

11. Write the result of 10., extended by the homogeneous 1, as fragment color. Do not use the build-in blending engine here.

Edited by haegarr

Share this post


Link to post
Share on other sites

thank you very much  haegarr smile.png

Well, I have revised my shaders and followed your instructions.. and actually, I think I'm now closer to something cool smile.png

 

11ca4g8.png

 

As you can see I have a light point that follows my mouse, and it lights up a circular area, in a color that I pass as a uniform, however, now I've got another problem tongue.png

Obviously, the entire scene is completely dark, and I don't know why... (my ambient color is like a dark blue, and I've checked, it is applied only where there is light from the light point...).. What's wrong ?

 

Here is my fragment shader as of now :

#version 130

in vec2 fragmentPosition;
in vec4 fragmentColor;
in vec2 fragmentUV; 

uniform sampler2D texture; 

uniform vec4 ambientColor;
uniform vec2 lightPos;
uniform vec3 lightIntensity;

void main() {
    vec4 temp = texture2D(texture, fragmentUV);
	
    float distance = length(lightPos - fragmentPosition);
    vec3 lightColor = vec3(lightIntensity.rgb - distance);
    vec3 ambient = ambientColor.rgb * ambientColor.a;

    vec3 final = lightColor * ambient;
    //final = clamp(final, 0, 1);
    
    gl_FragColor = vec4(final * temp.rgb, 1);
}

The clamping is commented out.. however, when I clamp between e.g 0.1 and 1, some light does shine through in the scene and it is not completely dark..

what do you mean by saying I should clamp to 1, 1, 1 ?

 

 

Share this post


Link to post
Share on other sites
What's wrong ?

Ambient light and spot light are to be added instead of multiplied!

 

The clamping is commented out.. however, when I clamp between e.g 0.1 and 1, some light does shine through in the scene and it is not completely dark..
what do you mean by saying I should clamp to 1, 1, 1 ?

Clamp each channel to [0.0, 1.0]. The reason is because the light addition may yield in values above 1. That is a typical problem in LDR lighting.

final = clamp( final, 0.0, 1.0 );

If you clamp to [0.1, 1.0] you'll have a minimum lighting value of 0.1, and hence, of course, the scene can never get totally dark. But it is the role of the ambient light to provide the base brightness of the scene.

Edited by haegarr

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!