Практическое использование расширений: анизотропная фильтрация в OpenGL
Автор: Антон В. Звягинцев
Кратко о фильтрации текстур - для чего она существует? Вопреки сложившемуся мнению о том, что фильтрация предназначена только для улучшения качества изображения - скажу так - это лишь окончательный результат который складывается не только за счет самой фильтрации. Хотя подобное замечание наиболее справедливо для билинейной фильтрации, но об этом несколько позже. Вернемся к OpenGL. При формировании образа текстуры в памяти программист задает два уровня фильтрации текстур - говоря более простым и понятным языком это фильтры максимальной и минимальной дистанции, какая из функций фильтрации будет применяться для формирования образа текстуры при сильном удалении или при достаточном приближении текстурного изображения. Ты, наверное, уже смотрел примеры с текстурированием - если нет - советую взглянуть.
Рассмотрим функцию при "достаточном приближении": когда один тексель(один элемент или пиксель если угодно для (лучшего понимания) текстуры) становится достаточно большим и покрывает несколько пикселей на экране для устранения ступенчатости мы используем фильтрацию. Замечу, что подобное решение не достаточно эффективно - поскольку фильтрация несколько "смазывает" изображение. Для придания более реалистичного вида необходимо увеличивать разрешение самой текстуры. При этом для каждой аппаратной реализации максимальный размер текстуры свой. Получить его можно, например, с помощью следующего кода (на заметку - текстуры должны иметь размеры (ширина, длина) кратные степени двойки.):
GLint nTexSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE,&nTexSize);
Поговорим о минимизации текстурного изображения. Тут конечно нужно упомянуть о мипмаппинге - дело в том, что при достаточном удалении текстуры, могут возникнуть нежелательные искажения и артефакты (так называемый z- или depth-aliasing) в изображении. Для того чтобы этого избежать, используется генерация и сохранение на стадии загрузки уменьшенных копий текстуры для использования на различных дистанциях при удалении. Для улучшения качества полученных изображений также используется фильтрация.
Хочу заметить, что в при использовании совместно с мипмаппингом билинейной фильтрации (впрочем и без нее) возникает эффект mip-banding'а - визуально заметный переход от одного мипмап уровня к другому. Для борьбы с этим используется более требовательная ко времени исполнения трилинейная фильтрация.
Что же тогда такое анизотропная фильтрация? Дело в том, что билинейная и трилинейная фильтрация не совсем корректно рассчитывает цвет текселя - а точнее рассчитывает его неверно (отталкиваясь от законов нашего зрения) для наклонных плоскостей. Использование анизотропной фильтрации дополняет текущие режимы фильтрации, позволяя регулировать угол анизотропии. Чем больше угол - тем выше качество и реалистичность самой фильтрации, тем выше, в то же время, затраты на обсчет. Не стоит ожидать сказочного улучшения качества результата - скорее наоборот - на больших углах мы получим большую "смазанность" изображения - тем не менее результирующее изображение является более реалистичным.
В OpenGL анизотропная фильтрация реализуется расширением GL_EXT_texture_filter_anisotropic. Возможно со временем появятся другие аппаратно-специфичные варианты анизотропной фильтрации - однако я ориентировался именно на это расширение.
Вот ПРИМЕР. Для изменения режима фильтрации левой и правой текстуры используй клавиши '1' и '2'. Углы расположения полигонов меняются клавишами курсора. Приближение и удаление полигонов осуществляется "серыми" плюсом и минусом. В полноэкранном режиме завершить работу приложения можно клавишами Alt+F4. Файлы mainaux.cpp и mainaux.h содержат функцию и константы для универсальной функции поиска вхождения в строку и могут использоваться не только для обработки строки расширения в OpenGL. Поддержка расширения определяется на этапе инициализации:
// проверим вхождение... if (!IsInString( pszExtStr,"GL_EXT_texture_filter_anisotropic")) { // анизотропная фильтрация не поддерживается MessageBox( NULL,"\nAnisotropic texture filtering not found !", "Skipping filtering...",MB_OK | MB_ICONINFORMATION); LogMsg( "GL_EXT_texture_filter_anisotropic not found !\n"); g_nMaxTex--; } else { // есть поддержка анизотропной фильтрации // получим максимально доступный угол анизотропии... glGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&g_nMaxAnisotropy); LogMsg( "MAX anisotropy: %d\n",g_nMaxAnisotropy); }
В случае отсутствия анизотропной фильтрации, пример так же будет работоспособен, однако будут доступны всего три режима - отсутствие фильтрации, билинейная и трилинейная. Если анизотропная фильтрация доступна - то в примере будет доступен еще один уровень фильтрации - с достаточно высоким углом анизотропии для трилинейной фильтрации:
// если есть поддержка анизотропной фильтрации определенная ранее if (g_nMaxTex == ( MAX_TEXTURES-1)) { LogMsg( "Using anisotropy level: %f\n",( float)( g_nMaxAnisotropy-0.1)); // используем четвертую текстуру текстуру(отсчет с нуля)... glBindTexture( GL_TEXTURE_2D,texture[3]); // устанавливаем угол анизотропии... glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT, g_nMaxAnisotropy-0.1); // трилинейная фильтрация... glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); // мипмап уровни... gluBuild2DMipmaps( GL_TEXTURE_2D,3,pTexture->sizeX,pTexture->sizeY, GL_RGB,GL_UNSIGNED_BYTE,pTexture->data); }
Расширение анизотропной фильтрации не добавляет новых функций - лишь определения и константы.
#расширения OpenGL, #OpenGL, #фильтрация
16 февраля 2002