Графические устройства

         

Наложение рисунков и спецэффекты

Видеорежимы direct color позволяют решать задачи, постановка которых при работе в режимах PPG была просто невозможна. К ним относится, например, получение различного рода спецэффектов, за счет манипуляций с цветами отдельных точек изображения. В данном разделе описаны способы получения некоторых спецэффектов, широко применяемых в трехмерной графике (ЗD-графика).

При реализации спецэффектов, как правило, выполняется большой объем арифметических операций, что существенно замедляет процесс получения результата. Поэтому в современной графике арифметические операции либо выполняются с помощью новых команд ммх, появившихся у процессоров Pentium, либо используются акселераторы, выполняющие соответствующие вычисления на аппаратном уровне (см. раздел). Основные графические пакеты поддерживают как программный, так и аппаратный способы вычислений, направленных на достижение нужного спецэффекта.

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



Спрайты (Sprites)

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

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

Уточним, о каком фоне идет речь. Образ рисунка всегда занимает прямоугольную область, в которой основное изображение может быть окружено фоном, не имеющим прямого отношения к рисунку. При описании работы с курсором (см. главу 6) говорилось, что одним из способов удаления ненужного фона является маскировка. Например, в файлах, содержащих образы рисунков курсоров и пиктограмм, обязательно находится маска, указывающая, какую часть образа рисунка не надо показывать на экране.

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

Фильтрация цвета (Chroma Keying)

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

В отличие от построения спрайта при фильтрации решается более общая задача — исключение однородного фона независимо от его цвета. В обоих случаях исключаемый цвет не должен использоваться в, основной части рисунка, в противном случае в ней появятся точки с цветом точек подложки, на которую накладывается рисунок.
Для того чтобы цвет с заданным кодом оказался прозрачным, его надо просто не записывать в видеопамять. Это и делает приведенная в примере 7.29 подпрограмма, выполняющая построение строки формата bgr с фильтрацией цвета. Она отфильтровывает цвет, код которого указан в переменной bkgrcod. Эта 32-разрядная переменная должна быть описана в разделе данных задачи. Рабочий видеорежим True Color.

Перед вызовом входные параметры задаются так же, как для всех описанных подпрограмм построения строки (drawline). В регистрах fs:si указывается адрес начала строки в оперативной памяти, в di — адрес ее начала в видеопамяти, в сх — количество точек в строке. Как обычно, должно быть установлено окно видеопамяти, которому принадлежит адрес точки начала строки, а в регистре es должен находиться код видеосегмента.

Пример 7.29. Фильтрация цвета строки формата bgr, режим True Color

sprline: lods word ptr fs: [si] ; ax = коды синего и зеленого цвета
push ax ; сохраняем ах в стеке
lods byte ptr fs:[si] ; al = код красного цвета
xor ah, ah ; очищаем резервный байт
shl eax, 16 ; сдвиг ах в старшую половину еах
pop ax ; восстанавливаем ах из стека
cmp eax, bkgrcod это фильтруемый цвет ?
je Ысо! -> да, обходим запись нового кода
mov es:[di], eax нет, записываем код в видеопамять
blcol: add di, bytppnt корректируем адрес видеопамяти
jnz @F -> адрес в пределах окна
call NxtWin установка следующего окна
@@: loop splint управление повторами цикла
ret возврат из подпрограммы

В 1-м варианте примера 7.26 была приведена подпрограмма, выполняющая простое построение строки формата bgr. В отличие от нее, в данном случае код очередной точки строки не копируется в видеопамять, а помещается в регистр еах. Затем он сравнивается с кодом, указанным в переменной bkgrcod, и в случае совпадения не записывается в видеопамять, поэтому цвет соответствующей точки экрана не изменяется.

Описанную подпрограмму можно использовать при построении рисунков, хранящихся в форматах BMP (не упакованный) и PCX (упакованный). Для этого в примерах 7.25 и 7.28 достаточно просто заменить call drawiine на call spriine. Замена возможна потому, что в обоих случаях используется одна и та же подпрограмма drawiine.

