Opengl 使用着色器在二维环境中实现视野

Opengl 使用着色器在二维环境中实现视野,opengl,glsl,shader,Opengl,Glsl,Shader,我正在实现动态视野。我决定使用明暗器,以使照明更好看,以及它如何影响墙壁。以下是我正在研究的场景: 我有一张地图,有平坦的地板和墙壁。这里的一切都是二维的,没有三维几何体,只有构成墙的二维多边形 使用多边形的顶点投射阴影,以定义可视区域。(紫色线条是我在下一步中使用的遮罩的一部分) 在场景顶部绘制阴影时使用着色器,可以避免墙也被遮挡 这样,随着视野的变化,阴影将沿墙动态投射 我使用了以下着色器来实现这一点。但我觉得这有点过分,而且真的没有效率: uniform sampler2D textur

我正在实现动态视野。我决定使用明暗器,以使照明更好看,以及它如何影响墙壁。以下是我正在研究的场景:

  • 我有一张地图,有平坦的地板和墙壁。这里的一切都是二维的,没有三维几何体,只有构成墙的二维多边形

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

  • 在场景顶部绘制阴影时使用着色器,可以避免墙也被遮挡

  • 这样,随着视野的变化,阴影将沿墙动态投射

  • 我使用了以下着色器来实现这一点。但我觉得这有点过分,而且真的没有效率:

    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;
    }
    
    均匀二维纹理;
    均匀采样2D滤波器结构;
    均匀vec2织构化;
    均匀的浮点数;
    纹理均匀;
    void main()
    {
    vec2位置;
    vec4过滤器像素;
    vec4阴影像素;
    vec4像素=纹理2d(纹理,gl_TexCoord[0].xy);
    
    对于(float i=0;i来说,这里的解决方案非常简单:使用阴影贴图

    你的情况可能是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
    是角色的位置;
    X
    s是墙。
    C
    中的线条表示渲染2D线条所需的四个方向

    在3D中,要对点光源进行阴影贴图,必须在立方体阴影贴图的面上以6个不同方向渲染场景6次。在2D中,必须在4个不同方向将场景渲染4次,以4个不同的1D阴影贴图。可以使用1D阵列纹理进行渲染

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


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

    为什么要使用着色器?我使用的库是SFML。I tried用于了解如何读取图像上的像素信息(以便将发光像素上方的墙设置为可见)但是操作非常慢,而且这个过程应该每个循环都进行,所以它不是真正可行的。我遇到了着色器,并决定尝试一下。我喜欢结果,但我担心性能一点也不好,但我对着色器是完全陌生的,所以我想听听其他人对这方面的意见。我明白了这个想法,但看不出怎么做在确定应显示墙的哪些部分时,1D投影非常有用。我是否应该在每个方向上对每面墙进行投影以使其正确?例如:红色矩形中的线是灯光/阴影的1D投影。但该投影不适用于块1和块2,因为块2 I完全可见块1大部分是可见的,但在投影中,这些区域被标记为模糊的……也许我的想法错了?@user2215331:这不是一个二进制值;它是一个深度。你可以得到最近的遮挡表面的距离。块1的贡献将被忽略,因此块1和目标之间的任何碎片都将被视为可见ble.我现在明白了!我只有一个问题。正如我所说,我对着色器不熟悉,并且几乎充分利用了GPU。我的问题是关于工作负载分布:这些任务中哪些是GPU完成的,哪些是CPU正常处理的?对于GPU完成的任务,什么时候应该使用着色器?@user2215331:都完成了“通过GPU”。您需要渲染“阴影”“场景4次,有4个单独的变换。你必须渲染主场景一次,使用适当的阴影贴图。除了发出渲染命令、更改FBO和着色器等,这里没有任何CPU工作。我想知道…即使我成功地获得了4个投影