1

I read a 2d light shader in shader toy which can be used to create 2d (point) light. https://www.shadertoy.com/view/4dfXDn

vec4 drawLight(vec2 p, vec2 pos, vec4 color, float range)
    {
        float ld = length(p - pos);  
        if (ld > range) return vec4(0.0);
        float fall = (range - ld)/range;
        fall *= fall;
        return (fall) * color;
    }

void main() {
    vec2 p = gl_FragCoord.xy;
    vec2 c = u_resolution.xy / 2.0;

    vec4 col = vec4(0.0);

    vec2 lightPos = vec2(c);
    vec4 lightCol = vec4(1.000,0.25,0.000,1.000);

    col += drawLight(p, lightPos, lightCol, 400.0);

    gl_FragColor = col;
}

However, I can't figure out how to make another "shape" of light using this? How can I modify the drawLight function to have another parameter, which modifies the original light, like 1.0 is a full circle light, and 0.25 is a quad-light?

genpfault
  • 51,148
  • 11
  • 85
  • 139
  • @Spektre i actually achive that, but just dont know clearly how to change the light shape when using this method? – Trần Thành Đạt May 02 '20 at 12:12
  • @Spektre Thanks for answering me :D. However is there any way that don't casting every direction, but only to a shape, not polygon, but eclipse shape? Something like a 2D flash light collusion. I have tried if (ld > p.x) return 0.0 and the image it showed when the pos near to 0.0 – Trần Thành Đạt May 02 '20 at 17:44
  • I making some process: using a dir param, now i can make the result : `float dir = 12.0 float S_ld = length(p - dir); if (S_ld > p.x) return vec4(0.0);` However, this code seem to be rely on the x fragcoord of the shader (0 is left and 1 is right, so i dont figure out how to make "left direction" :( (and "down direction" too) – Trần Thành Đạt May 02 '20 at 18:12
  • I added image with description what is what ... – Spektre May 03 '20 at 07:33
  • btw you can not substract position and direction (that has no meaning in math/geometry its like mixing apples and oranges or what the English expression is for this) ... Instead you can use `dot` between 2 directions as a measure of angle between fragment and light ... `dot ( lightdir, fragpos-lightpos )` positive/negative means forw/back and magnitude is distance. If you want also left and right then just rotate the light dir by 90deg (so swap x,y and negate one of them) and do the same `dot` ... positive negative means left/right and magnitude how far ... – Spektre May 03 '20 at 07:38

1 Answers1

1

in your code the

float ld = length(p - pos);

Is computing your distance from light uniformly in all directions (euclidean distance). If you want different shading change the equation...

For example you can compute minimal perpendicular distance to a polygon shaped light like this:

Vertex:

// Vertex
#version 420 core
layout(location=0) in vec2 pos;     // glVertex2f <-1,+1>
layout(location=8) in vec2 txr;     // glTexCoord2f  Unit0 <0,1>
out smooth vec2 t1;                 // fragment position <0,1>
void main()
    {
    t1=txr;
    gl_Position=vec4(pos,0.0,1.0);
    }

Fragment:

// Fragment
#version 420 core
uniform sampler2D txrmap;   // texture unit
uniform vec2 t0;            // mouse position <0,1>
in smooth vec2 t1;          // fragment position <0,1>
out vec4 col;

// light shape
const int n=3;
const float ldepth=0.25;    // distance to full disipation of light
const vec2 lpolygon[n]=     // vertexes CCW
    {
    vec2(-0.05,-0.05),
    vec2(+0.05,-0.05),
    vec2( 0.00,+0.05),
    };
void main()
    {
    int i;
    float l;
    vec2 p0,p1,p,n01;
    // compute perpendicular distance to edges of polygon
    for (p1=vec2(lpolygon[n-1]),l=0.0,i=0;i<n;i++)
        {
        p0=p1; p1=lpolygon[i];          // p0,p1 = edge of polygon
        p=p1-p0;                        // edge direction
        n01=normalize(vec2(+p.y,-p.x)); // edge normal CCW
//      n01=normalize(vec2(-p.y,+p.x)); // edge normal CW
        l=max(dot(n01,t1-t0-p0),l);
        }
    // convert to light strength
    l = max(ldepth-l,0.0)/ldepth;
    l=l*l*l;
    // render
//  col=l*texture2D(txrmap,t1);
    col = l*vec4(1.0,1.0,1.0,0.0);
    }

I used similar code How to implement 2D raycasting light effect in GLSL as a start point hence the slightly different names of variables.

The idea is to compute perpendicular distance of fragment to all the edges of your light shape and pick the biggest one as the others are facing wrong side.

The lpolygon[n] is the shape of light relative to light position t0 and the t1 is fragment position. It must be in CCW winding otherwise you would need to negate the normal computation (mine view is flipped so it might look its CW but its not). I used range <0,1> as you can use that as texture coordinate directly...

Here screenshot:

preview

Here some explanations:

explanations

For analytical shape you need to use analytical distance computation ...

Spektre
  • 49,595
  • 11
  • 110
  • 380