Переменная bkgrcod должна быть описана в разделе данных задачи как двойное слово, содержащее код исключаемого цвета. Вопрос в том, как определить код прозрачного цвета — не задавать же его вручную. Если основное изображение окружает однородный фон, то можно предположить, что первая точка первой или последней строки рисунка имеет цвет фона. В таком случае, перед началом построения надо прочитать (программно) код первой точки образа рисунка и присвоить его значение переменной bkgrcod. Если указанное условие не выполнено, то можно с помощью графического редактора присвоить нужной точке цвет фона. В любом случае выбранный рисунок лучше предварительно просмотреть с помощью графического редактора, поскольку точки, которые воспринимаются на глаз как одноцветные, фактически могут быть разноцветными и вам придется редактировать цвет фона.

Смешение цветов (alpha blending)

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

Z[i,j] = X[i,j] * alpha + Y[i,j] * (1 - alpha)

Здесь x и Y — смешиваемые изображения, a z — результат смешения. Формула применяется к каждому базовому цвету каждой точки смешиваемых изображений, поэтому i изменяется от 1 до N (N — количество точек в рисунке), a j — от 1 до 3 (по количеству базовых цветов). Допустимые значения alpha находятся в пределах от 0 до 1.

Очевидно, ЧТО при alpha = 0 Z[i,j] = Y[i,j], а при alpha = 1 Z[i,j] : = x[i, j], т. е. при граничных значениях alpha в результате смешения получается одно из двух изображений. В остальных случаях результат смешения будет зависеть как от значения alpha, так и от конкретных цветов точек. Вспомните табл. 7.6, при пропорциональном изменении значений базовых цветов точки одновременно изменяются ее яркость и цвет.

Предположим, что коды двух смешиваемых точек в формате rgb равны FF, 0, 0 и 0, FF, 0. т. е. одна из них окрашена в ярко-красный цвет, а другая — в ярко-зеленый. В зависимости от значения alpha цвет результата смешения будет изменяться от красного до зеленого, а его яркость сначала будет уменьшаться до 50%, а затем начнет возрастать до максимального значения. При aipha=0,5 получится чисто желтый цвет, но его яркость составит 50% от максимальной.

Особенности программной реализации

Прежде всего, давайте раскроем скобки в приведенной выше формуле и сгруппируем величины, умножаемые на alpha. В результате получится следующий вариант формулы:

