使用OpenGL和GLSL的SSAO算法的奇怪性能行为
我正在研究使用定向半球渲染技术的SSAO(屏幕空间环境光遮挡)算法 I)算法 此算法要求输入:使用OpenGL和GLSL的SSAO算法的奇怪性能行为,opengl,glsl,shader,ssao,Opengl,Glsl,Shader,Ssao,我正在研究使用定向半球渲染技术的SSAO(屏幕空间环境光遮挡)算法 I)算法 此算法要求输入: 1个包含预计算样本的数组(在主循环之前加载->在我的示例中,我使用64个根据z轴定向的样本) 1噪波纹理,包含也根据z轴定向的归一化旋转向量(此纹理生成一次) GBuffer中的2个纹理:“PositionSampler”和“NormalSampler”包含视图空间中的位置和法向量 以下是我使用的片段着色器源代码: #version 400 /* ** Output color value. *
- 1个包含预计算样本的数组(在主循环之前加载->在我的示例中,我使用64个根据z轴定向的样本)
- 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;
}
顺便说一句:
FragColor = vec4(OcclusionFactor);
FragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
性能的缺乏消失了
这意味着如果SSAO代码被正确执行(我试图在执行过程中放置一些断点来检查它),并且我不会在最后使用这个遮挡因子来填充最终的输出颜色,那么性能就不会下降
我认为我们可以得出结论,问题不在于“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
你在这里做的是:
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;
}
在进行此操作时,可以进行的另一个优化是以较小的大小渲染SSAO纹理,最好是主视口大小的一半。如果执行此操作,请确保将深度纹理复制到另一个半尺寸纹理(glBlitFramebuffer)并从中采样位置。我希望这能将性能提高一个数量级,特别是在您给出的最坏情况下。Ok。因此,问题应该来自与缓存相关的纹理采样。实际上,位置采样器是一个32位纹理(GL_RGB32F)。我选择这种格式是因为我需要存储法线不需要的位置(GL_RGB就足够了)。你认为我使用这样的纹理格式对纹理采样和缓存效率更差吗?无论如何,对于我来说,下一步不是将位置存储在RGB32F纹理中,而是将线性深度存储到RGB纹理中,并将位置直接重建到片段着色器中。你怎么看?是的,这个职位应该会有帮助。我在答案中添加了这个。非常感谢您提供完整的答案。再见。通过消除零矩阵元素,可以大大加快视图空间位置重建的速度。“我希望这能将性能提高一个数量级”,更像是降低分辨率。半分辨率=4倍更少像素=4倍更快尽管如此,因为由于dari解释的原因,纹理采样也可能更快。既然你是ALU有限公司的。少4倍像素=少4倍计算。这并不能使它快10倍。我已经实现了MSSAO(它使用了不同分辨率的多层),它正好展示了我刚才描述的行为。当然,我假设您的全分辨率SSAO没有使用非常愚蠢的缓存抖动采样模式。如果真是这样,lowres版本也会受到影响。