如何在GLSL中实现2D光线投射光效果

时间:2016-01-10 16:42:00

标签: opengl graphics 2d glsl raycasting

这最初是由@sydd here提出的。我很好奇它,所以我尝试编码它但它被关闭/删除之后我才回答所以这里是。

问题:如何在 GLSL 中重现/实施this 2D光线投射照明效果?

效果本身会将光线从鼠标位置投射到每个方向,累积背景地图alpha和影响像素强度的颜色。

所以输入应该是:

  • 鼠标位置
  • 背景RGBA地图纹理

1 个答案:

答案 0 :(得分:5)

  1. 背景地图

    好的我创建了一个测试 RGBA 地图作为2个图像,其中一个包含 RGB (在左侧),第二个包含alpha通道(在右侧),因此您可以看到他们俩。粗糙的它们被组合形成单个 RGBA 纹理。

    RGB map alpha map

    我将它们模糊了一点,以便在边缘获得更好的视觉效果。

  2. 光线投射

    因为这应该在 GLSL 中运行,我们需要在某处投射光线。我决定在片段着色器中进行此操作。算法是这样的:

    1. GL 侧面传递着色器所需的制服这里将鼠标位置作为纹理坐标,最大纹理分辨率和光传输强度。
    2. GL 侧绘制四边形覆盖整个屏幕,背景纹理(o混合)
    3. 在“顶点着色器”上,只需传递所需的纹理和片段坐标
    4. 在每个片段的片段着色器上:

      • 将光线从鼠标位置投射到实际片段位置(在纹理坐标中)
      • 在光线旅行期间累积/积分光属性
      • 如果光强度接近零或达到目标碎片位置,则停止。
  3. 顶点着色器

    // 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;                 // texture end point <0,1>
    void main()
        {
        t1=txr;
        gl_Position=vec4(pos,0.0,1.0);
        }
    

    片段着色器

    // Fragment
    #version 420 core
    uniform float transmit=0.99;// light transmition coeficient <0,1>
    uniform int txrsiz=512;     // max texture size [pixels]
    uniform sampler2D txrmap;   // texture unit for light map
    uniform vec2 t0;            // texture start point (mouse position) <0,1>
    in smooth vec2 t1;          // texture end point, direction <0,1>
    out vec4 col;
    void main()
        {
        int i;
        vec2 t,dt;
        vec4 c0,c1;
        dt=normalize(t1-t0)/float(txrsiz);
        c0=vec4(1.0,1.0,1.0,1.0);   // light ray strength
        t=t0;
        if (dot(t1-t,dt)>0.0)
         for (i=0;i<txrsiz;i++)
            {
            c1=texture2D(txrmap,t);
            c0.rgb*=((c1.a)*(c1.rgb))+((1.0f-c1.a)*transmit);
            if (dot(t1-t,dt)<=0.000f) break;
            if (c0.r+c0.g+c0.b<=0.001f) break;
            t+=dt;
            }
        col=0.90*c0+0.10*texture2D(txrmap,t1);  // render with ambient light
    //  col=c0;                                 // render without ambient light
        }
    

    最后结果:

    output

    动画256色GIF:

    output animation

    由于8位截断,GIF中的颜色会略微失真。此外,如果动画停止刷新页面或在decend gfx viewer中打开。

    light inside semitransparent object