# Calculating UV coordinates for sampling texture atlas

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;



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.

• 8192x8192? This would be 16 shadow maps but the text says side by side, could you please clarify? Oct 5, 2021 at 14:39
• @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 Oct 5, 2021 at 15:31
• shouldn't tile size be 8192/8 ? (or just plain 1024) Oct 5, 2021 at 15:48
• Also, is this code working with normalized texture coordinates or unnormalized texture coordinates? Oct 5, 2021 at 15:55
• @pmw1234 The textures coordinates are normalized Oct 5, 2021 at 16:10

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.

• Thanks for your answer. This seems to work but only for the shadowmap that is at index 0, a light with a shadowmap index of 1 for example will not produce correct shadows until it's index becomes 0 (for example if the first light is deleted). I'll accept your answer anyway maybe I'll figure it out. Oct 5, 2021 at 16:56
• 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 Oct 5, 2021 at 17:13
• 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. Oct 5, 2021 at 17:32