使用OpenGL和GLSL的SSAO算法的奇怪性能行为

用户名

我正在研究使用定向半球渲染技术的SSAO(屏幕空间环境光遮挡)算法

一)算法

该算法需要作为输入:

  • 1个包含预先计算的样本的数组(在主循环之前加载->在我的示例中,我使用了根据z轴定向的64个样本)。
  • 1个噪声纹理,其中包含也根据z轴定向的归一化旋转矢量(此纹理生成一次)。
  • GBuffer的2个纹理:“ PositionSampler”和“ NormalSampler”,包含视图空间中的位置和法向矢量。

这是我使用的片段着色器源代码:

#version 400

/*
** Output color value.
*/
layout (location = 0) out vec4 FragColor;

/*
** Vertex inputs.
*/
in VertexData_VS
{
    vec2 TexCoords;

} VertexData_IN;

/*
** Inverse Projection Matrix.
*/
uniform mat4 ProjMatrix;

/*
** GBuffer samplers.
*/
uniform sampler2D PositionSampler;
uniform sampler2D NormalSampler;

/*
** Noise sampler.
*/
uniform sampler2D NoiseSampler;

/*
** Noise texture viewport.
*/
uniform vec2 NoiseTexOffset;

/*
** Ambient light intensity.
*/
uniform vec4 AmbientIntensity;

/*
** SSAO kernel + size.
*/
uniform vec3 SSAOKernel[64];
uniform uint SSAOKernelSize;
uniform float SSAORadius;

/*
** Computes Orientation matrix.
*/
mat3 GetOrientationMatrix(vec3 normal, vec3 rotation)
{
    vec3 tangent = normalize(rotation - normal * dot(rotation, normal)); //Graham Schmidt process 
    vec3 bitangent = cross(normal, tangent);

    return (mat3(tangent, bitangent, normal)); //Orientation according to the normal
}

/*
** Fragment shader entry point.
*/
void main(void)
{
    float OcclusionFactor = 0.0f;

    vec3 gNormal_CS = normalize(texture(
        NormalSampler, VertexData_IN.TexCoords).xyz * 2.0f - 1.0f); //Normal vector in view space from GBuffer
    vec3 rotationVec = normalize(texture(NoiseSampler,
        VertexData_IN.TexCoords * NoiseTexOffset).xyz * 2.0f - 1.0f); //Rotation vector required for Graham Schmidt process

    vec3 Origin_VS = texture(PositionSampler, VertexData_IN.TexCoords).xyz; //Origin vertex in view space from GBuffer
    mat3 OrientMatrix = GetOrientationMatrix(gNormal_CS, rotationVec);

    for (int idx = 0; idx < SSAOKernelSize; idx++) //For each sample (64 iterations)
    {
        vec4 Sample_VS = vec4(Origin_VS + OrientMatrix * SSAOKernel[idx], 1.0f); //Sample translated in view space

        vec4 Sample_HS = ProjMatrix * Sample_VS; //Sample in homogeneus space
        vec3 Sample_CS = Sample_HS.xyz /= Sample_HS.w; //Perspective dividing (clip space)
        vec2 texOffset = Sample_CS.xy * 0.5f + 0.5f; //Recover sample texture coordinates

        vec3 SampleDepth_VS = texture(PositionSampler, texOffset).xyz; //Sample depth in view space

        if (Sample_VS.z < SampleDepth_VS.z)
            if (length(Sample_VS.xyz - SampleDepth_VS) <= SSAORadius)
                OcclusionFactor += 1.0f; //Occlusion accumulation
    }
    OcclusionFactor = 1.0f - (OcclusionFactor / float(SSAOKernelSize));

    FragColor = vec4(OcclusionFactor);
    FragColor *= AmbientIntensity;
}

这是结果(没有模糊渲染过程):

在此处输入图片说明

到这里为止,一切似乎都是正确的。

二)表现

我注意到NSight Debugger在性能方面非常奇怪:

如果我将相机越来越靠近龙,那么表演将会受到极大的影响。

但是,在我看来,情况并非如此,因为SSAO算法适用于屏幕空间,例如,它不依赖于龙的图元数量。

这是具有3个不同相机位置的3张屏幕截图(在这3种情况下,所有1024 * 768像素着色器均使用相同的算法执行):

a)GPU闲置:40%(影响像素:100%)

在此处输入图片说明

b)GPU闲置:25%(影响像素:100%)

在此处输入图片说明

c)GPU空闲:2%!(受影响的像素:100%)

在此处输入图片说明

我的渲染引擎在示例中使用了2个渲染过程:

  • 材料通(填充位置正常采样器)
  • 环境通(填充SSAO纹理)

我以为问题出在这两个过程的执行上,但事实并非如此,因为我在客户端代码中添加了一个条件,即如果相机静止不动,则不计算任何物质过程。因此,当我在上面拍摄这三张照片时,只是执行了环境通行证。因此这种性能的缺乏与材料的通过无关。我可以给您的另一个论点是,如果我删除了龙网(仅带有平面的场景),结果是一样的:我的相机越靠近平面,越缺乏表现力!

