如何在GLSL中使用从fragcoord到灯光位置的距离来制作自定义的灯光形状。

问题描述 投票:0回答:1

我在shader toy里读到一个二维灯光着色器,可以用来创建二维(点)灯光。https:/www.shadertoy.comview4dfXDn

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;
}

但是,我想不通如何用这个来制作另一种 "形状 "的光?如何修改 drawLight 函数有另一个参数,修改原来的光,比如1.0是全圆光,0.25是四角光?

opengl glsl
1个回答
1
投票

在你的代码中

float ld = length(p - pos);

是计算你与光在所有方向上均匀的距离(欧氏距离)。如果你想要不同的阴影,就改变公式......

例如你可以这样计算一个多边形形状的光的最小垂直距离。

顶点:

// 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);
    }

我使用了类似的代码 如何在GLSL中实现2D光线投射光效 作为起点,因此变量的名称略有不同。

这个想法是计算碎片到你的光形的所有边缘的垂直距离,并选择最大的一个,因为其他的都是朝向错误的一面。

这个 lpolygon[n] 是指光相对于光的位置的形状 t0t1 是碎片位置。它必须是在CCW绕组,否则你将需要否定正常的计算(我的视图是翻转的,所以它可能看起来它的CW,但它不是)。我用的是范围 <0,1> 因为你可以直接用它作为纹理坐标......。

这里是截图。

preview

这里有一些解释

explanations

对于分析形状,你需要使用分析距离计算... ...

© www.soinside.com 2019 - 2024. All rights reserved.