Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

RedBook

.pdf
Скачиваний:
18
Добавлен:
11.06.2015
Размер:
7.43 Mб
Скачать

значения карт; все размеры по умолчанию равны 1, а величины по умолчанию – 0. Размер каждой карты должен быть степенью 2.

Таблица 8-6. Имена и значения параметров glPixelMap*()

Имя карты

Что на входе

Что на выходе

GL_PIXEL_MAP_I_I

цветовой индекс

цветовой индекс

GL_PIXEL_MAP_S_S

индекс трафарета

индекс трафарета

GL_PIXEL_MAP_I_R

цветовой индекс

R

GL_PIXEL_MAP_I_G

цветовой индекс

G

GL_PIXEL_MAP_I_B

цветовой индекс

B

GL_PIXEL_MAP_I_A

цветовой индекс

A

GL_PIXEL_MAP_R_R

R

R

GL_PIXEL_MAP_G_G

G

G

GL_PIXEL_MAP_B_B

B

B

GL_PIXEL_MAP_A_A

A

A

 

 

 

Максимальный размер карты является машинно-зависимым. Вы можете выяснить размеры пиксельных карт на вашей машине с помощью команды glGetIntegerv(). Для

выяснения максимального размера всех пиксельных карт используйте аргумент GL_MAX_PIXEL_MAP_TABLE, а для выяснения текущего размера конкретной карты используйте аргументы GL_PIXEL_MAP_*_TO_*. Размеры 6 карт, касающихся цветового и трафаретного индекса, всегда должны быть степенью 2, RGBAкарты могут иметь любой размер от 1 до GL_MAX_PIXEL_MAP_TABLE.

Чтобы понять, как работают эти таблицы, рассмотрим простой пример. Предположим, что вы хотите создать таблицу в 256 вхождениями, которая отображает цветовые индексы на цветовые индексы (GL_PIXEL_MAP_I_TO_I). Вы создаете таблицу с одним вхождением для каждой величины от 0 до 255 и инициализируете ее с помощью glPixelMap*(). Предположим, что вы используете таблицу, которая отображает все индексы меньше 101 (индексы от 0 до 100 включительно) на 0, а все остальные индексы (от 101 до 255 включительно) на 255. В этом случае ваша таблица состоит из 101 нуля и 155 значений 255. Пиксельная карта включается с помощью установки параметра GL_MAP_COLOR в TRUE командой glPixelTransfer*(). Как только

пиксельная карта загружена и активизирована входящие цветовые индексы меньше 101 будут выходить равными 0, а большие или равные 101 – равными 255. Если входящий пиксель больше 255, он сначала маскируется с 255 (в процессе чего отбрасываются все биты старше восьмого) и в таблице ищется получившаяся величина. Если входящий индекс представляет собой число с плавающей точкой (например, 88.14585), он округляется до ближайшего целого (в нашем случае 88) и это число ищется в таблице (результатом в нашем случае будет 0).

Используя пиксельные карты вы также можете изменять индексы трафарета или конвертировать цветовые индексы в RGB.

8.2.2.5Увеличение, уменьшение и отражение изображения

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

void glPixelZoom (GLfloat , GLfloat );

Задает фактор увеличения или уменьшения для операций по записи пикселей

(glDrawPixels() и glCopyPixels()) по осям x и y. По умолчанию и

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

значения факторов отражают изображение относительно текущей позиции растра и соответствующей оси.

Во время растеризации каждый пиксель изображения считается прямоугольником

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

текущей позиции растра как (,). Если отдельная группа элементов (индексов или компонент) является n-ой в ряду и принадлежит m-ной колонке, то в оконных координатах она будет покрывать регион, ограниченный прямоугольником с углами в

и .

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

Отрицательные факторы могут быть полезны для отражения изображения. В OpenGL изображения описываются снизу вверх и слева направо. Если у вас есть изображение, описанное сверху вниз, например, кадр видео, вам может пригодиться glPixelZoom(1.0,-1.0); чтобы выправить изображение под формат OpenGL. Убедитесь, что вы должным образом установили текущую растровую позицию.

