我一直在OpenGL中使用SSAO。我决定从OpenGL中的本教程中为我的延迟渲染器实现SSAO 。不幸的是,我一直无法正常工作。被SSAO变暗的区域根据相机的位置而变化很大。我知道当相机移动时,SSAO的输出可能会有一些变化,但这比我在其他SSAO实现中观察到的要大得多。
这是片段着色器代码
void main() {
vec3 origin = positionFromDepth(texture2D(gDepth, samplePosition));
vec3 normal = texture2D(gNormal, samplePosition).xyz; //multiplying this
//by 2 and subtracting 1 doesn't seem to help
vec2 random = getRandom(samplePosition);
float radius = uRadius/origin.z;
float occlusion = 0.0;
int iterations = samples/4;
for (int i = 0; i<iterations; i++) {
vec2 coord1 = reflect(kernel[i], random)*radius;
vec2 coord2 = vec2(coord1.x*0.707 - coord1.y*0.707, coord1.x*0.707 + coord1.y*0.707);
occlusion += occlude(samplePosition, coord1 * 0.25, origin, normal);
occlusion += occlude(samplePosition, coord2 * 0.50, origin, normal);
occlusion += occlude(samplePosition, coord1 * 0.75, origin, normal);
occlusion += occlude(samplePosition, coord2, origin, normal);
}
color = vec4(origin, 1);
}
该positionFromDepth()
函数:
vec3 positionFromDepth(float depth) {
float near = frustrumData.x;
float far = frustrumData.y;
float right = frustrumData.z;
float top = frustrumData.w;
vec2 ndc;
vec3 eye;
eye.z = near * far / ((depth * (far - near)) - far);
ndc.x = ((gl_FragCoord.x/buffersize.x) - 0.5) * 2.0;
ndc.y = ((gl_FragCoord.y/buffersize.y) - 0.5) * 2.0;
eye.x = (-ndc.x * eye.z) * right/near;
eye.y = (-ndc.y * eye.z) * top/near;
return eye;
}
和occlude()
功能:
float occlude(vec2 uv, vec2 offsetUV, vec3 origin, vec3 normal) {
vec3 diff = positionFromDepth(texture2D(gDepth,(uv+offsetUV)))-origin;
vec3 vec = normalize(diff);
float dist = length(diff)/scale;
return max(0.0,dot(normal,vec)-bias)*(1.0/(1.0+dist))*intensity;
}
我觉得问题可能出在positionFromDepth()
功能上,除了我在渲染器的照明阶段使用相同的代码外,它可以完美地工作(我认为)。我已经看过这个代码一千遍了,还没有发现任何错误的地方。我试过了各种的价值观bias
,radius
,intenisty
,和scale
,但似乎并不成为问题。我担心我的法线或位置错误,所以下面是其中的一些屏幕截图:
重构位置:和普通缓冲区:
我会添加一个遮挡缓冲区的图像,但是问题仅在相机移动时才很明显,而图像却无助于显示。
有人知道这是怎么回事吗?
奇怪的是,乘以2并减去1对您的法线贴图没有帮助。通常这样做是为了克服与以无符号/标准化纹理格式存储法线有关的问题。除非您的普通G缓冲区是有符号/非规格化格式,否则您可能需要* 0.5 + 0.5
在首次写入* 2.0 - 1.0
纹理和对纹理进行采样时使用来打包和解压缩正常。
无论如何,SSAO有多种方法,许多甚至根本不使用表面法线。因此,关于将法线存储在哪个向量空间上的讨论经常被忽略。
我强烈怀疑您的法线是在视野空间中,而不是在世界空间中。如果将法线与顶点着色器中的“法线矩阵”相乘(就像许多教程一样),则法线将在视图空间中。
事实证明,视图空间法线的确没有那么有用,因为如今的后处理效果的数量在使用世界空间法线的情况下效果更好。大多数现代延迟着色引擎(例如,虚幻引擎4,CryEngine 3等)都将常规G缓冲区存储在世界空间中,然后在像素着色器中将其转换为视图空间(如果需要)。
顺便说一句,我包括了一些代码,这些代码用于从传统的深度缓冲区重建对象空间的位置。您似乎正在使用视图空间位置/法线。您可能想尝试对象/世界空间中的所有内容。
平放在mat4 inv_mv_mat; 在vec2 uv中; ... 浮动linearZ(float z) { #ifdef INVERT_NEAR_FAR const float f = 2.5; const float n = 25000.0; #别的 const float f = 25000.0; const float n = 2.5; #万一 返回n /(f-z *(f-n))* f; } vec4 Constructor_pos(以浮动深度为单位) { 深度= linearZ(深度); vec4 pos = vec4(uv *深度,-depth,1.0); vec4 ret =(inv_mv_mat * pos); 返回ret / ret.w; }
在延期着色光照过程的顶点着色器阶段需要一些额外的设置,如下所示:
#version 150核心 在vec4中vtx_pos; 在vec2中vtx_st; 统一的mat4 modelview_mat; //构建G-Buffer时使用的矩阵 统一的mat4 camera_matrix; //用于在视口上拉伸G缓冲区的矩阵 统一浮点buffer_res_x; 统一浮点buffer_res_y; 出vec2 tex_st; 整理mat4 inv_mv_mat; 出vec2 uv; //硬编码45度FOV // const float fovy = 0.78539818525314331; //下面的行中有NV恶作剧! // const float fovy =弧度(45.0); // const float tan_half_fovy = tan(fovy * 0.5); const float tan_half_fovy = 0.41421356797218323; 浮动方面= buffer_res_x / buffer_res_y; vec2 inv_focal_len = vec2(tan_half_fovy *方面, tan_half_fovy); const vec2 uv_scale = vec2(2.0,2.0); const vec2 uv_translate = vec2(1.0,1.0); void main(无效) { inv_mv_mat =逆(modelview_mat); tex_st = vtx_st; gl_Position = camera_matrix * vtx_pos; uv =(vtx_st * uv_scale-uv_translate)* inv_focal_len; }
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句