【问题标题】:How to implement 2D raycasting light effect in GLSL如何在 GLSL 中实现 2D 光线投射光效
【发布时间】:2016-01-10 16:41:59
【问题描述】:

这最初是由@sydd here 提出的。我对此很好奇,所以我尝试对其进行编码,但在我回答之前它已被关闭/删除,所以就在这里。

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

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

所以输入应该是:

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

【问题讨论】:

    标签: opengl graphics 2d glsl raycasting


    【解决方案1】:
    1. 背景图

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

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

    2. 光线投射

      因为这应该在 GLSL 中运行,我们需要将光线投射到某个地方。我决定在片段着色器中进行。所以算法是这样的:

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

        • 将光线从鼠标位置投射到实际片段位置(在纹理坐标中)
        • 在光线传播期间累积/整合光线属性
        • 如果光强度接近零或达到目标片段位置,则停止。

    顶点着色器

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

    最后是结果:

    256 色动画 GIF:

    GIF 中的颜色由于 8 位截断而略有失真。此外,如果动画停止刷新页面或改为在 decend gfx 查看器中打开。

    【讨论】:

    • @sydd 看看这个。 (已重新提出您的问题以使其可以回答)。如果你愿意,你仍然需要添加闪烁的噪声纹理......
    • @NicolBolas 很高兴知道......我只是对他的一个问题添加了评论以确保。阴影贴图可以用于基本照明,但我现在无法想象如何使用这种方法添加背景的透明度和颜色(次表面光)(光会根据它通过的材料改变颜色和强度)。跨度>
    • @sydd 是的,与 CPU 方法相比,由于 GLSL 架构的限制,存在大量的计算冗余。但是我认为它仍然足够快,但是我没有对其进行基准测试。有时间我会试试的。不管怎样,它只是一个 QUAD,没有任何复杂的计算。最慢的是纹理获取。您可以通过混合或添加更多循环(每个灯光一个)将结果加在一起来添加更多灯光。您可以通过扩大dt 步骤或使用小分辨率贴图纹理来加速该过程。我不会在手机上编码,所以很难说你需要尝试一下......
    • @sydd ok on 512x512 window with 256x256 map, 0.97 透射率 我在 GeForce GT440 上的渲染时间最差,约为 6.5 毫秒。在移动设备上,分辨率会比我认为的要低......
    • @sydd 不,这对于当前的硬件来说是不可能的,如果有时间,您可以根据需要读取尽可能多的纹素,但每个片段着色器调用只能输出单个像素。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多