在XNA 4.0中在平面上渲染纹理时奇怪的“模糊”

时间:2011-06-23 03:42:05

标签: xna

我刚刚开始使用XNA,我确信我错过了很简单的东西。我有一架四轮飞机,我画的是地面。在这个平面上,我包裹了一个2D纹理。纹理看起来很近,但是当我移动相机时,我看到整个地方都有一堆白色的文物。当我靠近他们时,他们消失了。我猜这是一个抽样问题或类似的东西,但我被卡住了。

首先,我创建了一个QuadDrawer类来为我绘制平面。它来自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);
    }

  }

从我的主Game类的Initialize()方法中,我只是实例化这个对象并传入我想要使用的GameObject,Size和Texture名称:

_floor = new QuadDrawer(this, 100.0f, "Textures/checker");
  this.Components.Add(_floor);

一旦将对象添加到我的Components集合中,我的QuadDrawer的Draw方法就会被调用,所有这些都应该是好的。这是我所看到的图像。请注意,这应该是纯灰色,浅色线以网格图案运行。当您在相机周围移动相机时,白色瑕疵似乎会移动,但当您靠近时会消失。

这是显示白色文物的图片:

Fuzzy

这是近距离显示它应该如何显示: Close Up

这是另一张图片,展示了远距离有多糟糕: Better view of the problem

这是从远处看它应该是什么样的: enter image description here

图片不是最好的,但你可以看到我在说什么。当相机移动时,它变得非常糟糕。我已经看到在其他地方使用这种纹理,它工作正常。知道它可能是什么吗?

如果您需要,我很乐意提供更多信息。

谢谢,

-Scott

3 个答案:

答案 0 :(得分:6)

首先,您需要为纹理启用mipmap 。如果它只是一个独立的资产,您可以在解决方案资源管理器中选择它,按F4进入属性,展开“内容处理器”节点并将“生成Mipmap”设置为true。

This article by Shawn Hargreaves explains why。看看这篇文章中这两张图片之间的区别:

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

(看起来很像你的示例图片,不是吗?)

然后,如果你要以这样的倾斜角度观看,你需要启用各向异性过滤(Layoric在他的回答中解释了如何)。来自wikipedia的图像说明了各向异性过滤的用途 - 注意它是如何水平地“钝化”背景(由mipmap引起的)。

http://upload.wikimedia.org/wikipedia/en/c/c0/Anisotropic_compare.png

答案 1 :(得分:2)

它看起来像是一个各向异性过滤问题。我注意到你确实使用了GraphicsDevice.SamplerStates[0] = SamplerState.AnisotropicWrap;。我建议你看看Shawn Hargreaves article on the topic,特别是以下几行。

device.SamplerStates[0].MinFilter = TextureFilter.Anisotropic;
device.SamplerStates[0].MagFilter = TextureFilter.Linear;
device.SamplerStates[0].MipFilter = TextureFilter.Linear;
device.SamplerStates[0].MaxAnisotropy = <n>;

此外,

确保在正确的时间设置代码,因为Effect.Begin将重置这些过滤器设置。另一个帮助的代码片段。

// 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  
感谢Jeromy WashAppHub forums处的

代码段,这是另一个获得XNA大师帮助的好地方:)

HTH

答案 2 :(得分:1)

各向异性过滤无济于事。你最好的解决方案(虽然不便宜)会使用Supersampling,这将解决你的问题,但是相当昂贵,或Multisampling,这将解决你的问题取决于你的方块几何正在使用。

根据我的个人经验,多重采样在任何情况下都可以保留,因为现代显卡确实能够为您提供更多成本,除非您构建的GPU非常重应用程序\游戏。此外,超级采样并非完全不可能,即使它使用起来非常昂贵,出于与上述相同的原因,但测试看你不会有很大的性能损失。