Z[i,j] = (X[i,j3,- Y[i,j]} * alpha + Y[i,j]

Преимущество этого варианта записи в том, что на каждом шаге вычислений вместо двух умножений выполняется одно.

Теперь о значениях alpha. Величины x[i,j], Y[i, j] и z[i, j] являются кодами базовых цветов точек изображений, поэтому их значения заключены в пределах от 0 до 255 (или от о до OFFh). Умножать такие величины на дроби неудобно, поэтому при программной реализации значения alpha задаются в виде целых чисел, изменяющихся в пределах от 0 до 255, а результат умножения делится на 256. Фактически деление на 256 не требуется, достаточно просто использовать старший байт произведения. При таком представлении граничными значениями aipha будут 0 и 255/256 = 0,9961, но с учетом реальной точности вычислений отличие верхнего предела от 1 не имеет существенного значения.

Давайте упростим задачу и рассмотрим частный случай, когда z = у и изображение z находится на экране, а коды его точек, соответственно, в видеопамяти. Это позволит нам рассмотреть простой вариант подпрограммы, которая вместо смешения изображений, хранящихся в двух файлах, выполняет наложение изображения, хранящегося в файле, на изображение, находящееся на экране. Текст подпрограммы, выполняющей наложение строки формата bgr на строку, расположенную в видеопамяти, приведен в примере 7.30, предполагается, что установлен видеорежим True Color.

Входные параметры задаются так же, как для всех описанных подпрограмм построения строки (drawline):

  • в регистрах fs.-si указывается адрес начала строки в оперативной памяти;
  • в регистре di — адрес ее начата в видеопамяти;
  • в регистре сх — количество точек в строке.

Как обычно, должно быть установлено окно видеопамяти, а регистр es должен содержать код видеосегмента.

Значение alpha может изменяться от 0 до 255, оно указывается в одноименной переменной, имеющей размер слова, ее надо описать в разделе данных задачи, присвоив конкретное значение, или предусмотреть возможность ввода этого значения перед наложением рисунка.

Пример 7.30. Альфа-наложение строки формата Ьдг, режим True Color

alphamix: PushReg <bx,dx>; сохранение регистров bx, dx
mixpnt: push ex ; сохранение счетчика повторов
mov c.x, 03 ; для обработки трех базовых цветов
mixcol: mov Ы, es:[di] ; Ы = код базового цвета Y[i,j]
iods byte ptr fs:[si] ; al = код базового цвета X[i,j]
xor ah, ah преобразуем байт в слово
xor bh, bh преобразуем байт в слово
sub ax, bx X[i,j] = X[i,j]-Y[i,j]
imul alpha ax = (X [i, j ] -Y[i, j ]) * alpha; dx = 0
xchg al, ah al = ax/256
add al, Ы Z[i,j] = (X[i,j]-Y[i,j])*alpha/256+Y[i,j]
stosb запись Z[i,j] в видеопамять
loop mixcol управление повторами цикла
inc di пропуск резервного байта
jne @F -> адрес в пределах текущего окна
call NxtWin установка нового окна
@@: pop ex восстановление счетчика повторов
loop mixpnt управление повторами цикла
PopReg <dx,bx> восстановление регистров dx, bx
ret возврат из подпрограммы

Подпрограмму alphamix можно использовать при построении рисунков, хранящихся в форматах BMP (не упакованный) и PCX (упакованный). Для этого в примерах 7.25 и 7.28 достаточно просто заменить call drawiine на call alphamix. Замена возможна потому, что в обоих случаях используется одна и та же подпрограмма drawiine.

Основные действия в примере 7.30 выполняются во внутреннем цикле, имеющем метку mixcol, рассмотрим их более подробно. Две первые команды считывают в регистры ы и al коды смешиваемых базовых цветов. Перед вычитанием значения байты преобразуются в слова. Специальная команда CBW (convert byte to word) в данном случае не применима, т. к. она интерпретирует коды со значениями больше чем 127, как отрицательные числа. В примере 7.30 просто очищаются старшие байты регистров ах и bx, после чего выполняется вычитание (ах = ах - bx). Результат вычитания может быть как положительным, так и отрицательным числом, поэтому для его
умножения на значение переменной alpha используется специальная команда imui. В отличие от команды mul она интерпретирует операнды как числа со знаком.

Произведение находится в регистрах dx:ax, но поскольку модули значений операндов не превышают 255, dx будет просто очищен, а в ах будет находиться младшая часть произведения. Вместо деления результата на 256 выполняется перестановка байтов регистра ах (с таким же успехом его содержимое можно было сдвинуть на 8 разрядов вправо). Остается сложить содержимое регистров ai и ы и записать результат в видеопамять. Последняя команда loop mixcoi трижды повторяет выполнение цикла.
После выхода из внутреннего цикла адрес видеопамяти увеличивается на 1 для пропуска резервного байта в коде точки. Как обычно, проверяется принадлежность адреса установленному окну видеопамяти и, в случае необходимости, устанавливается следующее окно. Затем в регистр сх из стека выталкивается содержимое счетчика повторов, и команда loop mixpnt управляет повторами внешнего цикла.

Очевидно, что наложение рисунка будет выполняться дольше, чем его простое построение. Более точное представление о степени замедления дают результаты следующего эксперимента. Один и тот же рисунок формата BMP, размером 640x480 точек просто строился, или накладывался на изображение, уже имеющееся на экране. В обоих случаях основная подпрограмма соответствовала примеру 7.25. Компьютер был укомплектован процессором Pentium с тактовой частотой 100 МГц. Время, затрачиваемое на наложение, увеличилось, по сравнению со временем построения, примерно на 1,1 сек. Это свидетельствует о том, что альфа-наложение можно выполнять с помощью обычных команд, но лучше использовать операции ммх или функции акселератора.

Альфа-смешение — это один из популярных приемов используемых в 3D-графике для получения различных эффектов. Рассмотрим некоторые из них.

Наплыв изображения (Image Dissolve)

Если результат выводить на экран и многократно повторять смешение, увеличивая при каждом повторе значение alpha, то на фоне постепенно исчезающего исходного изображения будет все более четко проступать новое изображение. Или наоборот, если значение alpha постепенно уменьшается от 1 до 0, то одно из двух изображений будет исчезать (растворяться в другом изображении). Такие трюки довольно часто используются в оформительских целях не только в компьютерных приложениях, но и на телевидении.

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

Прежде всего, подпрограмма примера 7.30 должна выполнять смешение, а не наложение строк. Для этого первая команда цикла mixcoi (mov bl, es: [di]) заменяется на mov bl, gs: [si]. Однако такая замена возможна при условии, что смешиваемые изображения имеют одинаковый формат. В противном случае при выборке кодов точек нельзя будет использовать один и тот же индексный регистр gs.

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

Рисунок, подлежащий наложению, надо прочитать в сегмент оперативной памяти, указанный в регистре fs. Для создания эффекта наплыва организуется цикл последовательного смешения расположенных в памяти изображений с увеличением значения alpha от 0 до 255 с выбранным шагом. Для удаления построенного изображения можно использовать тот же цикл, предварительно обменяв содержимое сегментных регистров gs и fs.

Для упрощения задачи советуем использовать "наплывающий" рисунок формата BMP, но предварительно перевернуть в нем строки так, чтобы они располагались в естественном порядке, и исключить дополнительные байты, которые могут быть в конце строк. Специальная программа, выполняющая такое преобразование, может оказаться полезной во многих случаях, поэтому имеет смысл потратить время и усилия на ее составление.

Прозрачная поверхность (Transparent Surface)

В этом случае создается зрительный эффект, при котором наблюдаемый объект как бы отгорожен от наблюдателя бесцветной прозрачной перегородкой, например стеклом. Для получения эффекта производится наложение однородного фона белого цвета на наблюдаемый объект. При этом степень прозрачности перегородки тем больше, чем меньше значение alpha, если alpha = 1, то перегородка превратится в прямоугольник белого цвета.

Однородный фон белого цвета, заполняющий прямоугольник нужного размера, можно подготовить с помощью любого графического редактора. Для наложения строки просто используется подпрограмма примера 7.30. Если фон перегородки однородный, что вовсе не обязательно, то рисунок фона не нужен, можно составить подпрограмму, выполняющую наложение строки заданного цвета. Ее текст приведен в примере 7.31.

Пример 7.31. Наложение прозрачной строки заданного цвета

Trnspl: PushReg <bx, dx> сохранение регистров bx, dx
Tline: push ex сохранение счетчика повторов
mov ex, 03 для обработки 3-х базовых цветов
lea si, Trcol si = адрес переменной Trcol
Tpnt: lodsb al = налагаемый базовый цвет (C[jl)
mov Ы, es:[di] bl = базовый цвет изображения (Y[i,j]'
xor ah, ah преобразуем байт в слово
xor bh, bh преобразуем байт в слово
sub ах, bx ax = C[j] - Y[i,j]
imul alpha ax = ax * alpha; dx = 0
xchg al, ah al = ax/256
add al, bl al = al + Y[i,j]
stosb запись результата в видеопамять
loop Tpnt трехкратное повторение цикла
inc di пропуск резервного байта
jne @F -> адрес в пределах текущего окна
call NxtWin установка следующего окна
@@: pop ex восстановление счетчика повторов
loop Tline управление циклом преобразования строки
PopReg <dx, bx> восстановление регистров dx, bx
ret возврат из подпрограммы

Все отличия подпрограммы примера 7.31 от примера 7.30 связаны с тем, что код прозрачного цвета выбирается не из файла, а из переменной Trcoi. При каждом повторении внешнего цикла адрес этой переменной помещается в регистр si для использования во внутреннем цикле. Trcoi должна быть описана в разделе данных задачи, ее размер 3 байта, в которых находятся компоненты налагаемого цвета (коды базовых цветов). Для совместимости с видеорежимом True Color их надо расположить в порядке bgr.

Следует заметить, что при работе только с белым цветом переменная Trcci не нужна, поскольку в этом случае коды трех базовых цветов совпадают и равны OFFh. Мы ввели переменную Trcoi специально для возможности задания любого прозрачного цвета.

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

Формулу для выполнения альфа-наложения тумана однородного цвета можно записать в следующем виде:

X[i,j] = Fc[j] * alpha[i] + X[i,j] * (1 - alpha[i])

Здесь FC — цвет тумана, ах— цвет изображения, затягиваемого туманом. Запись Fctj] означает, что каждая точка тумана окрашена в один и тот же цвет, это позволяет избавиться от файла, содержащего изображение тумана. В отличие от ранее приведенных формул, в данном случае у коэффициента alpha появился индекс 1, т. е. значений alpha должно быть столько, сколько точек в основном рисунке (который затуманивается). О том, как подготовить массив значений alpha, мы поговорим после.описания программной реализации формулы.

Если у значений alpha убрать индекс i, то получится формула для наложения прозрачного цвета, которая была реализована в подпрограмме примера 7.31. Следовательно, надо несколько изменить внешний цикл этой подпрограммы, добавив в него выборку значения alpha для каждой точки изображения, что и сделано в примере 7.32. Предполагается, что затягиваемое туманом изображение находится на экране.
Перед вызовом подпрограммы в регистре di указывается адрес начала строки рисунка в видеопамяти, а в fs:si — адрес начала строки коэффициентов alpha в буфере обмена. В сх задается количество точек в строке.

Пример 7.32. Наложение строки тумана заданного цвета

Foglin: PushReg <bx, dx> ; сохранение регистров bx, dx
f og_l : push ex ; сохранение счетчика повторов
lods byte ptr f s : [si] ; al = alpha [i]
mov byte ptr falpha, al ; falpha = al запоминаем alpha [i]
push si сохраняем содержимое si
lea si, fogcol si = адрес переменной fogcol
mov ex, 03 для обработки трех базовых цветов
f og_2 : lodsb al = базовый цвет тумана (F[j])
mov Ы, es: [di] Ы = базовый цвет точки (Y[i,j]>
xor ah, ah преобразуем байт в слово
xor bh, bh преобразуем байт в слово
sub ax, bx ах = F[j] — Y[i,j]
imul falpha ах = ах * alpha [i]; dx = 0
xchg al, ah al = ax/256
add al, Ы al = al + Y[i,j]
stosb сохраняем результат в видеопамяти
loop fog 2 трехкратное повторение цикла
inc di пропуск резервного байта
jne @F -> адрес в пределах текущего окна
call NxtWin установка следующего окна
@@: Pop si восстановление адреса в si
pop ex восстановление счетчика повторов
loop fog 1 управление повторами цикла
PopReg <dx, bx> восстановление регистров dx, bx
ret возврат из подпрограммы

Значения alpha изменяются от 0 до 255, для сокращения размера файла их лучше хранить в виде байтов, но при умножении коэффициент alpha должен иметь размер слова. Поэтому в примере 7.32 введена специальная переменная falpha, имеющая размер слова. Ее надо описать в разделе данных задачи, присвоив нулевое значение.
Во внешнем цикле примера 7.32, по сравнению с примером 7.31, появились три новые команды. Первая из них считывает очередное значение alpha [i] в регистр al (и увеличивает содержимое si на 1). Вторая копирует содержимое ai в младший байт переменной faipha, а третья сохраняет в стеке адрес, находящийся в регистре si. Таким образом, в результате выполнения этих трех команд получено очередное значение alpha и освобожден регистр si. Теперь в него можно записать адрес переменной, содержащей цвет тумана, для использования во внутреннем цикле, это же делалось и в примере 7.31.

После выхода из внутреннего цикла восстанавливается находившийся в si адрес, и при повторе внешнего цикла будет выбрано следующее значение alpha из буфера обмена.
Для использования описанной подпрограммы надо подготовить файл, содержащий значения коэффициентов alpha. От их расположения в файле зависит способ построения рисунка, поэтому первыми должны располагаться коэффициенты для его верхней, а последними — для нижней строки. В таком случае построение будет производиться в направлении слева направо и сверху вниз, т. е. по наиболее простой схеме. Способ чтения файла в буфер обмена зависит от количества значений alpha. Например, для затягивания туманом всего изображения при разрешении 640x480 точек файл будет содержать 307 200 байтов и его придется считывать по частям.

Следовательно, перед построением риcунка надо вычислить размер считываемой порции данных (количество строк и байтов в порции). Мы это делали неоднократно.
Вычисление значений alpha. Вам понадобится специальная программа, формирующая файл, содержащий значения alpha для каждой точки затуманиваемого изображения. Значения alpha зависят от расстояния (r[i]) между текущей точкой (i) и точкой принятой за начало отсчета (точкой наблюдения). В линейном двухмерном дискретном пространстве это расстояние вычисляется как квадратный корень из суммы квадратов приращений значений координат:

r[i] = sqrt { (x[i] - х[0])**2 + (y[i] - у[0])**2}

Здесь ** обозначают степень, sqrt — квадратный корень, х[0] и у [0] — значения координат в точке наблюдения, x[i] и y[i] — текущие значения координат.

В общем случае значения alpha описываются некоторой функцией (F), зависящей от расстояния, т.е. alpha [i] = F(r[i]). Независимо от природы функции F значения alpha равны нулю в точке наблюдения и увеличиваются по мере удаления от точки наблюдения, не превышая при этом значение 255 (которое принято за 1).

Советуем вам начать с простого случая, когда F является нормированной чинейной функцией, у которой за норму принято значение г в максимально /деленной точке, т. е. alpha [i] = <r[i] / max) *255. В. результате получится }>айл, содержащий значения коэффициентов для тумана, плотность которого возрастает пропорционально расстоянию. Эксперименты с файлом позволят вам оценить степень соответствия линейной модели ожидаемым результатам.

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

alpha[i] = exp (-k*r[i]> или alpha[i] = exp {-(k*r[i])**2)

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

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

Общий случай смешения

Затягивание туманом является частным случаем смешения двух изображений с переменными значениями alpha. Рассмотрим простой пример. Предположим, что у вас есть рисунок сада и рисунок окна (или части комнаты с окном) и вы хотите изобразить на экране окно, выходящее в сад, причем часть окна открыта, а часть закрыта. Можно, конечно, смонтировать нужное изображение с помощью графического редактора, но нас интересует другой способ достижения результата.

Предположим, что изображение сада уже находится на экране и на него накладывается изображение окна. В таком случае нужен массив значений alpha для каждой точки изображения окна. Не прозрачным точкам, например рамам, подоконнику и т. п., должны соответствовать значения alpha=i, для полностью прозрачных точек, соответствующих открытой части окна, alpha=o, частично прозрачные точки (стекло) предварительно окрашиваются в белый цвет, а значение alpha для них подбирается в пределах от 0,25 до 0,5. Оставим в стороне вопрос о том, как составить массив значений alpha, предположим, что он существует.

Работать с двумя файлами не очень удобно, поэтому на практике используются комбинированные файлы, в которых коды базовых цветов каждой точки дополнены значениями alpha (от 0 до 255). Код точки при этом занимает не 24, а 32 разряда. В специальной литературе вы можете встретить выражение альфа-канал (Alpha Channel), которое обозначает некий источник кодов точек, в которых базовые цвета дополнены значениями alpha. Некоторые модели акселераторов имеют специальный альфа-буфер, для размещения рисунков с 32-разрядными кодами точек. При работе с обычными видеокартами прикладные пакеты (DirectX и Open GL) используют такие комбинированные файлы.

Для наложения строки комбинированного файла надо внести небольшие дополнения в подпрограмму Aiphamix, описанную в примере 7.30. В начале внешнего цикла перед командой, имеющей метку mixed, надо вставить следующие две команды:

mov al, es:[si+3] ; а!=значение альфа для данной точки
mov byte ptr alpha, al ; сохраняем его в переменной alpha

Кроме того,, после обработки кода точки во внешнем цикле, например перед командой inc di, надо вставить команду inc si для пропуска байта, содержащего значение alpha.
Мы не будем обсуждать способ создания комбинированного файла, только отметим, что основная задала заключается в вычислении массива значений коэффициентов alpha. А добавить эти значения к кодам точек образа рисунка не составит особого труда.

Заключение.
Данный раздел завершает основную часть книги. В нем описаны далеко не все спецэффекты, применяемые в современной компьютерной графике. Выбраны только те из них, способы получения которых можно отнести к основам компьютерной графики. При реализации более сложных спецэффектов используются специфические объекты трехмерной графики — треугольники, текстуры и пр. Описание работы с такими объектами выходит за рамки данной книги. Как говорил небезызвестный Козьма Прутков: "Нельзя объять необъятное".


Содержание раздела