使用着色器在2D环境中实现视野

时间:2013-03-27 11:46:46

标签: opengl graphics glsl shader fragment

我正在实施动态视野。我决定使用着色器,以使照明更好看,以及它如何影响墙壁。这是我正在研究的场景: http://i.imgur.com/QxZVyo7.jpg

  1. 我有一张地图,地板和墙壁平整。这里的每件事都是2d,没有三维几何,只有2d多边形组成了墙。

  2. 使用多边形的顶点我投射阴影,以定义可视区域。 (紫色线条是我在下一步中使用的面具的一部分)

  3. 在场景顶部绘制阴影时使用着色器,我可以避免墙壁被遮挡。

  4. 这样,随着视野的变化,阴影会沿着墙壁动态投射

  5. 我使用了以下着色器来实现这一目标。但我觉得这有点矫枉过正,真的很无效:

    uniform sampler2D texture;
    uniform sampler2D filterTexture;
    uniform vec2 textureSize;
    uniform float cellSize;
    uniform sampler2D shadowTexture;
    
    
    
    void main()
    {
        vec2 position;
        vec4 filterPixel;
        vec4 shadowPixel;
        vec4 pixel = texture2D(texture, gl_TexCoord[0].xy );
    
    
        for( float i=0 ; i<=cellSize*2 ; i++)
        {
            position = gl_TexCoord[0].xy;
            position.y = position.y - (i/textureSize.y);
            filterPixel = texture2D( filterTexture, position );
    
            position.y = position.y - (1/textureSize.y);
            shadowPixel = texture2D( texture, position );
    
            if (shadowPixel == 0){
                if( filterPixel.r == 1.0 )
                {
                    if( filterPixel.b == 1.0 ){
                        pixel.a = 0;
                        break;
                    }
                    else if( i<=cellSize )
                    {
                        pixel.a = 0;
                        break;
                    }
                }
            }
        }
    
        gl_FragColor = pixel;
    }
    

    为了查找掩码中的红色像素而迭代每个片段似乎是一个巨大的过载,但我没有看到如何通过使用着色器以任何其他方式完成此任务。

1 个答案:

答案 0 :(得分:3)

这里的解决方案非常简单:使用阴影贴图。

您的情况可能是2D而不是3D,但基本概念是相同的。您希望根据世界某个点与“光源”(在您的情况下是玩家角色)之间是否存在阻碍性表面来“遮蔽”区域。

在3D中,阴影贴图通过从光源的角度渲染世界来工作。这导致2D纹理,其中值表示从光(在特定方向上)到最近的障碍物的深度。渲染场景时,可以通过将场景投影到2D深度纹理(阴影贴图)来检查当前片段的位置。如果为当前片段计算的深度值比阴影贴图中投影位置中的最近障碍物更近,则可以从灯光中看到该片段。如果没有,那就不是。

您的2D版本必须做同样的事情,只需少一个维度。您可以从“光源”的角度渲染2D世界。在这种情况下,您的2D世界实际上只是阻碍四边形(您必须使用线多边形填充来渲染它们)。任何阻碍视线的四边形都应该渲染到阴影贴图中。纹理访问是完全没必要的;您需要的唯一信息是深度。您的着色器甚至不必写入颜色。您可以通过将2D空间投影到一维纹理来渲染这些对象。

这看起来像这样:

       X..X
XXXXXXXX..XXXXXXXXXXXXXXXXXXXX
X.............\.../..........X
X..............\./...........X
X...............C............X
X............../.\...........X
X............./...\..........X
X............/.....\.........X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

C是角色的位置;圆点只是规则的,无阻碍的地板。 X是墙。来自C的线代表了渲染2D线所需的四个方向。

在3D中,要为点光源进行阴影贴图,您必须在6个不同的方向上将场景渲染6次,进入立方体阴影贴图的面。在2D中,您必须在4个不同方向上将场景渲染4次,分为4个不同的1D阴影贴图。你可以使用一维数组纹理。

获得阴影贴图后,只需在着色器中使用它们即可检测片段何时可​​见。要做到这一点,您需要一组从窗口空间到4个不同投影的变换,这些投影代表您渲染的4个视图方向。根据片段相对于目标的位置,其中只有一个将用于任何特定片段。

为了实现这一点,我首先得到一个简单的定向“阴影”案例。也就是说,不要使用职位;只是一个“光”的方向。这将测试您开发2D到1D投影矩阵的能力,以及适当的相机空间矩阵,将您的世界空间四边形转换为相机空间。一旦掌握了这一点,那么你就可以用不同的投影去做4次。