Shadows: Using a shadow map

I am trying to render shadows in a Metal view. I am using two render passes. In the first pass the view is rendered into a 2d depth texture from the point of view of a point light source. This writes into the depth texture a shadow map of the minimum depths in the view . In the second pass the view is rendered to the viewport. In this second pass the vertex shader transposes the input position to the point light POV giving a shadowSpacePosition. In the fragment shader the depth of a point in the shadow map is compared to the depth of the shadowSpacePosition and the result is used to modify color of that point.

The first pass seems to be working as desired. The shadow map shown in a frame capture looks good. The problem I am having is that I don't know how the coordinates used in shadowSpacePosition relate the to coordinates in the shadow map. How do I transpose the x,y,z of the shadowPosition so that the comparison function gives the proper result?

cmp = shadowTexture.sample_compare(shadowSampler, shadowPosition.xy , shadowPosition.z);

The shadowPosition coordinates are in world space relative to the light position frustum with the origin at the light. I don't know what the above comparison function expects. Texture coordinates clamped 0 to 1?

Any insights would be appreciated. Below are the relevant shaders:

Code Block // Vertex shader outputs and fragment shader inputstypedef struct{    float4 clipSpacePosition [[position]];    float4 eyeSpacePosition;    float4 shadowSpacePosition;    float2 textureCoordinate;    float4 normal;    float4 color;} RasterizerData;// *******************************************************// ******** Shaders for Textured Models ************// *******************************************************// Vertex functionvertex RasterizerData vertexTexShader(    uint                   vertexID [[vertex_id]],    constant HT_Vertex     *vertices [[buffer(HT_Vertex_Index)]],    constant HT_Uniform    *param [[buffer(HT_Uniform_Index)]] ){    RasterizerData  out;    vector_float4  newPosition = float4( vertices[vertexID].position , 1 );    newPosition = param->nodeTransform[ vertices[vertexID].pickID ] * newPosition;    out.eyeSpacePosition = newPosition;    out.clipSpacePosition = param->perspectiveTransform * newPosition;    out.shadowSpacePosition = param->toLampPOV * newPosition;    out.shadowSpacePosition = param->shadowPerspective * newPosition;    // Apply rotations about the origin to the normals    vector_float4 newNormal = float4( vertices[vertexID].normal , 1);    out.normal = param->normalsTransform[vertices[vertexID].pickID] * newNormal;    out.textureCoordinate = vertices[vertexID].textCoor;    return out;}// Fragment functionfragment float4 fragmentTexShader(    RasterizerData                      in [[stage_in]],    constant HT_Uniform                 *param [[buffer(HT_Uniform_Index)]],    texture2d<half>                     colorTexture [[ texture(HT_Texture_Index) ]],    depth2d<float , access::sample>     shadowTexture [[ texture(HT_Shadow_Index)]],    sampler                             textureSampler [[sampler(HT_Texture_Index)]]){    vector_float4   outColor;    vector_float3   lightDirection;    float           lightDistance;    float           attenuation;    vector_float3   halfVector;    float           diffuse;    float           specular;    float           cmp;    float           coorRatio;    vector_float3   shadowPosition;    vector_float3   scatteredLight;    vector_float3   reflectedLight;    vector_float3   rgb;    half4           colorSample;    bool            isShadow;     constexpr sampler shadowSampler(coord::normalized,                                     filter::linear,                                     address::clamp_to_edge,                                     compare_func:: less);    shadowPosition = in.shadowSpacePosition.xyz;    cmp = shadowTexture.sample_compare(shadowSampler, shadowPosition.xy , shadowPosition.z);   if(cmp < 0.0001)       isShadow = true;    else        isShadow = false;    // Sample the texture to obtain a color    colorSample = colorTexture.sample(textureSampler, in.textureCoordinate);// *********// Apply Lighting Model// *******     return outColor;    }// *****************************************************// ******** Shaders: Make Shadow Map ************// *******************************************************typedef struct{    float4 clipSpacePosition [[position]];} ShadowData;// Vertex functionvertex ShadowData shadowVertexShader( uint                   vertexID [[vertex_id]], constant HT_Vertex     *vertices [[buffer(HT_Vertex_Index)]], constant HT_Uniform    *param [[buffer(HT_Uniform_Index)]]){    ShadowData out;    vector_float4  newPosition = float4( vertices[vertexID].position , 1 );    newPosition = param->nodeTransform[ vertices[vertexID].pickID ] * newPosition;    newPosition = param->toLampPOV * newPosition;    newPosition = param->shadowPerspective * newPosition;    out.clipSpacePosition = newPosition;    return out;}


After over a week of wandering around in the dark, I discovered how convert the coordinates. The input shadowSpacePosition is in Metal Normalized Coordinates: x and y -1 to 1, z 0 to 1 with the origin at the center of the drawable. When this is stored in the depth texture it is converted to texture coordinates: x,y and z 0 to 1 with the origin on the bottom-left. So to read the proper depth in the depth texture the code is:

Code Block      constexpr sampler shadowSampler(coord::normalized,                                     filter::linear,                                     address::clamp_to_zero,                                     compare_func:: less);    shadowPosition = in.shadowSpacePosition.xyz;    shadowPosition.y *= -1;    shadowPosition.xy += 1.0;    shadowPosition.xy /= 2;    cmp = shadowTexture.sample_compare(shadowSampler, shadowPosition.xy , shadowPosition.z);   if(cmp < 0.1)       isShadow = true;    else        isShadow = false;


Shadows: Using a shadow map
 
 
Q