//----------------------------------------------------------------------------- // Program Name: SGXLib_IntegratedPSSM // Program Desc: Texture Atlas functions. // Program Type: Vertex/Pixel shader // Language: CG //----------------------------------------------------------------------------- float mipmapLevel(float2 coords, float2 texSize) { coords = coords.xy * texSize; float2 dx = ddx(coords.xy); float2 dy = ddy(coords.xy); float Px = length(dx); float Py = length(dy); float Pmax = max(Px, Py); return log2(max(Pmax,1)); } //----------------------------------------------------------------------------- void SGX_Atlas_Sample_Auto_Adjust(in sampler2D sample, in float2 origTexcoord, in float2 atlasTexcoord, in float4 textureData, in float2 imageSize, out float4 texel) { // // Most of the idea for this function has been taken from the code under the webpage: // http://www.gamedev.net/topic/534149-solved-texture-seams-using-atlas-with-screenshots/ // origTexcoord - original texture coordintates as received from the vertex buffer. // atlasTexcoord - texture coordinates that have gone through on which different mathematical // functions to simulate different texture addressing modes (wrap, mirror, clamp) // textureData.xy - top left corner (in 0-1 units) where the needed texture in the texture atlas begins // textureData.zw - width and height in power of 2 for the needed texture in the texture atlas // imageSize - size of the image in pixels // texel - [Output] The color of the pixel at the requested position float2 startPos = textureData.xy; // calculate the tileSize by using the power of 2 value float2 pwrs = textureData.zw; //Calculate the power of 2 size of the maximum avialable Mipmap //Note: We limit the amount of available LODs to [actual number] - 2 //as some atlas packaging tools do not include the last 2 LODs //when packeging DXT format atlas textures. float availableLODCount = min(pwrs.x,pwrs.y) - 2; float2 tileSize = pow(float2(2.0,2.0),pwrs); // retrieve the mipmap level for this pixel clamped by the power of 2 value float lod = clamp(mipmapLevel(origTexcoord, tileSize), 0, availableLODCount); float2 relativeTileSize = tileSize / imageSize; // get the width/height of the mip surface we've decided on float2 mipSize = pow(float2(2.0,2.0), pwrs.xy - ceil(lod)); // compute the inverse fraction size for the tile //float2 lodSize = mipSize * imageSize / tileSize; float2 lodSizeInv = (relativeTileSize / mipSize); //compute the new coordinates //atlasTexcoord = atlasTexcoord * ((lodSize * (tileSize / imageSize) - 1.0) / lodSize) + (0.5 / lodSize) + startPos; atlasTexcoord = atlasTexcoord * (relativeTileSize - lodSizeInv) + (0.5 * lodSizeInv) + startPos; //return the pixel from the correct mip surface of the atlas texel = tex2Dlod(sample, float4(atlasTexcoord, 0, lod)); } //----------------------------------------------------------------------------- void SGX_Atlas_Sample_Normal(in sampler2D sample, in float2 origTexcoord, in float2 atlasTexcoord, in float4 textureData, in float2 imageSize, out float4 texel) { //texcoord contain: // x = texture atlas u // y = texture atlas v // z = derivative of original u // w = derivative of original v atlasTexcoord = textureData.xy + (atlasTexcoord * pow(float2(2.0,2.0),textureData.zw) / imageSize); //texel = tex2Dlod(sample, float4(atlasTexcoord, 0,0)); texel = tex2D(sample, atlasTexcoord); } //----------------------------------------------------------------------------- void SGX_Atlas_Wrap(in float inpCoord, out float outCoord) { outCoord = frac(inpCoord); } //----------------------------------------------------------------------------- void SGX_Atlas_Clamp(in float inpCoord, out float outCoord) { outCoord = saturate(inpCoord); } //----------------------------------------------------------------------------- void SGX_Atlas_Mirror(in float inpCoord, out float outCoord) { outCoord = (inpCoord + 1) * 0.5; outCoord = abs(frac(outCoord) * 2 - 1); } //----------------------------------------------------------------------------- void SGX_Atlas_Border(in float inpCoord, out float outCoord) { // //The shader needs to check whether the original texcoord are beyond the 0,1 range. //The shader attempts to do so without using if statments which are complicated for shaders // //if texcoord is in the 0,1 range then check will equal 0, //Otherwise it will equal the number 1 or greater float check = step(inpCoord, 0) + step(1, inpCoord); //using the check value transport the value of the texcoord beyond the 0,1 range so it will //recive the border color outCoord = abs(inpCoord) + check * 2; }