【问题标题】:OpenGL - Geometry shader shadow mapping pass performing terriblyOpenGL - 几何着色器阴影映射通道表现非常糟糕
【发布时间】:2017-06-27 18:06:42
【问题描述】:

我正在使用 Variance Shadow Mapping 计算多个点光源的阴影。立方体贴图的所有 6 个面都使用几何着色器在一个通道中渲染,每个光源都重复此操作,并且全部存储在立方体贴图数组中。这一切都运行良好,60fps 的 16 盏灯没问题。

为了进一步优化,我尝试将整个过程移至单个几何着色器通道,结果却达到了我的硬件唯一的 113 个顶点输出限制。出于好奇,我决定只渲染 4 个灯光(72 个发射顶点),令我惊讶的是它降至 24fps。

那么,为什么 16 个灯光和 16 个渲染通道的性能明显优于单通道中的 4 个灯光呢?

代码基本相同。

#version 400 core

layout(triangles) in;
layout (triangle_strip, max_vertices=18) out;

uniform int lightID;
out vec4 frag_position;

uniform mat4 projectionMatrix;
uniform mat4 shadowTransforms[6];

void main()
{   
    for(int face = 0; face < 6; face++)
    {
        gl_Layer = face + (lightID * 6);

        for(int i=0; i<3; i++)
        {
            frag_position = shadowTransforms[face] * gl_in[i].gl_Position;
            gl_Position = projectionMatrix * shadowTransforms[face] * gl_in[i].gl_Position;

            EmitVertex();
        }
        EndPrimitive();
    }
}

#version 400 core

layout(triangles) in;
layout (triangle_strip, max_vertices=72) out;

out vec4 frag_position;

uniform mat4 projectionMatrix;
uniform mat4 shadowTransforms[24];

void main()
{   
    for (int lightSource = 0; lightSource < 4; lightSource++)
    {
        for(int face = 0; face < 6; face++)
        {
            gl_Layer = face + (lightSource * 6);

            for(int i=0; i<3; i++)
            {
                frag_position = shadowTransforms[gl_Layer] * gl_in[i].gl_Position;
                gl_Position = projectionMatrix * shadowTransforms[gl_Layer] * gl_in[i].gl_Position;
                EmitVertex();
            }
            EndPrimitive();
        }
    }
}

public void ShadowMapsPass(Shader shader)
{
    // Setup
    GL.UseProgram(shader.ID);
    GL.Viewport(0, 0, CubeMapArray.size, CubeMapArray.size);

    // Clear the cubemarray array data from the previous frame
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, shadowMapArray.FBO_handle);
    GL.ClearColor(Color.White);
    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

    for (int j = 0; j < lights.Count; j++)
    {
        // Create the light's view matrices
        List<Matrix4> shadowTransforms = new List<Matrix4>();
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(1, 0, 0), new Vector3(0, -1, 0)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(-1, 0, 0), new Vector3(0, -1, 0)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 1, 0), new Vector3(0, 0, 1)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, -1, 0), new Vector3(0, 0, -1)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, 1), new Vector3(0, -1, 0)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, -1), new Vector3(0, -1, 0)));

        // Send uniforms to the shader
        for (int i = 0; i < 6; i++)
        {
            Matrix4 shadowTransform = shadowTransforms[i];
            GL.UniformMatrix4(shader.getUniformID("shadowTransforms[" + i + "]"), false, ref shadowTransform);
        }
        GL.Uniform1(shader.getUniformID("lightID"), j);
        DrawScene(shader, false);
    }
}

public void ShadowMapsPass(Shader shader)
{
    // Setup
    GL.UseProgram(shader.ID);
    GL.Viewport(0, 0, CubeMapArray.size, CubeMapArray.size);

    // Clear the cubemarray array data from the previous frame
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, shadowMapArray.FBO_handle);
    GL.ClearColor(Color.White);
    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

    // Create the light's view matrices
    List<Matrix4> shadowTransforms = new List<Matrix4>();
    for (int j = 0; j < lights.Count; j++)
    {
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(1, 0, 0), new Vector3(0, -1, 0)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(-1, 0, 0), new Vector3(0, -1, 0)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 1, 0), new Vector3(0, 0, 1)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, -1, 0), new Vector3(0, 0, -1)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, 1), new Vector3(0, -1, 0)));
        shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, -1), new Vector3(0, -1, 0)));
    }

    // Send uniforms to the shader
    for (int i = 0; i < shadowTransforms.Count; i++)
    {
        Matrix4 shadowTransform = shadowTransforms[i];
        GL.UniformMatrix4(shader.getUniformID("shadowTransforms[" + i + "]"), false, ref shadowTransform);
    }      
    DrawScene(shader, false);
}

【问题讨论】:

    标签: c# opengl glsl opentk geometry-shader


    【解决方案1】:

    我猜第二种形式的并行代码执行机会更少。几何着色器的第一个版本生成 18 个顶点并且必须执行 4 次,但是这 4 次执行可以并行运行。第二个版本一个接一个地生成 72 个顶点。

    【讨论】:

    • 啊,我明白了,这在总毫秒数内超过了绘制调用。
    猜你喜欢
    • 2013-08-23
    • 1970-01-01
    • 2023-04-06
    • 2014-05-09
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 2021-03-11
    • 2021-09-07
    相关资源
    最近更新 更多