对我来说,这种行为是不合逻辑的!就像我上面说的那样,在这3种情况下,所有像素着色器都是使用完全相同的像素着色器代码执行的!

现在,如果我直接在片段着色器中更改一小段代码,我会注意到另一个奇怪的行为:

如果我替换该行:

FragColor = vec4(OcclusionFactor);

按行:

FragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);

缺乏表现就消失了!

这意味着,如果正确执行了SSAO代码(我尝试在执行过程中放置​​一些断点以进行检查),并且我不会在最后使用此OcclusionFactor来填充最终的输出颜色,因此就不会缺乏性能!

我认为我们可以得出结论,问题并非出自“ FragColor = vec4(OcclusionFactor);”行之前的着色器代码... 我认为。

您如何解释这种行为?

我在客户端代码和片段着色器代码中都尝试了很多代码组合,但找不到该问题的解决方案!我真的迷路了。

预先非常感谢您的帮助!

简短的答案是缓存效率

为了理解这一点,让我们从内循环看以下几行:

    vec4 Sample_VS = vec4(Origin_VS + OrientMatrix * SSAOKernel[idx], 1.0f); //Sample translated in view space

    vec4 Sample_HS = ProjMatrix * Sample_VS; //Sample in homogeneus space
    vec3 Sample_CS = Sample_HS.xyz /= Sample_HS.w; //Perspective dividing (clip space)
    vec2 texOffset = Sample_CS.xy * 0.5f + 0.5f; //Recover sample texture coordinates

    vec3 SampleDepth_VS = texture(PositionSampler, texOffset).xyz; //Sample depth in view space

您在这里所做的是:

  1. 在视域中平移原始点
  2. 将其转换为剪辑空间
  3. 采样纹理

那么,这与缓存效率如何对应?

访问相邻像素时,缓存可以很好地工作。例如,如果您使用的是高斯模糊,则仅访问邻居,这些邻居很有可能已被加载到缓存中。

假设您的物体现在很远。然后在剪辑空间中采样的像素也非常接近原始点->高局部性->良好的缓存性能。

如果相机非常靠近您的对象,则生成的采样点会更远(在剪辑空间中),并且您将获得随机的内存访问模式。尽管您实际上并未执行更多操作,但这将大大降低性能。

编辑:

为了提高性能,您可以从上一遍的深度缓冲区重构视图空间位置。

如果您使用的是32位深度的缓冲区,它将一个样本所需的数据量从12字节减少到4字节。

位置重构如下所示:

vec4 reconstruct_vs_pos(vec2 tc){
  float depth = texture(depthTexture,tc).x;
  vec4 p = vec4(tc.x,tc.y,depth,1) * 2.0f + 1.0f; //tranformed to unit cube [-1,1]^3
  vec4 p_cs = invProj * p; //invProj: inverse projection matrix (pass this by uniform)
  return p_cs / p_cs.w;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

SQL:奇怪的查询性能行为

来自分类Dev

Java BigDecimal奇怪的性能行为

来自分类Dev

SQL:奇怪的查询性能行为

来自分类Dev

对使用OpenGL和GLSL的性能的简单好奇

来自分类Dev

奇怪的窗口功能行为

来自分类Dev

Java Applet在最新JRE(7.55+)上的奇怪性能行为

来自分类Dev

贪婪算法的奇怪行为

来自分类Dev

更新到Swift 3后奇怪的转义功能行为

来自分类Dev

CPU缓存的这种性能行为的说明

来自分类Dev

.NET字典插入的怪异性能行为

来自分类Dev

Javascript画布使用算法绘制线条奇怪的行为

来自分类Dev

递归算法中的奇怪行为,

来自分类Dev

C ++缓存性能奇怪的行为

来自分类Dev

使用getline和awk的奇怪行为

来自分类Dev

Opengl GLM lookAt奇怪的行为

来自分类Dev

OpenGL:VBO删除的奇怪行为?

来自分类Dev

使用OpenSceneGraph进行SSAO,优化和管道

来自分类Dev

||奇怪的Ruby行为 和 &&

来自分类Dev

加入和的奇怪行为

来自分类Dev

OpenXml 和奇怪的行为

来自分类Dev

谁能解释这种意外的V8 JavaScript性能行为?

来自分类Dev

使用NSTimer和动画的UIImageView和UILabel的奇怪行为

来自分类Dev

使用OpenGL和GLSL,Parralax映射无法正常工作

来自分类Dev

使用OpenGL和GLSL的模板缓冲和延迟渲染

来自分类Dev

使用glTexBuffer和texelFetch的OpenGL(带有GLSL)

来自分类Dev

使用OpenGL和GLSL的基本阴影映射工件

来自分类Dev

WebGL和OpenGL的性能

来自分类Dev

Python泛洪算法的奇怪行为

来自分类Dev

Dijkstra的算法在python中的奇怪行为