logo search
ГОСы - ответы [2012]

2. Афинное

Этот метод текстурирования основан на приближении u, v линейными функциями. Итак, пусть u - линейная функция, u = k1*sx+k2*sy+k3. Можно посчитать k1, k2, k3 исходя из того, что хотя бы в вершинах грани u должно совпадать с точным значением - это даст нам три уравнения, из которых быстро и просто находятся эти коэффициенты, и потом считать u по этой формуле. Но это все равно медленно - два умножения на пиксел.

Будем рисовать грань по строкам - это общепринято, довольно просто, и не доводит до умопомешательства кэш-память процессора. Вершины грани заранее отсортируем по sy (например, A.sy <= B.sy <= C.sy). Для каждой строки можно посчитать начальное значение x, u (так же, как и для x, ведь u по любой прямой меняется тоже линейно), а также длину этой строки.

В нарисованном случае, например,

x_start = A.sx+(current_sy-A.sy)*(C.sx-A.sx)/(C.sy-A.sy),

u_start = A.u+(current_sy-A.sy)*(C.u-A.u)/(C.sy-A.sy),

x_end = A.sx+(current_sy-B.sy)*(B.sx-A.sx)/(B.sy-A.sy),

length = x_end - x_start.

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

delta_x_start = (C.sx-A.sx)/(C.sy-A.sy),

и аналогично высчитываемые приращения для x_end, u_start. Вот только надо аккуратно следить за тем, какая сторона правая, какая - левая, и на каком мы сейчас промежутке находимся - то ли AB, то ли BC, и соответственно изменять приращения. Впрочем, все это - уже обыкновенное рисование треугольника. В примерах просто сделано решение "в лоб" - проверяем, какой участок - AB или BC - пересекает текущая строка, считаем x/u/v на обоих концах, считаем длину строки и берем соответствующие левому концу (то есть меньшему x) значения u и v.

Так вот. Посчитали начало строки, длину строки, u в начале строки. Осталось заметить, что раз уж u = k1*sx+k2*sy+k3, то при переходе к следующему пикселу строки у нас u изменяется на k1 (так же известный как du/dsx). Это число и надо как-то посчитать. Например, так:

x_start = A.sx+(B.sy-A.sy)*(C.sx-A.sx)/(C.sy-A.sy),

x_end = B.sx,

u_start = A.u+(B.sy-A.sy)*(C.u-A.u)/(C.sy-A.sy),

u_end = B.u,

du_dsx = (u_start-u_end)/(x_start-x_end).

Теперь осталось только взять и нарисовать эту строку:

// ...

u = u_start;

v = v_start;

for (current_sx = x_start; \

current_sx <= x_end; current_sx++)

{

putpixel(current_sx, \

current_sy, texture[(int)v][(int)u]);

u += du_dsx;

v += dv_dsx;

}

// ...

Пройдясь по всем строкам грани - т.е. пробежавшись current_sy по значениям от A.sy до C.sy (вершины отсортированы!), получим текстурированную грань. Voila!

Билинейная фильтрация текстур.

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

При билинейной фильтрации цвет всего-навсего линейно интерполируется между узлами сетки замеров.

Используя линейную интерполяцию вычислим интенсивность в точке А:

Мипмэппинг.

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

Поэтому для удаления артефактов используется мипмэппинг. Для каждой текстуры заранее создается несколько ее копий уменьшенного размера (1/4, 1/8, и так далее), а далее при текстурировании используется либо сама текстура, либо подходящая уменьшенная копия.

Схема построения – берется базовая текстура и каждые ее четыре точки усредняются до одной.

При использовании мипмэппинга текстурирование осуществляется следующим образом:

Как создать уменьшенную в два раза копию текстуры? Здесь мы опишем три метода, два из них очевидны, третий позаимствован у Crystal Space. Методы расположены в порядке уменьшения скорости и увеличения качества уменьшенной текстуры.

Метод 1. Выкинуть все пикселы текстуры с нечетными координатами. Самый простой, самый быстрый, но дает не очень хорошо выглядящие результаты.

Метод 2. Оставить точки с четными координатами, в каждой точке усреднить значения цвета в этой точке и ее трех соседях (справа, снизу и справа-снизу).