【问题标题】:Strange "fuzz" When Rendering Texture on Plane in XNA 4.0在 XNA 4.0 中在平面上渲染纹理时出现奇怪的“绒毛”
【发布时间】:2011-09-20 21:38:05
【问题描述】:

我刚刚开始使用 XNA,我确信我错过了一些非常简单的东西。我有一个为地面绘制的四边形平面。在这架飞机上,我包裹了一个 2D 纹理。近距离看纹理看起来不错,但是当我四处移动相机时,我看到一堆白色伪影遍布整个地方。当我靠近它们时,它们消失了。我猜这是采样问题或类似问题,但我被卡住了。

首先,我创建了一个 QuadDrawer 类来为我绘制平面。它派生自 DrawableGameComponent。

四抽屉:

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);
    }

  }

从我的主游戏类的 Initialize() 方法中,我简单地实例化这个对象并传入我想要使用的游戏对象、大小和纹理名称:

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

一旦对象被添加到我的组件集合中,我的 QuadDrawer 的 Draw 方法就会被调用,一切都应该很好。这是我所看到的图像。请注意,这应该是纯灰色,浅色线条以网格图案运行。当您在表面上移动相机时,白色伪影似乎会移动,但当您靠近时会消失。

这是显示白色伪影的图片:

这是一个特写,展示了它的外观:

这是另一张照片,显示它从远处会变得多么糟糕:

从远处看应该是这样的:

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

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

谢谢,

-斯科特

【问题讨论】:

  • 尽管工件对您来说可能很明显,但我仍然无法看到您所描述的问题。您是否能够获得更好的示例图像并可能圈出所述工件的实例?谢谢。
  • 我添加了另一张显示效果更好的图片。所有的白线都是不应该存在的。在新图像中,您可以看到白色网格线在远离相机时如何开始旋转。我将上传另一张我期望它看起来像的照片。顺便说一句,我应用的任何纹理都会发生这种情况,而不仅仅是这个。谢谢!
  • @Layoric - 我在最底部添加了另一张图片,显示了从远处看场景应该是什么样子。任何帮助都非常感谢......

标签: xna


【解决方案1】:

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


(来源:wikimedia.org

【讨论】:

  • 这完全解决了我的问题。显然我还有很多东西要学。谢谢!
【解决方案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 将重置这些过滤器设置。另一个代码 sn -p 来帮忙。

// 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  

代码 sn-p 感谢Jeromy WashAppHub forums,另一个从 XNA 大师那里获得帮助的好地方 :)

HTH

【讨论】:

  • 感谢您的链接。我通读了博客文章并应用了不同类型的过滤器 - 没有一个解决了我的问题。即使移除 AnisotropicWrap 采样器,我仍然会得到伪像。我只是对这些东西还不够了解,所以无法找到它......
  • 更新了更多建议@Scott
  • 我相信 4.0 取消了 BasicEffect.Begin() 和 BasicEffect.CommitChanges()。但是,我确实应用了您上面建议的过滤器(使用 4.0 语法),但我仍然遇到同样的问题。我将从 QuadDrawer 类中提取所有代码并将其直接添加到我的 Game 类中,以查看该类是否存在问题。谢谢您的帮助。如果您有更多建议....我很想听听。
  • 是否在效果循环中分配了过滤器?
【解决方案3】:

各向异性过滤无济于事。您最好的解决方案(虽然不便宜)是使用Supersampling,这肯定会解决您的问题,但非常昂贵,或者使用Multisampling,这将根据您使用的正方形几何形状解决您的问题。

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

【讨论】:

  • 虽然各向异性过滤单独没有帮助(尽管如果使用得当会有所帮助),超级采样只会减少问题并不能解决问题。只有当这是几何图形时,多重采样才会有所帮助 - OP 正在使用纹理(而且它只会减少问题)。请参阅我的答案中链接的文章,以更深入地解释为什么这两种解决方案不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多