Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (109)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Theory of 2d per pixel lighting.  (Read 1994 times)
0 Members and 1 Guest are viewing this topic.
Offline trollwarrior1
« Posted 2013-11-29 11:54:20 »

So uhm.. I kinda "finished" my game Zombie Massacre and had nothing else to do, so I decided to add lights to it.

I have done that with shaders, and it seems to work pretty nicely. But the problem is that I'm calculating lights for vertices, not for pixels. If I make light really dim, there is no problem, because differences between vertices are pretty small, you can't even see it. But when the light is really strong and shiny, you can see that the light is calculated between vertices, and the lighting is really squary.

So what is the "way" to do it per pixel? Calculate lighting in fragment shader?
The way I have done the lighting is just take the distance from vertex to light and convert it to some kind of color value. Is there some kind of GLSL function in fragment shader for getting the fragments position?

I tried looking in the web for per pixel lighting, but they all seem to be 3d tutorials..

Would be awesome if anyone could shine some light upon this topic Cheesy
Offline opiop65

JGO Kernel


Medals: 153
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #1 - Posted 2013-11-29 12:05:01 »

Honestly, the only way I would know how to do 2D lighting like that is by making an overlay that has a specified alpha, drawing it over everything, and then just changing the rgb values to make it darker and brighter in game. IVs never actually done 2D shader lighting! Maybe ra4king can help you, I'm assuming you followed his tutorial for the lighting?

Offline trollwarrior1
« Reply #2 - Posted 2013-11-29 12:11:52 »

Honestly, the only way I would know how to do 2D lighting like that is by making an overlay that has a specified alpha, drawing it over everything, and then just changing the rgb values to make it darker and brighter in game. IVs never actually done 2D shader lighting! Maybe ra4king can help you, I'm assuming you followed his tutorial for the lighting?

I have no idea what is IVs and who is ra4king. Overlaying stuff on top of everything isn't really my style Cheesy I will just have to optimize stuff.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline trollwarrior1
« Reply #3 - Posted 2013-11-29 12:40:49 »

Hmmmm I found this function in GLSL
gl_FragCoord
With it I can make per pixel lighting, but the scale seems f**ked up. Maybe I should include vertex or something.
Offline Phased
« Reply #4 - Posted 2013-11-29 14:22:57 »

put your lighting calculation in the fragment shader.

The fragment shader will do per pixel while the other is per vertices
Offline trollwarrior1
« Reply #5 - Posted 2013-11-29 14:35:58 »

put your lighting calculation in the fragment shader.

The fragment shader will do per pixel while the other is per vertices

How should I get the pixel coordinates?
Offline Phased
« Reply #6 - Posted 2013-11-29 15:03:45 »

For a game I made for a assignment (in my projects, a horde style game, i am pretty sure i have day/night cycle turned on), I didn't spend much time and just stayed with immediate mode because the school computers suck, some of them didn't even support OpenGL.

vec4 old is a rgba value for the pixel, gl_TexCoord[0].st is a vector 2 of the texture coordinate (if you use the GL11.glTexCoord2f() method to set your texture coordinates you can use the gl_TexCoord[0], if not use the vec2 of your texture coordinates you passed in). the value of texture is the texture ID you set up when you bound it.

each update I change the value of timer, according to how dark it should get, the timer way is probably not the best, but it did good for my first time using shaders and rushing it.


fragment shader
1  
2  
3  
4  
5  
6  
7  
8  
9  
uniform sampler2D texture;
uniform float timer;
uniform float alpha;
float timeEffect;
void main() {
   vec4 old = texture2D(texture, gl_TexCoord[0].st);
   timeEffect = 1.0 / timer;
   gl_FragColor = vec4(old.s * timer, old.t * timer, old.p * timer, old.q * alpha);
}
Offline trollwarrior1
« Reply #7 - Posted 2013-11-29 16:36:15 »

I think you misunderstood me.. I'm not looking for the day/night "screen dim". I want the lights! Cheesy

Here are my current shaders. Seem to work pretty sweet Tongue Need to do something about the extra bright light though.


VERTEX SHADER
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
varying vec4 vertColor;
varying vec3 light1, light2;
varying vec2 lvloffset;

uniform vec2 offset;
uniform float rotation, shadeColor;
uniform vec2 pivot;
uniform vec2 leveloffset;

uniform vec3 l1, l2;

vec3 translateLight(vec3 light) {
   light.x -= leveloffset.x;
   light.y -= leveloffset.y;
   return light;
}

