Advertisement

Border in virtual texture

Started by June 23, 2019 02:42 AM
2 comments, last by Vilem Otte 5 years, 7 months ago

So, I've got my implementation of virtual textures finally fully complete - and at that moment I noticed some very annoying issue - when I'm mapping virtual -> physical coordinates, then I can clearly see that vertices on the edge are mapping the first row or column of next tile. Note. I'm using virtual texture as a height map - therefore reading it per-vertex.

Suppose I have 64 x 64 tile size, and my physical texture has 8 x 8 tiles (for simplicity - and this also matches the test scenario I'm using). I'm mapping virtual texture on the plane (like height map), and edges of the tile are clearly showing the adjacent tiles on 2 edges (and this happens only at level 3 and higher). So - this gave me today a major headache which I've been trying to solve, there is no way I was able to solve this properly.

I had an idea (most likely correct one) - if I'm not able to map tile properly, i.e. edge vertices are reading value outside of the tile - then I could simply use 62 x 62 tile, and having 1 pixel border. On paper it sounds nice, but I got a bit too messed in the math. In vertex shader the mapping of virtual -> physical coordinates look like this:


float2 physicalTexCoord = pageIndirectionTableData[page].xy + virtualTexCoord * pageIndirectionData[page].zw;

Where:

  • virtualTexCoord - represent virtual texture coordinates
  • pageIndirectionTableData - contain offset (in x and y channels) and scale (in z and w channels)
  • page - which physical page id is current processed vertex located in (the read from virtual -> physical is done 1 line above)

Now, this seems correct to me, and apart from that annoying edge of each tile being nuts - I have everything selected properly. To get rid of that, I have to add border, which should change how pageIndirectionTableData is calculated. Which now is:


int virtualx = address % (int)mPages[0];
int virtualy = address / (int)mPages[0];

float scalex = 1.0f / (float)mPages[0];
float scaley = 1.0f / (float)mPages[1];
float offsetx = (float)virtualx * scalex - baseoffsetx * scalex / basescalex;
float offsety = (float)virtualy * scaley - baseoffsety * scaley / basescaley;

mPageDescData[page * 4 + 0] = offsetx;
mPageDescData[page * 4 + 1] = offsety;
mPageDescData[page * 4 + 2] = scalex / basescalex;
mPageDescData[page * 4 + 3] = scaley / basescaley;

Where:

  • virtualx and virtualy - are and Y coordinates of page in physical texture (i.e. 2, 0 represent page that is located between (128, 0) and (192, 64) with 64 x 64 page size).
  • mPages - is representing how many physical pages are there along X and along Y direction in texture (for current test mPages[0] = mPages[1] = 8)
  • baseoffsetx and baseoffsety - represent location in virtual texture (0.25, 0.25) means that they point to the location of (64, 64) in my test scenario with 64 x 64 tiles and 4 x 4 tile size)
  • basescalex and basescaley - represent scaling, i.e. miplevel of the tile - 1.0 means miplevel 0 (I.e. top level where tile contains whole texture), value of 0.25 means miplevel 2

Adding border (with given pixel size - which is 1.0 / physicalResolution) means that I need to scale a bit differently and add offset after (which needs to be recalculated too), but I got a bit confused with the math (as I'm mostly using 0.0 - 1.0 when working with texture coordinates.

 

If anyone sees some issue (or experienced similar), any help is appreciated.

Thank you for reading!

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

4 hours ago, Vilem Otte said:

I had an idea (most likely correct one) - if I'm not able to map tile properly, i.e. edge vertices are reading value outside of the tile - then I could simply use 62 x 62 tile, and having 1 pixel border.

Yeah that's the standard solution for sparse virtual textures. You need to double that border size for each mipmap level that you support (if your pages have three mip levels, you need a 4px border at mip0, to give a 1px border at mip2)... You also need to multiply it by half your highest aniso samping rate -- if you use an 8x aniso sampler state, you need mip0 to have a 4px border area.

Advertisement
2 hours ago, Hodgman said:

You need to double that border size for each mipmap level that you support (if your pages have three mip levels, you need a 4px border at mip0, to give a 1px border at mip2)...

Thanks!

This means, the border can grow to quite a big one (so having 8px border is quite common then). I'll now need to do the math to properly fit from physical coordinates to virtual with border. Time to sketch it...

As for filtering - I don't use any (it is point sampled), this is due to using it as height map only (for terrain - the decision. Although I'm considering adding another virtual texture as other material layers (color, normals, roughness, etc.), which would require filtering - so doing generic enough implementation might be viable.

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

This topic is closed to new replies.

Advertisement