I am building a 3d renderer in C++ using Vulkan.hpp. I am trying to implement Spherical Harmonics (SH) coefficients for diffuse radiance as part of global illumination. To do this I am generating two cube maps: an image cube map and a depth cube map at the probe location. These cube maps are generated by directly rendering the scene 6 times at the probe location and copying the output image to the faces of the cube map. The depth cube map is rendered to a range of 0 to 1. I want to set up a compute shader to calculate the SH coefficients. I also want to do depth testing to ensure the radiance calculated from the SH coefficients doesn't cause and light bleeding and correctly produces ambient shadows. I have the start of the compute shader I want to generate and I have a starting function to incorporate the SH coefficients into the PBR lighting shader. I'm not sure if what I have started with is the right approach though. I have depth testing occurring in the compute shader where I may also need to do testing in the lighting fragment shader. Can you complete the below compute shader or modify it accordingly? I have also included the extract from the lighting shader that can also be modified if needed.

Lighting Shader extract:

layout(scalar, set = 0, binding = 18) buffer SHBuffer {
    vec3 shCoeffs[];
} shBuffer;


vec3 evalDiffuseIrradiance(vec3 normal) {
    float x = normal.x;
    float y = normal.y;
    float z = normal.z;

    // SH basis functions - same logic as in compute shader, scalar only
    float shBasis[9];
    shBasis[0] = 0.282095;         // 0: Y0^0
    shBasis[1] = 0.488603 * y;     // 1: Y1^-1
    shBasis[2] = 0.488603 * z;     // 2: Y1^0
    shBasis[3] = 0.488603 * x;     // 3: Y1^1
    shBasis[4] = 1.092548 * x * y; // 4: Y2^-2
    shBasis[5] = 1.092548 * y * z; // 5: Y2^-1
    shBasis[6] = 0.315392 * (3.0 * z * z - 1.0); // 6: Y2^0
    shBasis[7] = 1.092548 * x * z; // 7: Y2^1
    shBasis[8] = 0.546274 * (x * x - y * y); // 8: Y2^2

    vec3 irradiance = vec3(0.0);

    for (int i = 0; i < 9; ++i) {
        irradiance += shBuffer.shCoeffs[i] * shBasis[i];
    }
    return irradiance;
}


    vec3 irradiance = evalDiffuseIrradiance(fragNormal);

    vec3 ambientDiffuse = irradiance * fragAlbedo * (1.0 - metallic);
    float subsurfaceStrength = (1.0 - metallic) * roughness;
if (subsurfaceStrength > 0.3) { // Threshold for SSS materials
    float wrap = subsurfaceStrength * 1.0; // Wrap factor for ambient
    vec3 wrappedIrradiance = evalDiffuseIrradiance(normalize(fragNormal + view_dir * wrap)).rgb;
    ambientDiffuse = wrappedIrradiance * fragAlbedo * (1.0 - metallic);
}


Start of the SH Coefficient Compute Shader:

#version 450
#extension GL_EXT_scalar_block_layout : enable

#define PI 3.1415926535897932384626433832795
#define SH_ORDER 2  // For second-order SH (9 coefficients)
#define NUM_COEFFS ((SH_ORDER + 1) * (SH_ORDER + 1))
#define NUM_SAMPLES 64  // Number of samples per direction

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

layout(scalar, set = 0, binding = 0) buffer SHBuffer {
    vec3 shCoeffs[];
} shBuffer;

layout(set = 0, binding = 1) uniform samplerCube irradianceMap;
layout(set = 0, binding = 2) uniform samplerCube depthMap;
layout(set = 0, binding = 3) uniform ProbePosition {
    vec3 probePos;
};