void main() {
   
   lvloffset = leveloffset;
   
   light1 = translateLight(l1);
   light2 = translateLight(l2);

   vec4 vertex = gl_Vertex;
   
   float rot = rotation;
   
   float x = vertex.x - pivot.x;
   float y = vertex.y - pivot.y;
   
   
   vertex.x = x * cos(rot) - y * sin(rot);
   vertex.y = x * sin(rot) + y * cos(rot);
   
   x = vertex.x;
   y = vertex.y;
   
   vertex.x = x + offset.x + pivot.x;
   vertex.y = y + offset.y + pivot.y;
   
   gl_TexCoord[0] = gl_MultiTexCoord0;
   vec4 vert = gl_ProjectionMatrix * gl_ModelViewMatrix * vertex;
   gl_Position = vert;
   
   vec4 sc = vec4(shadeColor, shadeColor, shadeColor, 1);
   vertColor = gl_Color * sc;
   
}


FRAGMENT SHADER
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
uniform sampler2D tex;
varying vec4 vertColor;
varying vec3 light1, light2;
varying vec2 lvloffset;

float getDist(vec4 vertex, vec3 light) {
   float xd = light.x - vertex.x;
   float yd = light.y - vertex.y;
   if(xd < 0) xd = -xd;
   if(yd < 0) yd = -yd;
   float dist = sqrt(xd * xd + yd * yd);
   
   return dist;
}

float getShade(float dist, float intensity) {
   float min = 64;
   if(dist < min) dist = min;
   
   float shade = 0;
   shade = intensity / (dist);
   return shade;
}

float getFullShade(vec4 vertex, vec3 light) {
   float dist = getDist(vertex, light);
   float shade = getShade(dist, light.z);
   return shade;
}

void main()
{
    vec4 color = texture2D(tex, gl_TexCoord[0].st);
   
    //this is not vertex.. I just called it like this.
   vec4 vertex = gl_FragCoord;
   
    //my axis start at top-left corner. Need to flip y axis.
   vertex.y = 600 - vertex.y;
   
    //scale the "viewport"
   // my display is 800, 600 and I did glOrtho(480, 360);
   vertex.x /= 1.666666f;
    vertex.y /= 1.666666f;
   
    float lightcolor = getFullShade(vertex, light1);
    lightcolor += getFullShade(vertex, light2);
   
    vec4 light = vec4(lightcolor, lightcolor, lightcolor, 1);
   
    gl_FragColor =  vertColor * color * light;
       
}


Offline theagentd
« Reply #8 - Posted 2013-11-29 18:38:23 »

There is no need to use shaders here. I've implemented basic 2D lighting, with shadows, without any shaders. The only thing you need is a framebuffer object, a texture to render your lighting to and proper blend modes. There are lots of tutorials available on framebuffer objects so I won't tell you how those work. What you do is draw your lights using additive blending (glBlendMode(GL_ONE, GL_ONE)) to a texture, basically making your lights add up. The red, green and blue channels of your light texture will be the light intensity of each color at each pixel. When you've added all your lights to the light map, you simply render a fullscreen quad over your unlit world with a blending mode that multiplies the light texture's color with the current color on the screen: glBlendMode(GL_ZERO, GL_SRC_COLOR).

Myomyomyo.
Offline trollwarrior1
« Reply #9 - Posted 2013-11-29 18:55:55 »

There is no need to use shaders here. I've implemented basic 2D lighting, with shadows, without any shaders. The only thing you need is a framebuffer object, a texture to render your lighting to and proper blend modes. There are lots of tutorials available on framebuffer objects so I won't tell you how those work. What you do is draw your lights using additive blending (glBlendMode(GL_ONE, GL_ONE)) to a texture, basically making your lights add up. The red, green and blue channels of your light texture will be the light intensity of each color at each pixel. When you've added all your lights to the light map, you simply render a fullscreen quad over your unlit world with a blending mode that multiplies the light texture's color with the current color on the screen: glBlendMode(GL_ZERO, GL_SRC_COLOR).

What are the pros, cons of using framebuffer for lighting? Does the performance take any hit?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline HeroesGraveDev

JGO Kernel


Medals: 239
Projects: 11
Exp: 2 years


┬─┬ノ(ಠ_ಠノ)(╯°□°)╯︵ ┻━┻


« Reply #10 - Posted 2013-11-29 19:08:46 »

Lights generally have subtractive blending.

A red light for example has no blue or green wavelengths, so blue or green would appear black (unless there was a hint of red)

Offline theagentd
« Reply #11 - Posted 2013-11-29 21:37:37 »

Lights generally have subtractive blending.

A red light for example has no blue or green wavelengths, so blue or green would appear black (unless there was a hint of red)
So if you mix a red light and green light, you get black?

