I have an 8192x8192 texture atlas that contains 1024x1024 shadow maps aligned side by side. I'm trying to calculate the uv coordinates so that I can sample each shadow map appropriately based on the 'shadowIndex' of my light. With a single non-atlas shadowmap I can easily calculate the uv coordinates like this:

tc.x = lightViewPosition.x / lightViewPosition.w / 2.0f + 0.5f;
tc.y = -lightViewPosition.y / lightViewPosition.w / 2.0f + 0.5f;

shadowFactor += shadowMap.SampleCmpLevelZero(SampleComp, tc, lightDepthValue);

How can I replicate the same thing while also factoring in an offset for sampling the correct shadow map from the atlas? I tried this:

tc.x = lightViewPosition.x / lightViewPosition.w / 2.0f + 0.5f;
tc.y = -lightViewPosition.y / lightViewPosition.w / 2.0f + 0.5f;

float tileSize = 1024.0f / 8.0f;
float tileOffset = tileSize * lights[i].shadowIndex;

tc += frac((tc - tileOffset) / tileSize) * tileSize + tileOffset;

But this does not work correctly. Additionally I have to consider that the y (V) coordinate should not be affected while the shadow index isn't a multiple of 8 because there are 8 shadow maps per row. Any ideas? Thanks.

  • $\begingroup$ 8192x8192? This would be 16 shadow maps but the text says side by side, could you please clarify? $\endgroup$
    – pmw1234
    Commented Oct 5, 2021 at 14:39
  • $\begingroup$ @pmw1234 They are aligned side by side in each row is what I meant. If there was more than 8 then the subsequent shadowmaps will be put on the next row $\endgroup$
    – H3XXX
    Commented Oct 5, 2021 at 15:31
  • $\begingroup$ shouldn't tile size be 8192/8 ? (or just plain 1024) $\endgroup$
    – pmw1234
    Commented Oct 5, 2021 at 15:48
  • $\begingroup$ Also, is this code working with normalized texture coordinates or unnormalized texture coordinates? $\endgroup$
    – pmw1234
    Commented Oct 5, 2021 at 15:55
  • $\begingroup$ @pmw1234 The textures coordinates are normalized $\endgroup$
    – H3XXX
    Commented Oct 5, 2021 at 16:10

1 Answer 1


Assuming normalized texture coordinates and a grid of 8x8 (which is 64 tiles not 16 like I said in the comments) then tileOffset will need to be a vec2 for the x and y offsets.

Also, assuming texture coordinates tc are mapped to a single texture map (0,1).

Then the new texture coordinates for tile 0,0 are tc = (tc*vec2(1024,1024))/vec2(8192,8192); For tile 1 the texture coordinates would added 1024/8192 to the tc.x, tile two would add 2048/8192 to tc.x and so forth up to tile 8.

tc.y doesn't change till tile 8 which then gets 1024/8192 added to it until tile 16 and so forth.

So the tile specific texture coords would be

tc = (tc*vec2(1024,1024))/vec2(8192,8192);
tc.x += ((lights[i].shadowIndex % 8) * 1024)/8192.0;
tc.y += ((lights[i].shadowIndex / 8) * 1024)/8192.0;

Where the %8 and /8 are indicating integer modulus and division. This is just psudo code and I was using the upper left corner as 0,0 but the idea is the same for other origins.

Edit: The code is converting normalized coordinates to unnormalized coordinates for a texture map size of 1024x1024. Then converting that to normalized coordinates for a texture maps size of 8192x8192.

Then it computes the normalized offsets for x and y and adds them to get the grid specific location.

  • $\begingroup$ Changing the code to tc.y += (0 * 1024.0) / 8192.0; has fixed it, looks like some kind of issue with the tiling in the 'y' direction $\endgroup$
    – H3XXX
    Commented Oct 5, 2021 at 17:13
  • 1
    $\begingroup$ The bit of code (lights[i].shadowIndex / 8) might be computing a floating point value instead of an integer value which would give an incorrect result by scewing everything by some small floating point offset. $\endgroup$
    – pmw1234
    Commented Oct 5, 2021 at 17:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.