如何在GLSL中实现2D光线投射光效果 [英] How to implement 2D raycasting light effect in GLSL

查看:213
本文介绍了如何在GLSL中实现2D光线投射光效果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这最初是由@sydd

动画256色GIF:





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


This was originally asked by @sydd here. I was curious about it so I try to code it but It was closed/deleted before I could answer so here it is.

Question: How to reproduce/implement this 2D ray casting lighting effect in GLSL?

The effect itself cast rays from mouse position to every direction, accumulating background map alpha and colors affecting the pixels strength.

So the input should be:

  • mouse position
  • background RGBA map texture

解决方案

  1. Background map

    Ok I created a test RGBA map as 2 images one containing RGB (on the left) and second with the alpha channel (on the right) so you can see them both. Of coarse they are combined to form single RGBA texture.

    I blurred them both a bit to obtain better visual effects on the edges.

  2. Ray casting

    As this should run in GLSL we need to cast the rays somewhere. I decided to do it in fragment shader. So the algo is like this:

    1. On GL side pass uniforms needed for shaders Here goes mouse position as texture coordinate, max resolution of texture and light transmition strength.
    2. On GL side draw quad covering whole screen with texture of background (o blending)
    3. On Vertex shader just pass the texture and fragment coordinates needed
    4. On Fragment shader per each fragment:

      • cast ray from mouse position to actual fragment position (in texture coordinates)
      • cumulate/integrate the light properties during the ray travel
      • stop if light strength near zero or target fragment position reached.

Vertex shader

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

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

And Finally the result:

Animated 256 colors GIF:

The colors in GIF are slightly distorted due to 8 bit truncation. Also if the animation stops refresh page or open in decend gfx viewer instead.

这篇关于如何在GLSL中实现2D光线投射光效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