Пример 8-4 демонстрирует использование команды glPixelZoom(). В начале в нижнем левом углу окна рисуется изображение шахматной доски. Нажимая клавишу мыши и передвигая ее, вы выполняете команду glCopyPixels(), копируя нижний левый угол окна в текущую позицию курсора. (Если вы скопируете изображение само на себя, оно будет выглядеть довольно неприлично.) Копируемое изображение масштабируется, но изначально оно масштабируется на величину по умолчанию (1.0), так что вы не обратите на это внимание. Клавиши ‘z’ и ‘Z’ увеличивают и уменьшают факторы масштаба на 0.5. Любое повреждение содержимого окна, вызывает его перерисовку. Нажатие на клавишу ‘r’ сбрасывает изображение и факторы масштаба.

Пример 8-4. Рисование, копирование и масштабирование пиксельных данных: файл image.cpp

#include <glut.h> #include <windows.h> #include <stdio.h>

#define checkImageWidth 64 #define checkImageHeight 64

GLubyte checkImage[checkImageHeight][checkImageWidth][3];

GLdouble zoomFactor=1.0;

GLuint height;

void makeCheckImage()

{

int i,j,c;

for (i=0;i<checkImageHeight;i++)

{

for (j=0;j<checkImageWidth;j++)

{

c=(((i&0x08)==0)^((j&0x8)==0))*255;

checkImage[i][j][0]=(GLubyte)c;

checkImage[i][j][1]=(GLubyte)c;

checkImage[i][j][2]=(GLubyte)c;

}

}

}

void init(void)

{

glClearColor(0.0,0.0,0.0,0.0); glShadeModel(GL_FLAT); makeCheckImage(); glPixelStorei(GL_UNPACK_ALIGNMENT,1);

}

void display(void)

{

glClear(GL_COLOR_BUFFER_BIT); glRasterPos2i(0,0); glDrawPixels(checkImageWidth,checkImageHeight,

GL_RGB,GL_UNSIGNED_BYTE,checkImage); glFlush();

}

void reshape(int w, int h)

{

glViewport(0,0,(GLsizei) w, (GLsizei) h); height=(GLint)h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h); glMatrixMode(GL_MODELVIEW); glLoadIdentity();

}

void motion(int x,int y)

{

static GLint screeny;

screeny=height-(GLint)y; glRasterPos2i(x,screeny); glPixelZoom(zoomFactor,zoomFactor);

glCopyPixels(0,0,checkImageWidth,checkImageHeight,GL_COLOR); glPixelZoom(1.0,1.0);

glFlush();

}

void outMsg(bool reset=false)

