In my current project I would like to hide everything except in a certain radius around the player. Essentially I want an unseen light source around the player that fades to almost complete darkness around the player. I donât even know where to start searching, researching, or coding, so any code samples, links, or keywords to google would help
Pass the playerâs position to your fragment shaders as a uniform and calculate the distance from the playerâs position to the fragmentâs position.
Divide the received value by your max view distance thus normalizing the value between 0 and 1.
Now flip the value by subtracting it from one. (<- This is needed so that further objects are being darker and not lighter)
The received value will be your color intensity factor which you can use to multiply your output color channels with.
This should be extremely efficient and pretty easy to implement.
If you need further help or a GLSL example code just tell me.
Edit: I forgot to mention that although you didnât talk about it Iâm expecting you to be doing this in 2D. What I wrote is a 2D approach to your problem.
Also forgot to mention that you should clamp the value to 1 after you divide it by your max view distance so further away fragments will return 1 as well and not 1+ values.
From what I can see PandaMoniumHUN, your idea would work well for me, however, I will need some examples as I am a complete newbie with GLSL. Thanks
Edit: I was looking around for any GLSL tutorials or explanations I could find, and I was giving GLSL a feeble (at best) attempt. Here is what I have so far (note: I may be completely wrong, so please point out any problems with what I have so far):
#version 110
uniform vec2 player;
in vec4 gl_FragCoord;
out vec4 outputF;
void main(){
// calculate the distance
double distance = sqrt(((gl_FragCoord.x - player.x) * (gl_FragCoord.x - player.x)) + ((gl_FragCoord.y - player.y) * (gl_FragCoord.y - player.y)));
// divide by the max view distance
double received = distance / 1000;
if(received > 1.0){
received = 1.0;
}
double inverted = 1.0 - received;
outputF = vec4(0.0, 0.0, 0.0, inverted);
}
Okay, so I was writing some more experimental stuff in GLSL, and now I have a shader that compiles (I think), but when I use it it makes the whole screen black.
Just some thoughts:
-Player position can be a uniform, since itâs not changing from fragment to fragment
-distance / 1000.0
-[icode]inverted = 1.0 - clamp(distance / 1000.0, 0.0, 1.0);[/icode]
Not a bad start but sadly I forgot to mention in my previous post that this could be best implemented as a post-processing effect.
That means you have to do the following:
Create an FBO with itâs own texture
Render everything to your FBO using your regular shaders
Render out your FBO to the screen using your lighting shader
You got me inspired with this and I was wondering if I could make it work, hereâs the result Iâve got:
Also hereâs a gorgeous (well, not so much, thanks to the recording program) GIF of the effect in action: [Link]
The GIF turned out to be huge (7+MB) so if itâs lagging for you give your browser time to load it properly. Also it is NOT as ugly as in the GIF, it looks like exactly on the picture above.
This is all calculated in the fragment shader, no premade mask has been used.
Another approach to this kind of lighting would be to use a circle texture from GIMP or Photoshop as an alpha mask but that could end up looking worse than this (although that is probably more efficient).
And to post some actual code too:
Vertex Shader:
#version 330 core
uniform mat4 projectionMatrix;
layout(location=0) in vec2 in_Position;
layout(location=1) in vec2 in_TexCoord;
out vec2 pass_TexCoord;
void main(){
pass_TexCoord = vec2(in_TexCoord.x, 1.0-in_TexCoord.y);
gl_Position = projectionMatrix*vec4(in_Position, 0.0, 1.0);
}
The thing is I canât teach you all of GLSL, you should learn that yourself. It could probably take up like 1 or 2 hours to get the grasp of it.
The shader that I wrote is for modern OpenGL, that means there are no built-in matrices (thatâs why you have to send the projection matrix to the shader as a uniform) - note: I donât need to multiply with a modelView matrix here since I always want my FBO texture to be rendered at (0; 0) - , no gl_FragColor (instead we have to send out a vec4 thatâll be our color, thatâs out_Color). PlayerPos and ViewDistance should be obvious. A nice side note here is that if youâre using orthographic projection you can specify the viewDistance in pixels (in my program I set it to 300 = The view distance is 300 pixels from the center of our player).
In the vertex shader my two inputs (in_Position and in_TexCoord) are per-vertex attributes that are being filled up from data from my buffers using vertex attribute pointers. But because I need the texture coordinate in the fragment shader instead of my vertex shader I have to pass it to the fragment shader. Thatâs what pass_TexCoord is for. An output that the fragment shader receives as an input. You might be wondering why I do this:
[icode]pass_TexCoord = vec2(in_TexCoord.x, 1.0-in_TexCoord.y);[/icode]
Instead of this:
[icode]pass_TexCoord = in_TexCoord;[/icode]
Thatâs because my FBO texture is upside down for some reason (probably because Iâm fighting the convention and my orthographic projection is âupside downâ to make (0; 0) my bottom-left coordinate) so I have to flip it on the Y axis. Donât care about it too much, if itâs upside down for you too thatâs how you flip it back.
Okay so about the calculations:
I calculate the current fragmentâs position by ceiling the gl_FragCoordâs x and y values. You have to ceil them because they contain the âmiddle position of a pixelâ. So for the bottom left pixel itâs going to be [icode](0.5; 0.5)[/icode] instead of [icode](0; 0)[/icode] or [icode](1; 1)[/icode]. With ceil I turn [icode](0.5; 0.5)[/icode] to [icode](1; 1)[/icode].
Iâve already explained how to calculate the lightFactor in my previous posts but hereâs it again:
You have to calculate the distance between the playerâs position and the fragmentâs position and divide the received value with your viewDistance. After that you should clamp the value to min. 0 and max. 1 and finally subtract the value from 1. As for the why check out my post above.
Finally I set the output color to be a mix of 3 things:
My FBO texture: [icode]texture(texUnit, pass_TexCoord)[/icode] (<- Thatâs where we use the passed texture coordinate in our fragment shader)
A passed uniform color that you can use to manipulate the outputâs color: [icode]color[/icode]
The lightFactor: [icode]vec4(vec3(lightFactor), 1.0);[/icode] Note that [icode]vec4(vec3(lightFactor), 1.0)[/icode] is just a shortcut to [icode]vec4(lightFactor, lightFactor, lightFactor, 1.0)[/icode].
Now that Iâve explained everything you should be able to port this to OpenGL 2.0 or to whatever version youâre using.