2

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

  1. 我有一张地图,有平坦的地板和墙壁。这里的所有东西都是 2d 的,没有 3d 几何,只有 2d 多边形构成墙壁。

  2. 使用我投射阴影的多边形的顶点来定义可视区域。(紫色线条是我下一步使用的蒙版的一部分)

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

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

我使用以下着色器来实现这一点。但我觉得这有点矫枉过正,而且真的非常低效:

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

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

4

1 回答 1

3

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

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

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

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

这看起来像这样:

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

C是角色的位置;这些点只是规则的,通畅的地板。Xs 是墙壁。来自的线条C代表您需要从中渲染 2D 线条的四个方向。

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

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

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

于 2013-03-27T12:42:34.713 回答