Странный "пух" при рендеринге текстуры на плоскости в XNA 4.0 - PullRequest
5 голосов
/ 23 июня 2011

Я только начинаю работать с 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);
    }

  }

Из метода Initialize () моего основного класса Game я просто создаю экземпляр этого объекта и передаю GameObject, Size и имя текстуры, которую я хочу использовать:

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

Как только объект добавлен в мою коллекцию компонентов, вызывается метод Draw моего QuadDrawer, и все должно быть хорошо. Вот изображение того, что я вижу. Обратите внимание, что это должен быть сплошной серый с светлыми цветными линиями, идущими в виде сетки. Белые артефакты кажутся движущимися при перемещении камеры по поверхности, но исчезают, когда вы приближаетесь.

Вот изображение, показывающее белые артефакты:

Fuzzy

Это крупный план, показывающий, как это должно выглядеть: Close Up

Вот еще одна картинка, показывающая, как плохо это может быть на расстоянии: Better view of the problem

А вот как это должно выглядеть на расстоянии: enter image description here

Картинка не самая лучшая, но вы можете видеть, о чем я говорю. Когда камера движется, становится очень плохо. Я видел эту текстуру, используемую в других местах, и она отлично работает. Есть идеи, что бы это могло быть?

Я был бы рад предоставить больше информации, если вам это нужно.

Спасибо

-Скотт

Ответы [ 3 ]

6 голосов
/ 23 июня 2011

Прежде всего вам нужно включить мипмапы для вашей текстуры . Если это просто автономный ресурс, вы можете выбрать его в обозревателе решений, нажать клавишу F4, чтобы перейти к свойствам, развернуть узел «Обработчик содержимого» и установить для параметра «Сгенерировать Mipmaps» значение true.

Эта статья Шона Харгривза объясняет, почему . Посмотрите на разницу между этими двумя фотографиями из этой статьи:

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

(очень похоже на ваши примеры изображений, не так ли?)

Тогда, если вы собираетесь смотреть под такими наклонными углами, вам нужно включить анизотропную фильтрацию (Лайорик объяснил, как в своем ответе). Это изображение из википедии иллюстрирует, для чего нужна анизотропная фильтрация - обратите внимание, как она горизонтально «размывает» фон (который был вызван мипмапами).

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

2 голосов
/ 23 июня 2011

Похоже на проблему с антистропической фильтрацией. Я заметил, что у вас есть GraphicsDevice.SamplerStates[0] = SamplerState.AnisotropicWrap; используется. Я бы посоветовал взглянуть на статью Шона Харгривза на тему и особенно следующие строки.

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 Wash на форумах AppHub , еще одно отличное место, чтобы получить помощь от мастеров XNA:)

НТН

1 голос
/ 23 июня 2011

Анизотропная фильтрация не поможет. Лучшим решением (хотя и не дешевым) было бы использовать Supersampling , который определенно решит вашу проблему, но довольно дорогой, или Multisampling , который решит вашу проблему в зависимости от геометрия квадратов, которые вы используете.

По моему личному опыту, мультисэмплинг - это то, что вы обычно можете оставить в любом случае, так как современные видеокарты действительно имеют возможность рендерить его с небольшими затратами для вас, если только вы не создаете очень тяжелый графический процессор. приложения \ игры. Кроме того, вопрос о суперсэмплинге не исключен, хотя его использование довольно дорого по той же причине, что и выше, но проверьте, чтобы убедиться, что у вас не будет большого снижения производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...