При текстурировании существует проблема. Текстура состоит из конечного числа точек, которые называются текселями. На текстурируемой поверхности текстурные координаты могут располагаться с различной плотностью, кроме того сама поверхность может находиться дальше или ближе к камере, что приводит к изменению видимых размеров. В результате текстура накладывается некорректно. Представьте, что текстура, шириной в 16 текселей должна отобразиться на участок бэкбуфера, шириной в 17 или 15 пикселей. В первом случае один из текселей должен будет отобразиться на два пикселя, во втором одному из текселей не хватает места. Когда размер изображения значительно превышает размер текстуры, последняя, как говорят «распадается на клетки».

Для наглядности сделаем проект. В модуль modMain предыдущего проекта добавьте все необходимое для создания вертексного буфера на четыре вертекса и одной текстуры. Вертекс должен содержать координаты XYZ и текстурные координаты. Создайте квадрат, размером 2 * 2 с центром в начале координат так, чтобы текстура десять раз укладывалась на поверхность квадрата:

код на языке vb
 
Private Sub InitGeometry()
Dim Vert(3) As vFormat
  vSize = Len(Vert(0))
  Set vBuf = d3dDevice.CreateVertexBuffer(4 * vSize, 0, vFlag, D3DPOOL_DEFAULT)
  Vert(0) = Vertex(-1, 0, -1, -5, -5)
  Vert(1) = Vertex(-1, 0, 1, -5, 5)
  Vert(2) = Vertex(1, 0, -1, 5, -5)
  Vert(3) = Vertex(1, 0, 1, 5, 5)
  D3DVertexBuffer8SetData vBuf, 0, 4 * vSize, 0, Vert(0)
End Sub
 
Камеру расположите низко  над квадратом, чтобы смотреть вдоль его поверхности:
 
  D3DXMatrixLookAtLH Mtrx, vec3(0, 0.03, -1), vec3(0, -0.39, 0), vec3(0, 1, 0)
  d3dDevice.SetTransform D3DTS_VIEW, Mtrx
 

Проинициализируйте остальные необходимые трансформации. Поместите в процедуру Render команду рисования квадрата, используя D3DPT_TRIANGLESTRIP для двух треугольников. Можно взять уже знакомую текстуру кирпичей.

Если при запуске программы вы видите черное поле, видимо вы забыли запретить использование света. Так же поместите перед основным циклом команду инициализации QueryPerformanceCounter – QFreqIni, а в сам цикл вращение трансформации мира:

код на языке vb
 
  D3DXMatrixRotationY Mtrx, QTime * 0.1
 

Теперь мы видим медленно вращающийся квадрат, в таком ракурсе прекрасно видно все виды искажения текстуры. Вдали текстура вообще превращается в мелкую рябь, вблизи распадается на клетки и, лишь на небольшом отдалении, где истинный размер текстуры близок к отображаемому, поле выглядит достаточно прилично. Для начала избавимся от самого неприятного искажения – ряби в удалении. Для этого применяется мип-мэппинг. Суть его состоит в том, что для отображения мелких или удаленных объектов, когда истинный размер текстуры превышает отображаемый, используется другая текстура более мелкого размера, полученная из первоначальной. При загрузке текстуры сразу создаются эти дополнительные изображения – их называют мип-уровнями. Линейные размеры каждого следующего мип-уровня вдвое меньше, чем у предыдущего. Последний мип-уровень, если мы явно не указали другое, имеет размер 1 * 1. Текстурой в Direct3D называется не отдельное изображение, а весь этот набор мип-уровней, при текстурировании Direct3D сам выбирает из них наиболее подходящий.

И самое интересное, что все эти мип-уровни уже созданы, нам лишь осталось разрешить их применение. Для этого в инициализацию добавим всего одну строку:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR
 

И вот рябь исчезла, а быстродействие даже возросло! Но текстура по-прежнему распадается на клетки, для борьбы с этим применяется другой метод – фильтрация. При выборке из текстуры берется усредненное значение текселей, соседних с точкой выборки. Способ вычисления может быть разный, но как правило применяется линейная фильтрация. Для ее включения достаточно одной строки:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR
 

Это мы включили фильтрацию на увеличение текстуры. Картинка вблизи стала лучше, но при удалении клетки все еще есть. Включим такую же фильтрацию и на уменьшение:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR
 

Теперь картинка почти идеальна, есть лишь один недостаток – при удалении текстура сильно «размазана» по поверхности. Это происходит оттого, что мы видим поверхность под острым углом, и при подборке такого мип-уровня, чтобы размер текселя «вдоль» направления взгляда примерно соответствовал размеру пикселя, размер текселя в направлении «поперек» значительно превышает размер пикселя, что сильно заметно на глаз. С этим тоже можно бороться, для этого существует так называемая анизотропная фильтрация. Заменим MINFILTER на такой:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_MINFILTER, D3DTEXF_ANISOTROPIC
 

И добавим строку, указывающую, насколько глубоко мы позволяем рассчитывать анизотропию:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_MAXANISOTROPY, 4
 

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