1 февраля 2010 в 20:40
Уроки Direct3D - 2.2. Мип-мэппинг, фильтрация текстур
При текстурировании существует проблема. Текстура состоит из конечного числа точек, которые называются текселями. На текстурируемой поверхности текстурные координаты могут располагаться с различной плотностью, кроме того сама поверхность может находиться дальше или ближе к камере, что приводит к изменению видимых размеров. В результате текстура накладывается некорректно. Представьте, что текстура, шириной в 16 текселей должна отобразиться на участок бэкбуфера, шириной в 17 или 15 пикселей. В первом случае один из текселей должен будет отобразиться на два пикселя, во втором одному из текселей не хватает места. Когда размер изображения значительно превышает размер текстуры, последняя, как говорят «распадается на клетки».
Для наглядности сделаем проект. В модуль modMain предыдущего проекта добавьте все необходимое для создания вертексного буфера на четыре вертекса и одной текстуры. Вертекс должен содержать координаты XYZ и текстурные координаты. Создайте квадрат, размером 2 * 2 с центром в начале координат так, чтобы текстура десять раз укладывалась на поверхность квадрата:
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, а в сам цикл вращение трансформации мира:
D3DXMatrixRotationY Mtrx, QTime * 0.1
Теперь мы видим медленно вращающийся квадрат, в таком ракурсе прекрасно видно все виды искажения текстуры. Вдали текстура вообще превращается в мелкую рябь, вблизи распадается на клетки и, лишь на небольшом отдалении, где истинный размер текстуры близок к отображаемому, поле выглядит достаточно прилично. Для начала избавимся от самого неприятного искажения – ряби в удалении. Для этого применяется мип-мэппинг. Суть его состоит в том, что для отображения мелких или удаленных объектов, когда истинный размер текстуры превышает отображаемый, используется другая текстура более мелкого размера, полученная из первоначальной. При загрузке текстуры сразу создаются эти дополнительные изображения – их называют мип-уровнями. Линейные размеры каждого следующего мип-уровня вдвое меньше, чем у предыдущего. Последний мип-уровень, если мы явно не указали другое, имеет размер 1 * 1. Текстурой в Direct3D называется не отдельное изображение, а весь этот набор мип-уровней, при текстурировании Direct3D сам выбирает из них наиболее подходящий.
И самое интересное, что все эти мип-уровни уже созданы, нам лишь осталось разрешить их применение. Для этого в инициализацию добавим всего одну строку:
d3dDevice.SetTextureStageState 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR
И вот рябь исчезла, а быстродействие даже возросло! Но текстура по-прежнему распадается на клетки, для борьбы с этим применяется другой метод – фильтрация. При выборке из текстуры берется усредненное значение текселей, соседних с точкой выборки. Способ вычисления может быть разный, но как правило применяется линейная фильтрация. Для ее включения достаточно одной строки:
d3dDevice.SetTextureStageState 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR
Это мы включили фильтрацию на увеличение текстуры. Картинка вблизи стала лучше, но при удалении клетки все еще есть. Включим такую же фильтрацию и на уменьшение:
d3dDevice.SetTextureStageState 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR
Теперь картинка почти идеальна, есть лишь один недостаток – при удалении текстура сильно «размазана» по поверхности. Это происходит оттого, что мы видим поверхность под острым углом, и при подборке такого мип-уровня, чтобы размер текселя «вдоль» направления взгляда примерно соответствовал размеру пикселя, размер текселя в направлении «поперек» значительно превышает размер пикселя, что сильно заметно на глаз. С этим тоже можно бороться, для этого существует так называемая анизотропная фильтрация. Заменим MINFILTER на такой:
d3dDevice.SetTextureStageState 0, D3DTSS_MINFILTER, D3DTEXF_ANISOTROPIC
И добавим строку, указывающую, насколько глубоко мы позволяем рассчитывать анизотропию:
d3dDevice.SetTextureStageState 0, D3DTSS_MAXANISOTROPY, 4
Это ограничение нужно потому, что анизотропная фильтрация – это очень тяжелые вычисления, сильно снижающие производительность, мы вынуждены искать баланс между качеством и скоростью. Кроме того различные видеоадаптеры поддерживают различный максимальный уровень анизотропии, и желательно не превышать этот уровень, хотя опыт показывает, что превышение этого уровня не приводит к сбою работы программы. Вполне возможно, что вы сейчас не увидели эффекта от включения анизотропной фильтрации, это означает, что ваш видеоадаптер ее не поддерживает.
комментарии отсутствуют
авторизуйтесь