[Solved] Sparkling Textures - Mipmapping problem?

My plant/bush type models have an annoying sparkling effect. I’ve seen this before and it’s usually when i’ve forgotten to turn on Mipmapping for the model’s texture.

It’s definitely on for these (clump of grass, bush, larger bush) but as you can see they sparkle annoying when you move away from them.

Here’s a Youtube video of the problem.

Initially I thought there was a problem with my instanced model shader for the grass but the larger bush is just a normal non-instanced render and still shows the same problem.

Maybe the sampler is wrong? I’m a bit stumped. I could add a depth of field or FXAA type post processing effect to hide it and maybe that’s what I’ll need to do.

Here’s the shader for the instanced models:

// Camera settings.
float4x4 World;
float4x4 View;
float4x4 Projection;

float3 DiffuseLight = 1.25;
float3 AmbientLight = 0.25;
bool Highlight = true;

texture2D Texture;

sampler2D Sampler = sampler_state
{
Texture = (Texture);
MinFilter = Anisotropic; // Minification Filter
MagFilter = Anisotropic; // Magnification Filter
MipFilter = Linear; // Mip-mapping
AddressU = Wrap; // Address Mode for U Coordinates
AddressV = Wrap; // Address Mode for V Coordinates
};

struct VertexShaderInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TextureCoordinate : TEXCOORD0;
};

struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TextureCoordinate : TEXCOORD0;
float2 Depth : TEXCOORD1;
float3 Normal : TEXCOORD2;
};

struct PixelShaderOutput
{
half4 Color : COLOR0;
half4 Normal : COLOR1;
half4 Depth : COLOR2;
};

// Vertex shader helper function shared between the two techniques.
VertexShaderOutput VertexShaderCommon(VertexShaderInput input, float4x4 instanceTransform)
{
VertexShaderOutput output;

// Apply the world and camera matrices to compute the output position.
float4 worldPosition = mul(float4(input.Position.xyz,1), instanceTransform);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);

// Compute lighting, using a simple Lambert model.
float3 worldNormal = mul(input.Normal, instanceTransform);
//output.Normal = half4(worldNormal,0);
output.Normal = half4(input.Normal,0); //normalize(mul(input.Normal, (float3x3)World));

output.Depth.x = output.Position.z;
output.Depth.y = output.Position.w;

// Copy across the input texture coordinate.
output.TextureCoordinate = input.TextureCoordinate;

return output;
}

// Hardware instancing reads the per-instance world transform from a secondary vertex stream.
VertexShaderOutput HardwareInstancingVertexShader(VertexShaderInput input,
float4x4 instanceTransform : BLENDWEIGHT)
{
return VertexShaderCommon(input, mul(World, transpose(instanceTransform)));
}

PixelShaderOutput PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
PixelShaderOutput output;

float4 color = tex2D(Sampler, input.TextureCoordinate);

  output.Depth = input.Depth.x / input.Depth.y;

if (color.a < 0.4)
discard;

color.a = 0;

if (Highlight)
color.r *= 50.0f;

output.Color = color * 2.5f;

//output.Normal = half4(input.Normal,1);

// read the normal from the normal map
float3 normalFromMap = input.Normal;
//tranform to [-1,1]
//normalFromMap = 2.0f * normalFromMap - 1.0f;
//normalize the result
normalFromMap = normalize(normalFromMap);
//output the normal, in [0,1] space
output.Normal.rgb = 0.5f * (normalFromMap + 1.0f);

//specular Power
output.Normal.a = 1; //specularAttributes.a;
return output;
}

// Hardware instancing technique.
technique HardwareInstancing
{
pass Pass1
{
VertexShader = compile vs_4_0 HardwareInstancingVertexShader();
PixelShader = compile ps_4_0 PixelShaderFunction();
}
}

yeah looks like mip mapping is not working, but your shader looks alright.

I’ve had the issue before that the wrong sampler is used, not the one specified in the shader file, but that’s a while back and I haven’t checked on this again.

1 Like

Thanks Kosmo, helpful as always :slight_smile:

So should I set the sampler state in the code rather than the shader? I wasn’t entirely sure what the solution was from reading that post.

Or should I use the new dx11 way of setting it in the shader (which i’m not entirely clear on and will need to read up on)?

I tried not setting my Texture shader parameter and instead creating a sampler state and setting the texture like so:

    SamplerState mySamplerState = new SamplerState()
    {
       
        AddressU = TextureAddressMode.Wrap,
        AddressV = TextureAddressMode.Wrap,
        Filter = TextureFilter.LinearMipPoint
    };
    pDevice.Textures[0] = _InstanceModel.Texture;
    pDevice.SamplerStates[0] = mySamplerState;

And then adjusting the shader to:

texture2D Texture : register(t0);
sampler2D Sampler : register(s0);

Which unfortunately produces blankness, so I’m not doing something correctly.

You can format your code better and get syntax highlighting if you wrap it in triple backticks `

I think you said that to me before. I can’t seem to get it to work, I’m obviously being dumb.

Anyway…

I was thinking this was a problem with my deferred rendering or instancing or something but when I go back to the old XNA version of this there’s no sparkling effect at all so mipmapping is working just fine with deferred renderered instanced models (nice mouthful). So… I must be doing something wrong in the MG and I’m a bit stuck what it is.

I’ve tried:

  • Using the dx11 way of sampling based on the link above.
  • Setting the texture using device.texture and register in the shader
  • Making a sampler object in the code and setting it using device.samplerstate and register in the shader
  • I tried switching to a png rather than a tga (just in case).
  • Made sure mipmapping is definitely on the model’s texture in the content manager.

What else can I try? Any other suggestions please?

Check the last sampler used before this one. Set it to use mip mapping. See if that helps

Not sure what you mean Kosmo?

Check in your code to go back to the last texture sampler used (for example opaque ground or sth)

In the bug I found the sampler wasn’t updated so the one used previously was used instead

No matter what sampling technique I used nothing was changing. After examining the texture2d object associated with my model I could see it has mipmapping set to false (even though that texture had the setting enabled in the content manager). I solved it by manually loading and assigning the texture. Slightly different to how XNA worked but whatever, it works now and this is a decent solution.