I’m developing a 3D multitexturing terrain engine in C# on Monogame (XNA) plateform. I would like my engine works on Windows XP or upper, so on DirectX 9c minimum.
Monogame allow me to build a DirectX 9c version of my engine, equal or less than a SM 2.0 (4_0_level_9_1) shader model.
Because there are not texture arrays on SM 2.0 and for performances, I use a texture atlas with each mipmaps build manually (to apply aliasing to each textures individually). My vertex structure contains textures coordinates of the texture atlas.
That’s all right ? Fine
In my case, the texture atlas looks like that (textures unity: 512×512 count: 6 total: 1024×1536):
So, normally there are 11 mipmaps for this texture size, but I have just generated 10 mipmaps to avoid textures bleeding. The last mipmap of the texture atlas is not set.
My pixel shader code look like this:
float4 MutiTexturing_PS(MultiTexturing_VSOut input) : COLOR
{
float4 _color;
_color = tex2D(TextureAtlasSampler, input.TextureUV1) * input.TextureOpacity.x;
_color += tex2D(TextureAtlasSampler, input.TextureUV2) * input.TextureOpacity.y;
_color += tex2D(TextureAtlasSampler, input.TextureUV3) * input.TextureOpacity.z;
_color += tex2D(TextureAtlasSampler, input.TextureUV4) * input.TextureOpacity.w;
return saturate(_color);
}
The result is that:
You can see at the background a gradient of dark: this is normal because the lastest mipmap is not set, so texture is transparent. I’ve have already tried to set the latest mipmap of texture atlas with the lastest generated mipmap (size: 2×3) but… the shader is more smart ! It knows the lastest mipmap must have a 1×1 size and and based its working area on that. So, the dark gradient become a red color.
To avoid the trouble, the only best solution that I have seen on the web is to use tex2Dlod (but if you have a better solution I take). This function return a color of a sampler texture at specified coordinates (like tex2D) but you can also specify the mip level to use. So, after lots of search, I found most frequently this function on the web to calculate the level of mipmap to use with the textures coordinates:
float GetMipmapLevel(float2 textureUV)
{
float2 dx = ddx(textureUV * TextureAltasWidth);
float2 dy = ddy(textureUV * TextureAltasHeight);
float1 d = max(dot(dx, dx), dot(dy, dy));
return log2(max(d, 1)) * 0.5f; // I can clamp mipmap here
}
But by changing my pixel shader code to use tex2Dlod(sampler, float4(texUV.xy, 0, LOD)) and GetMipmapLevel(texUV), I have this result:
I have adjust the calculation by using: return log2(max(d, 1)) * 0.75f;
You can see at the background, a similar result of tex2D function but … the hill at foreground is to blured !
This is (finally) my question, how can I adjust the mipmap level calculation to get the same result as the tex2D ? How the tex2D function does it ?
If your solution need to use a SM 4.0, I think I’m ready to leave the DirectX 9c support but I’m sure that’s possible to do in SM 2.0…
Resources link that can help other pepole in my case:
http://xboxforums.create.msdn.com/forums/p/82969/502102.aspx
http://xboxforums.create.msdn.com/forums/p/51280/309977.aspx