{

char buffer[100];

if (reset)

sprintf(buffer,"zoomFactor is now %4.1f\n",zoomFactor);

else

sprintf(buffer,"zoomFactor reset to 1.0\n"); MessageBox(NULL,buffer,"Drawing, Copying and Zooming Pixel

Data",MB_OK); return;

}

void keyboard(unsigned char key,int x,int y)

{

switch(key)

{

case 'r': case 'R':

zoomFactor=1.0;

outMsg();

glutPostRedisplay();

break; case 'z':

zoomFactor+=0.5;

if (zoomFactor>=3.0) zoomFactor=3.0;

outMsg(true);

break; case 'Z':

zoomFactor-=0.5;

if (zoomFactor<=0.5) zoomFactor=0.5;

outMsg(true);

break; case 27:

exit(0);

break;

}

}

int main(int argc, char **argv)

{

glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(250,250); glutInitWindowPosition(100,100);

glutCreateWindow("Drawing, Copying and Zooming Pixel Data"); init();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutKeyboardFunc(keyboard);

glutMotionFunc(motion);

glutMainLoop(); return 0;

}

8.2.3 Считывание и рисование прямоугольников пикселей

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

8.2.3.1Процесс рисования пиксельного прямоугольника

Рисунок 8-13 и следующий за ним список описывают процесс рисования пикселей в буфер кадра.

Рисунок 8-13. Рисование пикселей с помощью glDrawPixels()

1.Если пиксели представляют собой не индексы (то есть формат не равен

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

2.Если формат равен GL_LUMINANCE или GL_LUMINANCE_ALPHA, элемент светлоты конвертируется в R, G и B с использованием величины светлоты для каждого из R, G и B компонентов. В формате GL_LUMINANCE_ALPHA альфа величина напрямую переходит в компонент A. Если задан формат GL_LUMINANCE альфа устанавливается равной 1.0.

3.Каждый компонент (R, G, B , A или глубина) умножается на соответствующую величину масштаба, и к ней прибавляется определенный скос. Например, компонент Rумножается на величину GL_RED_SCALE и складывается с величиной GL_RED_BIAS.

4.Если GL_MAP_COLOR равно TRUE, каждый из R, G, B и альфа компонент интерполируется до диапазона [0.0, 1.0], умножается на целое число на единицу меньшее размера цветовой таблицы, его дробная часть отбрасывается и ищется в таблице.

5.Далее R, G, B и A компоненты интерполируются до диапазона [0.0, 1.0] (если они не были интерполированы до этого) и конвертируются в формат с

фиксированной точкой с максимально допустимым количеством бит слева от точки (в соответствии с возможностями буфера кадра для конкретного компонента).

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

сдвигаются влево или вправо на количество разрядов равное абсолютной величине GL_INDEX_SHIFT. Индекс сдвигается влево, если GL_INDEX_SHIFT > 0 и вправо, если GL_INDEX_SHIFT < 0. Наконец, к индексу прибавляется значение

GL_INDEX_OFFSET.

7.Следующий шаг при работе с индексами зависит от того, функционирует ли приложение в RGBA или в индексном цветовом режиме. В RGBA режиме индекс конвертируется в RGBA с использованием карт GL_PIXEL_MAP_I_TO_R, GL_PIXEL_MAP_I_TO_G, GL_PIXEL_MAP_I_TO_B и GL_PIXEL_MAP_I_TO_A. Иначе,

если GL_MAP_COLOR равно GL_TRUE, индекс заменяется согласно таблице

GL_PIXEL_MAP_I_TO_I (если GL_MAP_COLOR равно GL_FALSE– индекс остается неизменным). Если изображение состоит из трафаретных, а не из цветовых индексов, и если GL_MAP_STENCIL равно GL_TRUE, индекс изменяется согласно таблице GL_PIXEL_MAP_S_TO_S. Если GL_MAP_STENCIL равен FALSE

трафаретный индекс не изменяется.

8.Наконец, если индексы не были конвертированы в RGBA, они маскируются до количества бит допустимых для цветового индекса или индекса трафарета.

8.2.3.2Процесс считывания пиксельного прямоугольника

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

Рисунок 8-14. Считывание пикселей с помощью glReadPixels()

1.Если считываемые индексы не являются индексами (то есть формат не равен

GL_COLOR_INDEX и GL_STENCIL_INDEX), компоненты отображаются в диапазон [0.0, 1.0].

2.Далее, к каждому компоненту применяются масштаб и скос. Если GL_MAP_COLOR равен GL_TRUE, компоненты заменяются согласно таблице и снова интерполируются в диапазон [0.0, 1.0]. Если желаемый вами формат освещенность, компоненты суммируются (L=R+G+B).

3.Если пиксели являются индексами (цветовыми или трафаретными), они сдвигаются, складываются со смещением и, если GL_MAP_COLOR равно TRUE, также заменяются с помощью таблицы.

4.Если формат хранения GL_COLOR_INDEX или GL_STENCIL_INDEX, индексы пикселей маскируются до числа бит в типе хранилища (1, 8, 16 или 32) и упаковываются в память.

5.Если формат хранения является одним из основанных на компонентах (таким как светлота или RGB), пиксели всегда заменяются с помощью карт индекс-к- RGBA. Затем работа с ними ведется так, как если бы они были RGBA пикселями с самого начала (включая потенциальную конверсию в формат светлоты).

6.Наконец, и индексные, и компонентные данные упаковываются в память в соответствии с режимами GL_PACK* установленными командой glPixelStore*().

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

Замечание: Может показаться, что светлота обрабатывается неправильно и при чтении, и при записи. Например, обычно светлота зависит от R, G и B не в одинаковой степени, как можно предположить из рисунков 8-13 и 8-14. Если вам нужно, чтобы светлота вычислялась так, чтобы R, G и B вносили в нее 30, 59 и 11 процентов, вы можете установить GL_RED_SCALE в .30, GL_GREEN_SCALE в .59, а GL_BLUE_SCALE в .11. Тогда вычисленное L будет равно .30R+.59G+.11B.

8.2.4 Советы для увеличения скорости вывода пикселей

Как вы можете видеть, у OpenGL весьма большие возможности для считывания, отображения и манипулирования пиксельными данными. Несмотря на то, что эти возможности часто бывают полезны, они также снижают быстродействие. Здесь приведено несколько советов для ускорения операций с пикселями.

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

(1.0, 1.0).

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

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

Если вы используете формат изображения и тип, соответствующие буферу кадра, вы можете сократить работу, которую должна произвести реализация OpenGL. Например, если вы записываете изображение в буфер кадра, имеющий формат RGB и 8 бит на компонент, вызывайте glDrawPixels() с параметром format, установленным в GL_RGB, и type, установленным в GL_UNSIGNED_BYTE.

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

Вполне возможно, что вам удастся снизить затраты на производительность, уменьшив количество перемещаемых данных. Например, вы можете уменьшить тип данных (в частности до GL_UNSIGNED_BYTE) или число компонент (в частности, использовав формат GL_LUMINANCE_ALPHA).

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

8.2.5 Подмножество команд по обработке изображений

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

использование цветовых таблиц для замены величин пикселей

использование фильтров для изображений

использование цветовой матрицы для пространственной конверсии и других линейных преобразований

сбор статистики в виде гистограмм, а также минимальных и максимальных

цветовых значений

использование уравнений цветового наложения для вычисления суммы, разницы, минимума и максимума двух изображений

использование постоянных факторов цветового наложения для изменения цветов пикселей.

Вам следует использовать подмножество команд обработки изображений, если вам требуется большие возможности по работе с пикселями, чем те, что предоставляются командами glPixelTransfer*() и glPixelMap*().

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

Независимо от того, передаются ли пиксели OpenGL или считываются из нее, они обрабатываются всеми активизированными механизмами подмножества. Команды, на которые влияет подмножество, включают следующие:

команды, рисующие и считывающие пиксели: glReadPixels(), glDrawPixels(), glCopyPixels()

команды, определяющие текстуры: glTexImage1D(),glTexImage2D(), glCopyTextureImage*D(), glSubTexImage1D(), glSubTexImage2D(), glCopySubTexImage().

Рисунок 8-15 иллюстрирует операции, производимые подмножеством обработки изображений, над пикселями, которые поступают в OpenGLили считываются оттуда.

Большинство из возможностей подмножества может быть активизировано или деактивировано (за исключением цветовой матрицы, которая всегда активизирована).

Рисунок 8-15. Операции подмножества обработки изображений

Замечание: Константы и функции, связанные с различными расширениями OpenGL могут быть не объявлены в заголовочном файле gl.h, поставляемым с вашим средством разработки, поскольку их поставщики не могут быть заранее уверены, какие расширения поддерживает имеющаяся у вас реализация OpenGL. Чтобы решить проблему с константами, воспользуйтесь дополнительным заголовочным файлом glext.h (более новую его версию вы можете найти на сайте http://www.opengl.org/). Для получения адресов команд – расширений следует воспользоваться специфической для операционной системы функцией. В системах Windows, например, это функция wglGetProcAddress(). Примеры ее использования будут приведены дальше в этой главе.

8.2.5.1Цветовые таблицы

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

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

Таблица 8-7. Цветовые таблицы и их место на конвейере

Цветовая таблица

Воздействует на пиксели

GL_COLOR_TABLE

когда они входят на конвейер

GL_POST_CONVOLUTION_COLOR_TABLE

после фильтрации

GL_POST_COLOR_MATRIX_COLOR_TABLE

после цветовой матрицы

 

 

Каждая таблица может быть включена отдельно с помощью команды glEnable() с соответствующим аргументом из таблицы 8-7.

8.2.5.1.1Настройка цветовых таблиц

Соседние файлы в предмете Компьютерная Графика