There is no need to use shaders here. I've implemented basic 2D lighting, with shadows, without any shaders. The only thing you need is a framebuffer object, a texture to render your lighting to and proper blend modes. There are lots of tutorials available on framebuffer objects so I won't tell you how those work. What you do is draw your lights using additive blending (glBlendMode(GL_ONE, GL_ONE)) to a texture, basically making your lights add up. The red, green and blue channels of your light texture will be the light intensity of each color at each pixel. When you've added all your lights to the light map, you simply render a fullscreen quad over your unlit world with a blending mode that multiplies the light texture's color with the current color on the screen: glBlendMode(GL_ZERO, GL_SRC_COLOR).

What are the pros, cons of using framebuffer for lighting? Does the performance take any hit?
Rendering to a texture is no different hardware-wise than rendering to a the screen directly as long as you render to a standard GL_RGBA8 texture. Performance is not a concern; even my now long dead GTX 7900 could handle a few hundred lights at least, easily thousands if they don't cover a very big part of the screen. I don't think there is a more efficient way of doing this.

Myomyomyo.
Offline trollwarrior1
« Reply #12 - Posted 2013-11-30 12:45:39 »

So um how do I render to a texture? Does that have do something with frame buffer?
Offline Danny02
« Reply #13 - Posted 2013-11-30 14:06:14 »

btw, using a framebuffer for lighting is probably better, because you can add more easily new light types(spot-lights, area lights) and scales way better with higher number of lights.

Why do they scale better you ask?
As your code shows, you would have to add more shader attributes/uniforms all the time if you want to support more lights. This would end in things like in the past where one would either have to restrict the number of lights per object or have to render the whole scene multiple times. This method describte by theAgent is a 2D version of deferred rendering and has the same benefits.

But..
coming back to your shader, just calculate the distance of the light per vertex and use the interpolated result in the fragment shader.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
//vertex

in vec2 position;
uniform vec2 light_pos;

out float dist_to_light;

void main()
{
   dist_to_light = length(position- light_pos);//no need for your own computation, if you have a vec4 and vec3(why???) just do length(pos.xy - light.xy)
  ...
}


//fragment

in float dist_to_light;
uniform float max_light_dist

void main()
{
  float intensity = max(0, 1 - dist_to_light / max_light_dist);
  float quad_intensity = intensity * intensity;//light has a quadratic falloff
 ...
}


also don't use cos/sin in your shader rotate with a uniform 2x2 matrix
Offline trollwarrior1
« Reply #14 - Posted 2013-11-30 14:32:00 »

vec3 light is for this shit -
x: position of light on X axis
y: position of light on Y axis
z: light's intensity or something.
Offline theagentd
« Reply #15 - Posted 2013-11-30 18:02:18 »

So um how do I render to a texture? Does that have do something with frame buffer?
Creation: Create texture, create framebuffer object, attach texture to framebuffer.
Rendering: Bind framebuffer, render stuff which ends up on the texture, unbind framebuffer, use texture.

For a more technical answer, just Google.

Why do they scale better you ask?
As your code shows, you would have to add more shader attributes/uniforms all the time if you want to support more lights. This would end in things like in the past where one would either have to restrict the number of lights per object or have to render the whole scene multiple times. This method describte by theAgent is a 2D version of deferred rendering and has the same benefits.
QFT. Spot on.

Myomyomyo.
Offline pitbuller
« Reply #16 - Posted 2013-11-30 20:54:57 »

That shader code is horrible over complex. Also use vector math instead of scalar math for readability reasons. Also use built in functions.

1  
2  
3  
4  
5  
6  
7  
8  
9  
float getDist(vec4 vertex, vec3 light) {
   float xd = light.x - vertex.x;
   float yd = light.y - vertex.y;
   if(xd < 0) xd = -xd;
   if(yd < 0) yd = -yd;
   float dist = sqrt(xd * xd + yd * yd);
   
   return dist;
}


Those branches are totally waste of cycles.(a * a >= 0 always with real numbers)  To calculate distance you can just use build in function.
1  
float dist = distance(light.xy, vertex.xy);
Offline trollwarrior1
« Reply #17 - Posted 2013-11-30 21:14:42 »

@pitbuller
I don't know about you, but I'm not trying to make a perfect game here. I didn't even know such a function as distance(vec2, vec2) existed. Thanks for that. I mean I didn't really go over this stuff to make it best for performance reasons.. I just made it.

@theagentd
Thanks for explaining that. I can try doing it now. But how do I render the light itself to a texture? Sorry, but I'm kinda new to this stuff Cheesy
Offline Danny02
« Reply #18 - Posted 2013-12-01 12:21:40 »

You have to create a fbo first, there shouldbe many examples how to do this. Then bind a texture to it, which has the size of the screen or only half of it if you want to optimize. After thatbind the fbo as the render target.
Collect all lights and either render them throughh a shader or as texturs (shape of the light cone as a grayscala image) to the fbo. So in the end this texture only holds the color of every light in it.
As a last step just blend this texture over your normally rendered scene.
Offline trollwarrior1
« Reply #19 - Posted 2014-02-01 12:43:11 »

