SSAO 在 z = 0 和距离处不正确
SSAO incorrect at z = 0 and at distance
所以我尝试实施 SSAO,但它没有按预期工作。
它似乎在Position z=0 (worldspace)处分裂,在position z=0处有一条白线。还有遮挡看起来不对。
再加上距离更远,所以当移动相机时,遮挡变得更奇怪
我的着色器渲染几何体(实例化):
顶点:
#version 330 core
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexUV;
layout(location = 2) in vec3 vertexColor;
layout(location = 3) in vec3 vertexNormal;
layout(location = 4) in mat4 offset;
layout(location = 8) in vec4 instanceColor;
uniform mat4 Projection;
uniform mat4 View;
out vec2 UV;
out vec4 Color;
out vec3 Normal;
void main()
{
mat4 Model = offset;
mat4 MVP = Projection * View * Model;
vec4 Pos = MVP * vec4(endpos,1);
gl_Position = Pos;
UV = vertexUV;
Color = instanceColor;
Normal = normalize((Model * vec4(vertexNormal,0)).xyz);
}
片段:
#version 330 core
in vec2 UV;
in vec4 Color;
in vec3 Normal;
uniform sampler2D Diffuse;
void main()
{
gl_FragData[0] = vec4(Color);
gl_FragData[1] = (vec4(Normal,1)+1)/2;
}
在几何通道之后,我应用带有法线和深度信息的 SSAO 通道。
这是我的 NoiseTexture:
我使用硬件深度缓冲。
我计算世界上的一切space.
这是片段着色器:
#version 330 core
#define KERNEL_SIZE 16
uniform sampler2D NormalMap;
uniform sampler2D DepthMap;
uniform sampler2D NoiseTexture;
uniform vec2 NoiseScale;
uniform vec2 Resolution;
uniform mat4 InvertViewProjection;
uniform float g_sample_rad = 0.1;
uniform float g_intensity = 2.0;
uniform float g_scale = 0.1;
uniform float g_bias = 0.0;
vec2 CalcTexCoord()
{
return gl_FragCoord.xy / Resolution;
}
vec3 getPosition(vec2 uv)
{
vec4 worldpos;
float depth = texture2D(DepthMap, uv).r;
worldpos.x = uv.x * 2.0f - 1.0f;
worldpos.y = uv.y * 2.0f - 1.0f;
worldpos.z = depth * 2.0f - 1.0f;
worldpos.w = 1.0;
worldpos = InvertViewProjection * worldpos;
worldpos /= worldpos.w;
return worldpos.rgb;
}
vec3 getNormal(vec2 uv)
{
return normalize(texture2D(NormalMap, uv).xyz * 2.0f - 1.0f);
}
vec2 getRandom(vec2 uv)
{
return normalize(texture2D(NoiseTexture, Resolution*uv / NoiseScale).xy * 2.0f - 1.0f);
}
float doAmbientOcclusion(in vec2 tcoord, in vec2 uv, in vec3 p, in vec3 cnorm)
{
vec3 diff = getPosition(tcoord + uv) - p;
vec3 v = normalize(diff);
float d = length(diff)*g_scale;
return max(0.0, dot(cnorm, v) - g_bias)*(1.0 / (1.0 + d))*g_intensity;
}
void main()
{
vec4 Kernels[KERNEL_SIZE] =
vec4[](
vec4(0.355512, -0.709318, -0.102371, 0.0 ),
vec4(0.534186, 0.71511, -0.115167, 0.0 ),
vec4(-0.87866, 0.157139, -0.115167, 0.0 ),
vec4(0.140679, -0.475516, -0.0639818, 0.0 ),
vec4(-0.0796121, 0.158842, -0.677075, 0.0 ),
vec4(-0.0759516, -0.101676, -0.483625, 0.0 ),
vec4(0.12493, -0.0223423, -0.483625, 0.0 ),
vec4(-0.0720074, 0.243395, -0.967251, 0.0 ),
vec4(-0.207641, 0.414286, 0.187755, 0.0 ),
vec4(-0.277332, -0.371262, 0.187755, 0.0 ),
vec4(0.63864, -0.114214, 0.262857, 0.0 ),
vec4(-0.184051, 0.622119, 0.262857, 0.0 ),
vec4(0.110007, -0.219486, 0.435574, 0.0 ),
vec4(0.235085, 0.314707, 0.696918, 0.0 ),
vec4(-0.290012, 0.0518654, 0.522688, 0.0 ),
vec4(0.0975089, -0.329594, 0.609803, 0.0 )
);
vec2 uv = CalcTexCoord(); //same as UV Coordinate from Vertex
vec3 p = getPosition(uv);
vec3 n = getNormal(uv);
vec2 rand = getRandom(uv);
float ao = 0.0f;
float rad = g_sample_rad / p.z;
for (int j = 0; j < KERNEL_SIZE; ++j)
{
vec2 coord = reflect(Kernels[j].xy, rand)*rad;
ao += doAmbientOcclusion(uv, coord, p, n);
}
ao /= KERNEL_SIZE;
ao = 1 - (ao);
gl_FragColor = vec4(ao,ao,ao, 1);
}
一步步调试代码搞定了
我计算世界上的一切space。那里的一切都更容易处理。
我查看了一个使用视图 space 的教程,并将我需要的所有内容更改为 world space.
错误在这里:
float rad = g_sample_rad / p.z;
这是根据距离计算采样半径。在视图 space 中,这会计算与相机距离的采样半径。
但在世界 space 中,这会计算与世界坐标的距离,这导致它在 z=0 处看起来很奇怪,在更远的地方甚至更奇怪。
所以我所做的修复很简单:
vec4 viewpos = CamView * vec4(p,1);
float ao = 0.0f;
float rad = g_sample_rad/viewpos.z;
我改变了视角 space 并计算了视角中的采样半径 space,因此考虑了与相机的距离。
这修复了它。
我对 g_values 进行了一些调整以适应我的需要。看看它看起来到处都一样。这就是它应该的样子。
所以我尝试实施 SSAO,但它没有按预期工作。 它似乎在Position z=0 (worldspace)处分裂,在position z=0处有一条白线。还有遮挡看起来不对。
再加上距离更远,所以当移动相机时,遮挡变得更奇怪
我的着色器渲染几何体(实例化):
顶点:
#version 330 core
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexUV;
layout(location = 2) in vec3 vertexColor;
layout(location = 3) in vec3 vertexNormal;
layout(location = 4) in mat4 offset;
layout(location = 8) in vec4 instanceColor;
uniform mat4 Projection;
uniform mat4 View;
out vec2 UV;
out vec4 Color;
out vec3 Normal;
void main()
{
mat4 Model = offset;
mat4 MVP = Projection * View * Model;
vec4 Pos = MVP * vec4(endpos,1);
gl_Position = Pos;
UV = vertexUV;
Color = instanceColor;
Normal = normalize((Model * vec4(vertexNormal,0)).xyz);
}
片段:
#version 330 core
in vec2 UV;
in vec4 Color;
in vec3 Normal;
uniform sampler2D Diffuse;
void main()
{
gl_FragData[0] = vec4(Color);
gl_FragData[1] = (vec4(Normal,1)+1)/2;
}
在几何通道之后,我应用带有法线和深度信息的 SSAO 通道。
这是我的 NoiseTexture:
我使用硬件深度缓冲。 我计算世界上的一切space.
这是片段着色器:
#version 330 core
#define KERNEL_SIZE 16
uniform sampler2D NormalMap;
uniform sampler2D DepthMap;
uniform sampler2D NoiseTexture;
uniform vec2 NoiseScale;
uniform vec2 Resolution;
uniform mat4 InvertViewProjection;
uniform float g_sample_rad = 0.1;
uniform float g_intensity = 2.0;
uniform float g_scale = 0.1;
uniform float g_bias = 0.0;
vec2 CalcTexCoord()
{
return gl_FragCoord.xy / Resolution;
}
vec3 getPosition(vec2 uv)
{
vec4 worldpos;
float depth = texture2D(DepthMap, uv).r;
worldpos.x = uv.x * 2.0f - 1.0f;
worldpos.y = uv.y * 2.0f - 1.0f;
worldpos.z = depth * 2.0f - 1.0f;
worldpos.w = 1.0;
worldpos = InvertViewProjection * worldpos;
worldpos /= worldpos.w;
return worldpos.rgb;
}
vec3 getNormal(vec2 uv)
{
return normalize(texture2D(NormalMap, uv).xyz * 2.0f - 1.0f);
}
vec2 getRandom(vec2 uv)
{
return normalize(texture2D(NoiseTexture, Resolution*uv / NoiseScale).xy * 2.0f - 1.0f);
}
float doAmbientOcclusion(in vec2 tcoord, in vec2 uv, in vec3 p, in vec3 cnorm)
{
vec3 diff = getPosition(tcoord + uv) - p;
vec3 v = normalize(diff);
float d = length(diff)*g_scale;
return max(0.0, dot(cnorm, v) - g_bias)*(1.0 / (1.0 + d))*g_intensity;
}
void main()
{
vec4 Kernels[KERNEL_SIZE] =
vec4[](
vec4(0.355512, -0.709318, -0.102371, 0.0 ),
vec4(0.534186, 0.71511, -0.115167, 0.0 ),
vec4(-0.87866, 0.157139, -0.115167, 0.0 ),
vec4(0.140679, -0.475516, -0.0639818, 0.0 ),
vec4(-0.0796121, 0.158842, -0.677075, 0.0 ),
vec4(-0.0759516, -0.101676, -0.483625, 0.0 ),
vec4(0.12493, -0.0223423, -0.483625, 0.0 ),
vec4(-0.0720074, 0.243395, -0.967251, 0.0 ),
vec4(-0.207641, 0.414286, 0.187755, 0.0 ),
vec4(-0.277332, -0.371262, 0.187755, 0.0 ),
vec4(0.63864, -0.114214, 0.262857, 0.0 ),
vec4(-0.184051, 0.622119, 0.262857, 0.0 ),
vec4(0.110007, -0.219486, 0.435574, 0.0 ),
vec4(0.235085, 0.314707, 0.696918, 0.0 ),
vec4(-0.290012, 0.0518654, 0.522688, 0.0 ),
vec4(0.0975089, -0.329594, 0.609803, 0.0 )
);
vec2 uv = CalcTexCoord(); //same as UV Coordinate from Vertex
vec3 p = getPosition(uv);
vec3 n = getNormal(uv);
vec2 rand = getRandom(uv);
float ao = 0.0f;
float rad = g_sample_rad / p.z;
for (int j = 0; j < KERNEL_SIZE; ++j)
{
vec2 coord = reflect(Kernels[j].xy, rand)*rad;
ao += doAmbientOcclusion(uv, coord, p, n);
}
ao /= KERNEL_SIZE;
ao = 1 - (ao);
gl_FragColor = vec4(ao,ao,ao, 1);
}
一步步调试代码搞定了
我计算世界上的一切space。那里的一切都更容易处理。 我查看了一个使用视图 space 的教程,并将我需要的所有内容更改为 world space.
错误在这里:
float rad = g_sample_rad / p.z;
这是根据距离计算采样半径。在视图 space 中,这会计算与相机距离的采样半径。 但在世界 space 中,这会计算与世界坐标的距离,这导致它在 z=0 处看起来很奇怪,在更远的地方甚至更奇怪。
所以我所做的修复很简单:
vec4 viewpos = CamView * vec4(p,1);
float ao = 0.0f;
float rad = g_sample_rad/viewpos.z;
我改变了视角 space 并计算了视角中的采样半径 space,因此考虑了与相机的距离。
这修复了它。
我对 g_values 进行了一些调整以适应我的需要。看看它看起来到处都一样。这就是它应该的样子。