I was trying to implement the Crytek SSAO technique based on a shader shown in the Appendix of the following paper:
However, when implementing and running the shader, it kept giving me this graining look and I cannot seem to identify what might have caused this particular issue.
My implementation of the shader:
#version 450
layout(binding = 3) uniform sampler2D texNoise;
layout(binding = 6) uniform sampler2D depthMap;
layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 uvCoords;
layout(binding = 5) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
float time;
}camera;
layout(binding = 4) uniform KernelSample {
vec3 samples[64];
mat4 projection;
vec4 camera_eye;
vec4 camera_direction;
float z_far;
}kernelsamples;
int kernelSize = 64;
layout(location = 0) out vec4 outColor;
vec4 ambient_occlusion;
float ec_depth(in vec2 tc)
{
float buffer_z = texture(depthMap, tc).x;
return camera.proj[3][2] / (-2.0 * buffer_z + 1.0 - camera.proj[2][2]);
}
const vec2 window = vec2(2560.0, 1440.0);
void main()
{
vec2 tc_depths = gl_FragCoord.xy / uvCoords;
float ec_depth_negated = -ec_depth(tc_depths);
vec3 wc_positions = kernelsamples.camera_eye.xyz + kernelsample.camera_direction * ec_depth_negated / kernelsamples.z_far;
ambient_occlusion.a = 0.0f;
const float radius = 10.0f;
const int samples = 64;
float projection_scale_xy = 1.0 / ec_depth_negated;
float projection_scale_z = 100.0 / kernelsamples.z_far * projection_scale_xy;
float scene_depth = texture(depthMap, tc_depths).x;
vec2 inverted_random_texture_size = 1.0 / vec2(textureSize(texNoise, 0));
vec2 tc_random_texture = gl_FragCoord.xy * inverted_random_texture_size;
vec3 random_direction = texture(texNoise, tc_random_texture).xyz;
random_direction = normalize(random_direction * 2.0 - 1.0);
for(int i = 0; i < samples; i++)
{
vec3 sample_random_direction = texture(texNoise, vec2(float(i) *
inverted_random_texture_size.x, float(i / textureSize(texNoise, 0).x) *
inverted_random_texture_size.y)).xyz;
sample_random_direction = sample_random_direction * 2.0 - 1.0;
sample_random_direction = reflect(sample_random_direction, random_direction);
vec3 tc_sample_pos = vec3(tc_depths.xy, scene_depth)
+ vec3(sample_random_direction.xy * projection_scale_xy,
sample_random_direction.z * scene_depth * projection_scale_z) * radius;
float sample_depth = texture(depthMap, tc_sample_pos.xy).x;
ambient_occlusion.a += float(sample_depth > tc_sample_pos.z);
}
ambient_occlusion.a /= float(kernelSize);
outColor = ambient_occlusion;
}
C++
// Projection
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width /
(float)swapChainExtent.height, 0.1f, 1000.0f);
ubo.proj[1][1] *= -1;
KernelSample ks{};
.....
ks.cameraEye = glm::vec4(cameraPosition, 0.0f);
ks.cameraDirection = glm::vec4(cameraPosition + cameraCenter, 1.0f);
RenderPass
VkAttachmentDescription colorAttachment{};
colorAttachment.format = VK_FORMAT_R16_SFLOAT;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentDescription depthAttachment = {};
depthAttachment.format = format;
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthAttachmentRef{};
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorAttatchmentRef{};
colorAttatchmentRef.attachment = 0;
colorAttatchmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttatchmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
VkSubpassDependency dependency{};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
std::array<VkAttachmentDescription, 2> attachments = { colorAttachment, depthAttachment };
VkRenderPassCreateInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;