A game about forced loneliness, made by TACStudios
at master 220 lines 7.8 kB view raw
1#include "GraniteShaderLibBase.hlsl" 2 3#define VtAddressMode_Wrap 0 4#define VtAddressMode_Clamp 1 5#define VtAddressMode_Udim 2 6 7#define VtFilter_Anisotropic 0 8 9#define VtLevel_Automatic 0 10#define VtLevel_Lod 1 11#define VtLevel_Bias 2 12#define VtLevel_Derivatives 3 13 14#define VtUvSpace_Regular 0 15#define VtUvSpace_PreTransformed 1 16 17#define VtSampleQuality_Low 0 18#define VtSampleQuality_High 1 19 20struct VtInputParameters 21{ 22 float2 uv; 23 float lodOrOffset; 24 float2 dx; 25 float2 dy; 26 int addressMode; 27 int filterMode; 28 int levelMode; 29 int uvMode; 30 int sampleQuality; 31 int enableGlobalMipBias; 32}; 33 34int VirtualTexturingLookup( 35 in GraniteConstantBuffers grCB, 36 in GraniteTranslationTexture translationTable, 37 in VtInputParameters input, 38 out GraniteLookupData graniteLookupData, 39 out float4 resolveResult 40) 41{ 42 GraniteStreamingTextureConstantBuffer grSTCB = grCB.streamingTextureBuffer; 43 GraniteTilesetConstantBuffer tsCB = grCB.tilesetBuffer; 44 45 float2 texCoord = input.uv; 46 float2 dx; 47 float2 dy; 48 float mipLevel; //interger 49 50 if (input.levelMode == VtLevel_Automatic) 51 { 52 dx = ddx(texCoord); 53 dy = ddy(texCoord); 54 } 55 else if (input.levelMode == VtLevel_Bias) 56 { 57 // We can't simply add the bias after the mip-calculation since the derivatives 58 // are also used when sampling the cache so make sure we apply bias by scaling derivatives 59 if ( input.sampleQuality == VtSampleQuality_High ) 60 { 61 float offsetPow2 = pow(2.0f, input.lodOrOffset); 62 dx = ddx(texCoord) * offsetPow2; 63 dy = ddy(texCoord) * offsetPow2; 64 } 65 // In low quality we don't care about cache derivatives and will add the bias later 66 else 67 { 68 dx = ddx(texCoord); 69 dy = ddy(texCoord); 70 } 71 } 72 else if (input.levelMode == VtLevel_Derivatives) 73 { 74 dx = input.dx; 75 dy = input.dy; 76 } 77 else /*input.levelMode == VtLevel_Lod*/ 78 { 79 //gra_TrilinearOffset ensures we do round-nearest for no-trilinear and 80 //round-floor for trilinear. 81 float clampedLevel = clamp(input.lodOrOffset + gra_TrilinearOffset, 0.0f, gra_NumLevels); 82 mipLevel = floor(clampedLevel); 83 dx = float2(frac(clampedLevel), 0.0f); // trilinear blend ratio 84 dy = float2(0.0f,0.0f); 85 } 86 87 // Transform the derivatives to atlas space if needed 88 if (input.uvMode == VtUvSpace_Regular && input.levelMode != VtLevel_Lod) 89 { 90 dx = gra_Transform.zw * dx; 91 dy = gra_Transform.zw * dy; 92 } 93 94 if (input.levelMode != VtLevel_Lod) 95 { 96 #ifdef VT_GLOBAL_MIP_BIAS_MULTIPLIER 97 if (input.enableGlobalMipBias) 98 { 99 dx *= VT_GLOBAL_MIP_BIAS_MULTIPLIER; 100 dy *= VT_GLOBAL_MIP_BIAS_MULTIPLIER; 101 } 102 #endif 103 104 mipLevel = GranitePrivate_CalcMiplevelAnisotropic(grCB.tilesetBuffer, grCB.streamingTextureBuffer, dx, dy); 105 106 // Simply add it here derivatives are wrong from this point onwards but not used anymore 107 if ( input.sampleQuality == VtSampleQuality_Low && input.levelMode == VtLevel_Bias) 108 { 109 mipLevel += input.lodOrOffset; 110 // GranitePrivate_CalcMiplevelAnisotropic will already clamp between 0 gra_NumLevels 111 // But we need to do it again here. The alternative is modifying dx,dy before passing to 112 // GranitePrivate_CalcMiplevelAnisotropic adding a pow2 + 4 fmuls so probably 113 // the exra clamp is more appropriate here. 114 mipLevel = clamp(mipLevel, 0.0f, gra_NumLevels); 115 } 116 117 mipLevel = floor(mipLevel + 0.5f); //round nearest 118 } 119 120 // Apply clamp/wrap mode if needed and transform into atlas space 121 // If the user passes in pre-transformed texture coords clamping and wrapping should be handled by the user 122 if (input.uvMode == VtUvSpace_Regular) 123 { 124 if (input.addressMode == VtAddressMode_Wrap) 125 { 126 texCoord = frac(input.uv); 127 } 128 else if (input.addressMode == VtAddressMode_Clamp) 129 { 130 float2 epsilon2 = float2(gra_AssetWidthRcp, gra_AssetHeightRcp); 131 texCoord = clamp(input.uv, epsilon2, float2(1,1) - epsilon2); 132 } 133 else if (input.addressMode == VtAddressMode_Udim) 134 { 135 // not modified (i.e outside of the 0-1 range, atlas transform below will take care of it) 136 texCoord = input.uv; 137 } 138 139 texCoord = Granite_Transform(gra_StreamingTextureCB, texCoord); 140 } 141 142 // calculate resolver data 143 float2 level0NumTiles = float2(gra_Level0NumTilesX, gra_Level0NumTilesX*gra_NumTilesYScale); 144 float2 virtualTilesUv = floor(texCoord * level0NumTiles * pow(0.5, mipLevel)); 145 resolveResult = GranitePrivate_MakeResolveOutput(tsCB, virtualTilesUv, mipLevel); 146 147 float4 translationTableData; 148 if (input.levelMode != VtLevel_Lod) 149 { 150 // Look up the physical page indexes and the number of pages on the mipmap 151 // level of the page in the translation texture 152 // Note: this is equal for both anisotropic and linear sampling 153 // We could use a sample bias here for 'auto' mip level detection 154#if (GRA_LOAD_INSTR==0) 155 translationTableData = GranitePrivate_SampleLevel_Translation(translationTable, texCoord, mipLevel); 156#else 157 translationTableData = GranitePrivate_Load(translationTable, gra_Int3(virtualTilesUv, mipLevel)); 158#endif 159 } 160 else 161 { 162 // Look up the physical page indexes and the number of pages on the mipmap 163 // level of the page in the translation texture 164 // Note: this is equal for both anisotropic and linear sampling 165 // We could use a sample bias here for 'auto' mip level detection 166#if (GRA_LOAD_INSTR==0) 167 translationTableData = GranitePrivate_SampleLevel_Translation(translationTable, texCoord, mipLevel); 168#else 169 translationTableData = GranitePrivate_Load(translationTable, gra_Int3(virtualTilesUv, mipLevel)); 170#endif 171 } 172 173 graniteLookupData.translationTableData = translationTableData; 174 graniteLookupData.textureCoordinates = texCoord; 175 graniteLookupData.dX = dx; 176 graniteLookupData.dY = dy; 177 178 return 1; 179} 180 181int VirtualTexturingSample( 182 in GraniteTilesetConstantBuffer tsCB, 183 in GraniteLookupData graniteLookupData, 184 in GraniteCacheTexture cacheTexture, 185 in int layer, 186 in int levelMode, 187 in int quality, 188 out float4 result) 189{ 190 // Convert from pixels to [0-1] and look up in the physical page texture 191 float2 deltaScale; 192 float3 cacheCoord = GranitePrivate_TranslateCoord(tsCB, graniteLookupData.textureCoordinates, graniteLookupData.translationTableData, layer, deltaScale); 193 194 if ( levelMode != VtLevel_Lod ) 195 { 196 if ( quality == VtSampleQuality_Low ) 197 { 198 // This leads to small artefacts at tile borders but is generally not noticable unless the texture 199 // is greatly magnified 200 result = GranitePrivate_SampleArray(cacheTexture, cacheCoord); 201 } 202 else /* quality == VtSampleQuality_High */ 203 { 204 deltaScale *= gra_LodBiasPow2; 205 206 // Calculate the delta scale this works by first converting the [0-1] texcoord deltas to 207 // pixel deltas on the current mip level, then dividing by the cache size to convert to [0-1] cache deltas 208 float2 sampDeltaX = graniteLookupData.dX*deltaScale; 209 float2 sampDeltaY = graniteLookupData.dY*deltaScale; 210 211 result = GranitePrivate_SampleGradArray(cacheTexture, cacheCoord, sampDeltaX, sampDeltaY); 212 } 213 } 214 else 215 { 216 result = GranitePrivate_SampleLevelArray(cacheTexture, cacheCoord, graniteLookupData.dX.x); 217 } 218 219 return 1; 220}