There is no need to use shaders here. I've implemented basic 2D lighting, with shadows, without any shaders. The only thing you need is a framebuffer object, a texture to render your lighting to and proper blend modes. There are lots of tutorials available on framebuffer objects so I won't tell you how those work. What you do is draw your lights using additive blending (glBlendMode(GL_ONE, GL_ONE)) to a texture, basically making your lights add up. The red, green and blue channels of your light texture will be the light intensity of each color at each pixel. When you've added all your lights to the light map, you simply render a fullscreen quad over your unlit world with a blending mode that multiplies the light texture's color with the current color on the screen: glBlendMode(GL_ZERO, GL_SRC_COLOR).

I was really stupid back when I was making that lighting. Its like my first time using blend modes other than alpha blending.. Thanks for this Smiley
Offline Oskuro

JGO Knight


Medals: 39
Exp: 6 years


Coding in Style


« Reply #20 - Posted 2014-02-03 13:41:50 »

I first coded a pure java2d implementation based off of these: mattdesl-lwjgl-basics: Shader Lesson 6  and Java4k implementation

I'm tinkering with shaders on lwjgl (as per the first link) now (huge performance boost).

Didn't know there was an alternative to fragment shaders, though, I'll look into it.

Offline Roquen
« Reply #21 - Posted 2014-02-03 14:11:11 »

Lights generally have subtractive blending.

A red light for example has no blue or green wavelengths, so blue or green would appear black (unless there was a hint of red)
Subtractive is when you're blend something that absorbs light (like paints).  Light reflecting off of things is (generally) additive and material dependent.
Offline StumpyStrust
« Reply #22 - Posted 2014-02-03 18:06:10 »

I have done 2d lights without a fbo  Cool

I think the hardest part with 2d lighting is not the blending or setting up an fbo but actually calculation the shadows given a set of polygons.

Offline trollwarrior1
« Reply #23 - Posted 2014-02-03 19:19:22 »

Ummmm is there a way to "multiply" 2 texture by blending? When I do GL_ONE and GL_SRC_COLOR the effect is like dim and really looks crappy.
Offline trollwarrior1
« Reply #24 - Posted 2014-02-03 20:01:09 »

Ehhhhhhhhhhhhh yay!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! I feel like I won a lottery and my life is complete!!!! At last I found a bug that caused my FBO lighting to look crap!

Thanks again theagent you made this possible.

I don't really get it. There are all these "beginner" tutorials for opengl and such which don't really teach anything.. And there is literally no source code(I didn't find any..) for stuff like this simple 2d lighting.. Fek.


Ow.. Just noticed.. It doesn't look as perfect as I would like. Is there a blending mode that isn't additive (r + r) but rather if(new.r > curr.r) curr.r = new.r
Is there a way to implement something like dis?
Offline theagentd
« Reply #25 - Posted 2014-02-04 01:33:39 »

You could use glBlendEquation() to change the operation from add to max().

Myomyomyo.
Offline trollwarrior1
« Reply #26 - Posted 2014-02-04 09:08:10 »

You could use glBlendEquation() to change the operation from add to max().

Hmm seems to be what I'm looking for. But where do I find those modes? I can't find them in either glcommon, gl11 or gl20.
Offline Roquen
« Reply #27 - Posted 2014-02-04 09:19:36 »

My 2-cents is I'd suggest building up the lightmap in a shader rather than using old-school techniques.  There's no margin in them, they're less flexible and less mileage as far as learning  (time spent vs. benefit).  Additionally I think the process has more fun-factor.
Offline theagentd
« Reply #28 - Posted 2014-02-04 13:41:38 »

Hmm seems to be what I'm looking for. But where do I find those modes? I can't find them in either glcommon, gl11 or gl20.
https://www.google.se/search?q=GL_MAX+lwjgl
https://www.google.se/search?q=glBlendEquation+lwjgl
Assuming LWJGL, of course.

Myomyomyo.
Pages: [1]
  ignore  |  Print  
 
 

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (18 views)
2014-07-30 21:08:39

Riven (23 views)
2014-07-29 18:09:19

Riven (15 views)
2014-07-29 18:08:52

Dwinin (12 views)
2014-07-29 10:59:34

E.R. Fleming (33 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (43 views)
2014-07-24 01:59:36

Riven (43 views)
2014-07-23 21:16:32

Riven (30 views)
2014-07-23 21:07:15

Riven (31 views)
2014-07-23 20:56:16
List of Learning Resources
by SilverTiger
2014-07-31 18:29:50

List of Learning Resources
by SilverTiger
2014-07-31 18:26:06

List of Learning Resources
by SilverTiger
2014-07-31 13:54:12

HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!