Crytek SSAO算法OpenGL

时间:2017-06-02 20:32:44

标签: c++ opengl ssao

我正在尝试实现Crytek的屏幕空间环境遮挡算法的简单变体。

根据我的理解算法;

  1. 对于像素 p ,在视图空间的球体中围绕 p 进行采样。
  2. 将采样点 sp 投影到屏幕空间。
  3. 将采样点的深度与当前像素的深度进行比较。
  4. 基本上应该是它的全部内容。如果采样点的深度较高(它位于几何体之外),则不会遮挡当前像素( p )。

    float z = gl_FragCoord.z; // depth-buffer value for the current pixel
    int occluding_points = 0;
    vec4 fPosition = model_transformation * vec4(position, 1.0f); // Really from vertex shader
    #ifdef CRYTEK_AO
        const int NUM_SAMPLES = 10;
        float R = 3.0f;
        const float[10] steps = float[](0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f);
        for (int sample_id = 0; sample_id < NUM_SAMPLES; sample_id++) {
            // 1. Generate sample point in world space.
            float ang = steps[sample_id];
            vec4 sample_point = vec4(R * cos(2 * M_PI * ang) * sin(M_PI * ang) + fPosition.x,
                                     R * sin(2 * M_PI * ang) * sin(M_PI * ang) + fPosition.y,
                                     R * sin(M_PI * ang) + fPosition.z,
                                     1.0f);
            // 2. Transform sample point from view space to screen space to get its depth value.
            sample_point = projection * camera_view * sample_point; // Clip space
            sample_point = sample_point / sample_point.w;           // Perspective division - Normalized device coordinate
            float sample_depth = 0.5f * (sample_point.z + 1.0f);    // Viewport transform for z - window space
    
            // 3. Check whether sample_point is behind current pixel depth.
            if (sample_depth > z) { occluding_points++; }
        }
        occlusion_factor = occluding_points / float(NUM_SAMPLES);
        // Diffuse, specular components removed
        total_light += vec3(ambient_intensity) * (1.0f - occlusion_factor); // Ambient factor
        outColor = total_light;
    #endif
    

    下面是它的外观截图。出于某种原因,只有在向下看z轴时才会出现伪影,因此转换时可能会有些瑕疵,尽管在渲染对象和相机等时工作正常。

    Ambient occlusion gone wrong...

    当基本上看任何其他角度时,您可以将遮挡因子设置为0.5(这将使您在所有颜色通道中变灰)。

    Nothing abnormal

    意外整数除法后的结果固定为浮点数除法。 enter image description here

    添加了闪烁的视频here

    任何线索?

    编辑:在舍入时检测到一个问题。 编辑:沿z轴移动时为工件添加了视频链接。

1 个答案:

答案 0 :(得分:2)

您的代码有两个可疑的东西。

整数除法

occlusion_factor = occluding_points / NUM_SAMPLES;

只需将occluding_points的类型更改为float,你应该没问题。

取样

    vec4 sample_point = vec4(R * cos(2 * M_PI * ang) * sin(M_PI * ang) + fPosition.x,
                             R * sin(2 * M_PI * ang) * sin(M_PI * ang) + fPosition.y,
                             R * sin(M_PI * ang) + fPosition.z,
                             1.0f);

这为您提供每次世界坐标中相同螺旋的样本,因此对于右表面,您将根据视角获得伪影。当你向下看z轴时,我认为它发生了什么,当与上面的舍入误差配对时。