I'm just getting started with XNA and I am sure I am missing something very simple. I have a quad plane I drew for the ground. On this plane I wrapped a 2D texture. The texture looks good up close, but as I move the camera around, I see a bunch of white artifacts all over the place. They disappear as I get close to them. I'm guessing this is a sampling problem or something similar, but I am stuck.
First, I created a QuadDrawer class to draw the plane for me. It's derived from DrawableGameComponent.
QuadDrawer:
class QuadDrawer : DrawableGameComponent
{
private string _textureName;
private Texture2D _texture;
private BasicEffect _effect;
private float _size = 100;
private VertexPositionNormalTexture[] _vertices;
private int[] _indices;
public QuadDrawer(Game game, float size, string textureName)
: base(game)
{
this._size = size;
this._textureName = textureName;
}
public override void Initialize()
{
BuildVertices();
base.Initialize();
}
private void BuildVertices()
{
_vertices = new VertexPositionNormalTexture[4];
_indices = new int[6];
_vertices[0].Position = Vector3.Forward + Vector3.Left;
_vertices[0].TextureCoordinate = new Vector2(0.0f, 1.0f);
_vertices[1].Position = Vector3.Backward + Vector3.Left;
_vertices[1].TextureCoordinate = new Vector2(0.0f, 0.0f);
_vertices[2].Position = Vector3.Forward + Vector3.Right;
_vertices[2].TextureCoordinate = new Vector2(1.0f, 1.0f);
_vertices[3].Position = Vector3.Backward + Vector3.Right;
_vertices[3].TextureCoordinate = new Vector2(1.0f, 0.0f);
for (int i = 0; i < _vertices.Length; i++)
{
_vertices[i].Normal = Vector3.Up;
_vertices[i].Position *= _size;
_vertices[i].TextureCoordinate *= _size;
}
_indices[5] = 0; _indices[4] = 1; _indices[3] = 2;
_indices[2] = 2; _indices[1] = 1; _indices[0] = 3;
}
protected override void LoadContent()
{
_texture = this.Game.Content.Load<Texture2D>(_textureName);
_effect = new BasicEffect(this.GraphicsDevice);
_effect.EnableDefaultLighting();
_effect.PreferPerPixelLighting = true;
_effect.SpecularColor = new Vector3(0.1f, 0.1f, 0.1f);
_effect.World = Matrix.Identity;
_effect.TextureEnabled = true;
_effect.Texture = _texture;
base.LoadContent();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
public override void Draw(GameTime gameTime)
{
MyGame game = this.Game as MyGame;
GraphicsDevice.SamplerStates[0] = SamplerState.AnisotropicWrap;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
_effect.View = game.Camera.ViewMatrix;
_effect.Projection = game.Camera.ProjectionMatrix;
foreach (EffectPass pass in _effect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, _vertices, 0, 4, _indices, 0, 2);
}
base.Draw(gameTime);
}
}
From my main Game class's Initialize() method, I simply instantiate this object and pass in the GameObject, Size and the Texture name I want to use:
_floor = new QuadDrawer(this, 100.0f, "Textures/checker");
this.Components.Add(_floor);
Once the object is added to my Components collection, the Draw method of my QuadDrawer gets called and all should be good. Here is an image of what I am seeing. Note this should be solid gray with light color lines running in a grid pattern. The white artifacts appear to move as you move the camera around the surface, but disappear when you get close.
Here is picture showing the white artifacts:
This is a close up showing how it should look:
Here is another picture showing how bad it can get from a distance:
And here is what it should look like from a distance:
The picture is not the best, but you can see what I am talking about. When the camera moves, it gets really bad. I've seen this texture used in other places and it works fine. Any idea what it could be?
I'd be happy to provide more info if you need it.
Thanks,
-Scott
First of all you need to enable mipmaps for your texture. If it's just a stand-alone asset, you can select it in Solution Explorer, press F4 to get to properties, expand the "Content Processor" node and set "Generate Mipmaps" to true.
This article by Shawn Hargreaves explains why. Look at the difference between these two pictures from that article:
http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/2388.image_5F00_401AFB8B.png
http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/6518.image_5F00_1B896E07.png
(Looks a lot like your example images, doesn't it?)
Then, if you're going to be viewing at such oblique angles, you need to enable anisotropic filtering (Layoric explained how in his answer). This image from wikipedia illustrates what anisotropic filtering is for - note how it horizontally "un-blurs" the background (which was caused by the mipmaps).
(source: wikimedia.org)
It looks like an anistropic filtering problem. I notice you do have GraphicsDevice.SamplerStates[0] = SamplerState.AnisotropicWrap;
being used. I would suggest having a look at Shawn Hargreaves article on the topic and specifically the following lines.
device.SamplerStates[0].MinFilter = TextureFilter.Anisotropic;
device.SamplerStates[0].MagFilter = TextureFilter.Linear;
device.SamplerStates[0].MipFilter = TextureFilter.Linear;
device.SamplerStates[0].MaxAnisotropy = <n>;
Also,
Make sure the code is being set at the right time as a Effect.Begin
will reset these filter settings. Another code snippet to help.
// inside draw perform any other required draw code
// Call begin on the basic effect and on the pass to initialize BasicEffect's render settings
basicEffect.Begin();
basicEffect.CurrentTechnique.Passes[0].Begin();
// Set your desired filter settings
GraphicsDevice.SamplerStates[0].MinFilter = TextureFilter.Anisotropic;
GraphicsDevice.SamplerStates[0].MagFilter = TextureFilter.Anisotropic;
GraphicsDevice.SamplerStates[0].MipFilter = TextureFilter.Linear;
GraphicsDevice.SamplerStates[0].MaxAnisotropy = 16;
// Commit the changes to basic effect so it knows you made modifications
basicEffect.CommitChanges();
// Now perform you rendering to see Anisotropic filtering in effect
code snippet thanks to Jeromy Wash over at AppHub forums, another great place to get help from the masters of XNA :)
HTH
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With