SSAO 阴影随着相机移动奇怪(计算 gbuffer 错误)
Posted
技术标签:
【中文标题】SSAO 阴影随着相机移动奇怪(计算 gbuffer 错误)【英文标题】:SSAO shading moves weird with camera (calculating gbuffer wrong) 【发布时间】:2016-10-11 03:59:41 【问题描述】:我正在尝试通过本教程实现这个版本的 ssao:
http://www.learnopengl.com/#!Advanced-Lighting/SSAO
这是我最终的渲染纹理。
当我移动相机时,阴影似乎会跟随
好像我错过了某种与相机的矩阵乘法。
代码
gBuffer 顶点
#version 330 core
layout (location = 0) in vec3 vertexPosition;
layout (location = 1) in vec3 vertexNormal;
out vec3 position;
out vec3 normal;
uniform mat4 m;
uniform mat4 v;
uniform mat4 p;
uniform mat4 n;
void main()
vec4 viewPos = v * m * vec4(vertexPosition, 1.0f);
position = viewPos.xyz;
gl_Position = p * viewPos;
normal = vec3(n * vec4(vertexNormal, 0.0f));
gBuffer 片段
#version 330 core
layout (location = 0) out vec4 gPosition;
layout (location = 1) out vec3 gNormal;
layout (location = 2) out vec4 gColor;
in vec3 position;
in vec3 normal;
const float NEAR = 0.1f;
const float FAR = 50.0f;
float LinearizeDepth(float depth)
float z = depth * 2.0f - 1.0f;
return (2.0 * NEAR * FAR) / (FAR + NEAR - z * (FAR - NEAR));
void main()
gPosition.xyz = position;
gPosition.a = LinearizeDepth(gl_FragCoord.z);
gNormal = normalize(normal);
gColor.rgb = vec3(1.0f);
SSAO 顶点
#version 330 core
layout (location = 0) in vec3 vertexPosition;
layout (location = 1) in vec2 texCoords;
out vec2 UV;
void main()
gl_Position = vec4(vertexPosition, 1.0f);
UV = texCoords;
SSAO 片段
#version 330 core
out float FragColor;
in vec2 UV;
uniform sampler2D gPositionDepth;
uniform sampler2D gNormal;
uniform sampler2D texNoise;
uniform vec3 samples[32];
uniform mat4 projection;
// parameters (you'd probably want to use them as uniforms to more easily tweak the effect)
int kernelSize = 32;
float radius = 1.0;
// tile noise texture over screen based on screen dimensions divided by noise size
const vec2 noiseScale = vec2(1024.0f/4.0f, 1024.0f/4.0f);
void main()
// Get input for SSAO algorithm
vec3 fragPos = texture(gPositionDepth, UV).xyz;
vec3 normal = texture(gNormal, UV).rgb;
vec3 randomVec = texture(texNoise, UV * noiseScale).xyz;
// Create TBN change-of-basis matrix: from tangent-space to view-space
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
// Iterate over the sample kernel and calculate occlusion factor
float occlusion = 0.0;
for(int i = 0; i < kernelSize; ++i)
// get sample position
vec3 sample = TBN * samples[i]; // From tangent to view-space
sample = fragPos + sample * radius;
// project sample position (to sample texture) (to get position on screen/texture)
vec4 offset = vec4(sample, 1.0);
offset = projection * offset; // from view to clip-space
offset.xyz /= offset.w; // perspective divide
offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0
// get sample depth
float sampleDepth = -texture(gPositionDepth, offset.xy).w; // Get depth value of kernel sample
// range check & accumulate
float rangeCheck = smoothstep(0.0, 1.0, radius / abs(fragPos.z - sampleDepth ));
occlusion += (sampleDepth >= sample.z ? 1.0 : 0.0) * rangeCheck;
occlusion = 1.0 - (occlusion / kernelSize);
FragColor = occlusion;
我已经阅读并看到有人有类似的问题,并将视图矩阵传递到 ssao 着色器并乘以 sampleDepth:
float sampleDepth = (viewMatrix * -texture(gPositionDepth, offset.xy)).w;
但这似乎只会让事情变得更糟。
这是另一个俯视图,您可以看到阴影随着相机移动
如果我以某种方式定位我的相机,事情就会对齐
【问题讨论】:
【参考方案1】:虽然我只能在 gBuffer 顶点着色器中假设您的法线矩阵 n
的值,但您似乎没有将法线存储在视图空间中,而是存储在世界空间中。由于 SSAO 计算是在屏幕空间中完成的,这可以(至少部分)解释意外行为。在这种情况下,您需要将视图矩阵 v
与法线相乘,然后再将它们存储到 gBuffer(可能更有效,但可能会干扰您的其他着色计算)或在检索它们之后。
【讨论】:
我的正常矩阵是 glm::mat4 n = glm::transpose(glm::inverse(view * model));所以我会在顶点着色器中相乘 normal = vec3(v * n * vec4(vertexNormal, 0.0f)); ?如何将其反转为照明? 另外,你有我的正常缓冲区应该是什么样子的例子吗?当我在网上搜索gbuffer延迟渲染和ssao时,有时正常的buffer有不同的颜色 我没有例子,但你的正常矩阵应该是glm::mat4 n = view * glm::transpose(glm::inverse(model))
。您不应该转置和反转视图矩阵。以上是关于SSAO 阴影随着相机移动奇怪(计算 gbuffer 错误)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C++ 中使用 sdl、opengl 移动相机时修复奇怪的相机旋转
使相机随着位置的变化而移动(Google Maps Api)