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

RedBook

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

count--;

}

else

if(token==GL_POINT_TOKEN)

{

printf("GL_POINT_TOKEN\n"); print3DcolorVertex(size,&count,buffer);

}

else

if(token==GL_LINE_TOKEN)

{

printf("GL_LINE_TOKEN\n"); print3DcolorVertex(size,&count,buffer); print3DcolorVertex(size,&count,buffer);

}

else

if(token==GL_LINE_RESET_TOKEN)

{

printf("GL_LINE_RESET_TOKEN\n");

print3DcolorVertex(size,&count,buffer);

print3DcolorVertex(size,&count,buffer);

}

}

}

void display()

{

GLfloat feedBuffer[1024]; GLint size;

glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0,100.0,0.0,100.0,0.0,1.0);

glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); drawGeometry(GL_RENDER);

glFeedbackBuffer(1024,GL_3D_COLOR,feedBuffer); glRenderMode(GL_FEEDBACK);

drawGeometry(GL_FEEDBACK);

size=glRenderMode(GL_RENDER); printBuffer(size,feedBuffer);

}

int main(int argc, char* argv[])

{

glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(100,100); glutInitWindowPosition(100,100); glutCreateWindow("Feedback Mode"); init();

glutDisplayFunc(display);

glutMainLoop(); return 0;

}

Запуск программы генерирует следующий вывод:

GL_LINE_RESET_TOKEN

30.00 30.00 0.00 0.84 0.84 0.84 1.0

50.00 60.00 0.00 0.84 0.84 0.84 1.0 GL_LINE_RESET_TOKEN

50.00 60.00 0.00 0.84 0.84 0.84 1.0

70.00 40.00 0.00 0.84 0.84 0.84 1.0 GL_PASS_THROUGH_TOKEN

1.00 GL_PASS_THROUGH_TOKEN 2.00

GL_POINT_TOKEN

50.00 50.00 0.00 0.84 0.84 0.84 1.0

Таким образом, ломаная, рисуемая следующими командами, отображается в два примитива:

glBegin(GL_LINE_STRIP); glNormal3f(0.0,0.0,1.0); glVertex3f(30.0,30.0,0.0); glVertex3f(50.0,60.0,0.0); glVertex3f(70.0,40.0,0.0);

glEnd();

Первый примитив начинается с кода GL_LINE_RESET_TOKEN. Это означает, что первым примитивом является сегмент линии, и что шаблон для линий сброшен. Второй примитив начинается с GL_LINE_TOKEN, то есть это тоже сегмент линии, но ломаная не прерывается и, следовательно, продолжается из той точки, где закончился предыдущий сегмент. Каждая из двух вершин этих линий генерирует по 7 величин в массиве отклика. Заметьте, что RGBA величины для всех четырех точек этих двух линий равны (0.84, 0.84, 0.84, 1.0), что является очень светлым оттенком серого цвета с максимальным значением альфа. Эти цветовые величины результат взаимодействия вектора нормали и параметров освещения.

Поскольку между первым и вторым сквозными маркерами не было сгенерировано данных отклика, вы можете сделать вывод о том, что примитивы, нарисованные между первыми двумя вызовами glPassThrough() были отсечены по объему видимости. Наконец, рисуется точка с координатами (50.0, 50.0, 0.0), и ассоциированные с ней данные заносятся в буфер отклика.

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

Глава 14. Трюки и советы

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

14.1 Обработка ошибок

Правда заключается в том, что ваша программа будет совершать ошибки.

Использование функций обработки ошибок просто необходимо во время разработки и настоятельно рекомендуется для коммерческих приложений. (Если только вы не можете дать 100 процентной гарантии, что ваша программа не сгенерирует ошибку OpenGL, но

кто может это гарантировать?) OpenGL предоставляет простые функции обработки ошибок для базовой библиотеки OpenGL и библиотеки GLU.

Когда OpenGL обнаруживает ошибку, она записывает код текущей ошибки. Команда, сгенерировавшая ошибку игнорируется, так что она не оказывает никакого воздействия на состояние OpenGL или содержимое буфера кадра. (Однако, если записанной ошибкой была GL_OUT_OF_MEMORY, результат выполнения команды не определен.) После записи код текущей ошибки не изменяется, то есть в него другие ошибки не записываются до тех пор, пока вы не вызовите команду glGetError(), возвращающую код текущей ошибки. После того, как вы запросили и очистили код текущей ошибки или если ни одной ошибки не было, glGetError() будет возвращать значение GL_NO_ERROR.

GLenum glGetError (void);

Возвращает текущее значение флага ошибки. Когда ошибка происходит в GL или GLU, ее код записывается в флаг ошибки. Если возвращаемое значение равно GL_NO_ERROR, значит, ошибок не происходило с момента последнего вызова glGetError() или с момента инициализации OpenGL. Никакие другие ошибки не записываются до тех пор, пока не будет произведен вызов glGetError(), не вернется код ошибки, и флаг не будет сброшен в значение GL_NO_ERROR.

Настоятельно рекомендуется вызывать glGetError() хотя бы один раз в каждой функции display() вашего приложения. Основные коды ошибок OpenGL перечислены в таблице 14-1.

Таблица 14-1. Коды ошибок OpenGL

Код ошибкии

Описание

GL_INVALID_ENUM

аргумент типа GLenum вне допустимого диапазона

GL_INVALID_VALUE

численный аргумент вне допустимого диапазона

GL_INVALID_OPERATION

недопустимая операция для текущего состояния

GL_STACK_OVERFLOW

команда вызовет переполнение стека

GL_STACK_UNDERFLOW

команда вызовет извлечение или изменение значения в пустом стеке

GL_OUT_OF_MEMORY

недостаточно памяти для выполнения команды

 

 

Существует также 37 ошибок связанных с интерфейсом GLU NURBS (имеющих не описательные константные имена GL_NURBS_ERROR1, GLU_NURBS_ERROR2 и так далее); 14 ошибок тесселяции (GLU_TESS_MISSING_BEGIN_POLYGON, GLU_TESS_MISSING_END_POLYGON, GLU_TESS_MISSING_BEGIN_CONTOUR, GLU_TESS_MISSING_END_CONTOUR, GLU_TESS_COORD_TOO_LARGE, GLU_TESS_NEED_COMBINE_CALLBACK, а также еще 8 ошибок, начинающихся с префикса GLU_TESS_ERROR*); и GLU_INCOMPATIBLE_GL_VERSION. GLU также определяет коды ошибок GLU_INVALID_ENUM, GLU_INVALID_VALUE и GLU_OUT_OF_MEMORY, имеющие тот же смысл, что и связанные коды ошибок OpenGL.

Чтобы получить описательную строку, соответствующую коду ошибки GL или GLU, используйте функцию GLU gluErrorString().

const GLubyte* gluErrorString (GLenum errorCode);

Возвращает указатель на описательную строку, соответствующую коду ошибки GL или GLU, переданному в качестве аргумента errorCode.

В примере 14-1 показана простая функция обработки ошибок.

Пример 14-1. Опрос и распечатка ошибки

GLenum errCode;

const GLubyte *errString;

if ((errCode=glGetError())!=GL_NO_ERROR

{

errString=gluErrorString(errCode); fsprintf(stderr,”OpenGL error: %s\n”, errString);

}

Замечание: Приложение не должно изменять или удалять из памяти строку,

возвращенную gluErrorString().

14.2 Определение используемой версии

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

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

текстурирование режимом по умолчанию на одной машине и ограничиться плоской закраской на другой. Для получения информации о версии OpenGL вы можете использовать команду glGetString().

const GLubyte* glGetString (GLenum name);

Возвращает указатель на строку, описывающий один из аспектов реализации OpenGL.

Аргумент name может принимать значения GL_VENDOR, GL_RENDERER, GL_VERSION

или GL_EXTENSIONS. GL_VENDOR возвращает название компании, ответственной за реализацию OpenGL, например:

NVIDIA Corporation

GL_RENDERER возвращает идентификатор визуализатора, обычно совпадающий с аппаратной платформой, например:

Voodoo550/AGP

или

GeForce4 Ti 4600/AGP/SSE2

О результате GL_EXTENSIONS можно подробно узнать в следующем разделе.

GL_VERSION возвращает строку, идентифицирующую номер версии реализации OpenGL. Строка версии состоит из следующих компонентов:

<номер версии><пробел><информация, зависящая от производителя>

Номер версии имеет форму

major_number.minor_number

или

major_number.minor_number.release_number

где каждое число может состоять из одной или более цифр. Информация, зависящая от производителя, является опциональной. Например, если реализация OpenGL создана компанией XYZ, возвращенная строка может быть следующей:

1.2.4 XYZ-OS 3.2

что означает, что это четвертый выпуск реализации OpenGL компании XYZ, и что эта реализация подчиняется спецификации OpenGL версии 1.2. Это также может означать, что данный выпуск предназначен для какой-либо операционной системы версии 3.2.

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

GL_VERSION_1_3, GL_VERSION_1_2 и GL_VERSION_1_1. Отсутствие константы GL_VERSION_1_3 означает, что у вас версия GL_VERSION_1_2, GL_VERSION_1_1 или

GL_VERSION_1_0. Отсутствие константы GL_VERSION_1_2 означает, что у вас версия

GL_VERSION_1_1 или GL_VERSION_1_0 и так далее.

Замечание: Однако стоит помнить, что реальная версия используемой реализации OpenGL и версия, на которую рассчитан заголовочный файл (а константы определяются именно в нем) могут различаться. Например, на момент написания данного пособия в основном действовала спецификация OpenGL 1.3, однако корпорация Microsoft продолжала поставлять вместе со своими средствами разработки заголовочные файлы и библиотеки импорта, рассчитанные на OpenGL спецификации 1.1. Так что важно помнить, что команда glGetString(GL_VERSION) на этапе выполнения программы возвращает номер версии реальной реализации OpenGL, используемой в вашей системе, а метод с применением директивы #ifndef на этапе разработки позволяет определить только версию, на которую рассчитан заголовочный файл gl.h.

Замечание: При работе в клиент – серверной архитектуре (например, с OpenGL расширением системы X Window) клиент и сервер могут иметь разные версии. Если версия вашего клиента более поздняя, чем версия сервера, клиент может запросить операцию, которая сервером не поддерживается.

14.2.1 Номер версии GLU

Функция gluGetString() предназначена для опроса реализации GLU и похожа на команду glGetString().

const GLubyte* gluGetString (GLenum name);

Возвращает указатель на строку, описывающий один из аспектов реализации GLU. Аргумент name может принимать значения GLU_VERSION или GLU_EXTENSIONS.

Обратите внимание, что функции gluGetString() не было в GLU версии 1.0. Другим способом получения информации о GLU (точнее информации о версии, на которую рассчитан заголовочный файл и библиотека импорта) заключается в использовании директивы препроцессора #ifndef для поиска констант GLU_VERSION_1_3, GLU_VERSION_1_2, GLU_VERSION_1_1 и GLU_VERSION_1_0 по аналогии с константами GL.

Имейте в виду, что расширения GLU отличаются от расширений OpenGL.

14.2.2 Версия расширений оконной системы

Для расширений оконных систем, предназначенных для работы с OpenGL, таких как GLX, WGL, PGL и AGL существуют похожие функции (например, glXQueryExtensionString()), запрашивающие информацию о версии.

(Упомянутая glXQueryExtensionString() и связанные функции появились в GLX 1.1 и не поддерживаются в GLX1.0)

14.3 Расширения стандарта

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

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

Имена функций и символических констант четко показывают, является ли конкретная возможность частью стандарта OpenGL, расширением специфичным для отдельного производителя или расширением OpenGL принятым OpenGL ARB (Architecture Review Board – Совет по Пересмотру Архитектуры).

Чтобы составить имя, специфичное для производителя, сам производитель добавляет идентификатор компании (заглавными буквами) и дополнительную информацию (например, тип компьютера). Например, если компания XYZ хочет добавить новую функцию и символическую константу, их имена могут быть в форме glCommandXYZ() и GL_DEFINITION_XYZ, соответственно. Если компания XYZ хочет разработать расширение доступное только на их «Специально Разработанной (Special Developed)» видеокарте, именами могут быть glCommandXYZsd() и GL_DEFINITION_XYZ_SD.

Если двое или более производителей согласны реализовать то же расширение, то к именам функций и констант добавляется более общий суффикс EXT (glCommandEXT()

и GL_DEFINITION_EXT).

Похожим образом, если расширение было принято OpenGL ARB, к именам функций и констант добавляется суффикс ARB (glCommandARB() и GL_DEFINITION_ARB).

Если вы хотите выяснить, поддерживается ли конкретное расширение в вашей реализации, сначала вызовите glGetString() с аргументом GL_EXTENSIONS, а затем gluGetString() с аргументом GLU_EXTENSIONS. Эти команды вернут полный список расширений, поддерживаемых вашей реализацией. В обеих строках индивидуальные имена расширений разделяются пробелами.

Первые расширения принятые ARB появились в OpenGL версии 1.2. Если в реализации

стандарта этой версии поддерживалось подмножество команд обработки изображений (Imaging Subset), в возвращенной строке расширений присутствовал фрагмент GL_ARB_imaging. Наличие фрагмента GL_ARB_multitexture свидетельствовало о том, что реализация поддерживает механизм мультитекстурирования, принятый ARB.

Если вы работаете с GLU версии 1.3 или выше, вы можете использовать функция gluCheckExtension() для определения того, поддерживается ли конкретное расширение.

GLboolean gluCheckExtension (char* extName, const GLubyte* extString);

Возвращает GL_TRUE, если строка extName обнаружена в extString, и GL_FALSE в ином случае.

gluCheckExtension() может проверять как расширения OpenGL, так и GLX, и GLU.

Чтобы обнаружить поддерживается ли конкретное расширение при работе с GLU ранних версий, вы можете использовать код из примера 14-2, который просматривает список расширений в поисках нужного. Функция QueryExtension() возвращает GL_TRUE, если расширение обнаружено и GL_FALSE в противном случае.

Пример 14-2. Выявление наличия поддержки расширения (для кода с использованием

GLU 1.0, 1.1 или 1.2)

GLboolean QueryExtension(char *extName)

{

char *p=(char*)glGetString(GL_EXTENSIONS); char *end;

if(p==NULL)

return GL_FALSE; end=p+strlen(p); while(p<end)

{

int n=strcspn(p," ");

if((strlen(extName)==n) && (strncmp(extName,p,n)==0)) return GL_TRUE;

p+=(n+1);

}

return GL_FALSE;

}

14.3.1 Расширения к стандарту для Microsoft Windows (WGL)

Если на платформе Microsoft Windows вы хотите получить доступ к функциям расширений, вы должны:

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

идентифицирующей расширение

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

использовать функцию wglProcAddress() для обнаружения указателя на функцию расширения.

Пример 14-3 демонстрирует процесс обнаружения фиктивного расширения glSpecialEXT(). Заметьте, что условный код (#ifndef) проверяет наличие определения GL_EXT_special. Если расширение присутствует, то для указателя на функцию расширения определен специальный тип PFNGLSPECIALEXTPROC. Наконец, wglGetProcAddress() получает указатель на функцию.

Пример 14-3. Обнаружение расширения OpenGL с помощью wglGetProcAddress()

#ifdef GL_EXT_special PFNGLSPECIALEXTPROC glSpecialEXT;

#endif

/* где-то в другом месте программы */ #ifdef GL_EXT_special

glSpecialEXT=(

PFNGLSPECIALEXTPROC)wglGetProcAddress(“glSpecialEXT”);

assert(glSpecialEXT!=NULL);

#endif

14.4 Пропускание света

Вы можете использовать шаблонирование полигонов для симуляции материала, пропускающего свет. Это решение особенно полезно для систем, в которых отсутствует аппаратура для цветового наложения. Поскольку размер рисунка шаблона полигона – 32 на 32 бита или 1024 бита в целом, вы можете пройти от непрозрачного до прозрачного материала за 1023 шага (на практике требуется значительно меньше шагов). Например, если вы хотите, чтобы поверхность пропускала 29 процентов света, создайте шаблон, в котором 29 процентов бит (это примерно 297 бит) будут установлены в 0, а остальные в 1. Даже если все ваши поверхности должны пропускать одинаковое количество света, не используйте один рисунок шаблона для всех, поскольку они накроют те же самые биты на экране. Создавайте новый рисунок для каждой поверхности, выбирая нужное количество бит, которые будут установлены в 0, случайным образом.

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

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

14.5 Эффект исчезающего изображения

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

Например, предположим, что вы хотите растворить изображение в черном цвете за 16 шагов. Сначала определите 16 различных массивов с рисунками шаблонов:

GLubyte stips[16][4*32];

Затем загрузите их таким образом, чтобы в первом рисунке в единицы была установлена 1/16 часть от 32x32 бит, а побитовое ИЛИ всех рисунков шаблона было равно всем единицам. Далее нужно применить следующий код:

нарисовать_изображение();

glColor3f(0.0,0.0,0.0); /* установить текущий цвет в черный */ for(i=0;i<16;i++)

{

glPolygonStipple(&stips[i][0]);

нарисовать_большой_полигон_закрывающий_всю_область();

}

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

#define STIP_OFFSET 100 for(i=0;i<16;i++)

{

glNewList(i+STIP_OFFSET,GL_COMPILE); glPolygonStipple(&stips[i][0]);

glEndList();

}

Затем в предыдущем фрагменте кода замените строку

glPolygonStipple(&stips[i][0]);

на

glCallList(i);

Скомпилировав команды настройки рисунков шаблона в списки отображения, OpenGL может переработать данные в stips[ ][ ] в аппаратно-зависимую форму, требуемую для максимально быстрой работы с шаблонами.

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

current_stipple=0;

/* вечный цикл */

while(1)

{

 

нарисовать_следующий_кадр(); glCallList(current_stipple)++; if(current_stipple==16)

current_stipple=0;

/* установить текущий цвет в

glColor3f(0.0,0.0,0.0);

черный */

 

нарисовать_большой_полигон_закрывающий_всю_область();

}

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

значительно проще перед рисованием каждого кадра накладывать на изображение некоторое количество цвета фона.

14.6 Выбор объектов с помощью заднего буфера

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

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

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

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

Имейте в виду, что если в вашей сцене очень много объектов, уникальные идентификаторы могут закончиться. Например, предположим, что вы работаете на системе с 4-ех битными буферами для цветовых индексов (16 возможных индексов) в обоих переднем и заднем буферах, но в сцене присутствуют тысячи объектов. Чтобы решить такую проблему, можно осуществлять выбор в несколько проходов. Чтобы поговорить об этом конкретнее, предположим, что в вашей сцене менее 4096 объектов, то есть все идентификаторы могут быть закодированы 12 битами. Во время первого прохода нарисуйте сцену с использованием индексов, состоящих из 4-ех старших бит идентификаторов, затем, во время второго и третьего проходов используйте индексы, состоящие из 4-ех средних и младших битов идентификаторов. Во время каждого прохода, выясните значение индекса под курсором и, в конце, упакуйте их вместе это даст вам идентификатор нужного объекта.

При таком подходе выбор занимает в три раза больше времени, но иногда это приемлемо. Заметьте, что после того, как вы получили 4 старших бита идентификатора, вы можете отбросить 15/16 всех объектов, так что на самом деле вам нужно нарисовать только 1/16 из них на втором проходе. Похожим образом после второго прохода можно отбросить 255/256 возможных объектов. Таким образом, первый проход занимает столько же времени, сколько рисование одного кадра, но второй и третий проходы могут пройти в 16 и 256 быстрее, соответственно.

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

14.7 Простые преобразования изображений

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

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

Для конкретизации проблемы предположим, что оригинальное изображение имеет размеры m на n пикселей, с координатами между [0,m-1] и [0,n-1]. Пусть функциями искажения будут x(m,n) и y(m,n). Например, если искажение представляет собой просто изменение масштаба с фактором 3.2, то x(m,n)=3.2m, а y(m,n)=3.2n. Следующий код рисует искаженной изображение:

glShadeModel(GL_FLAT); glScale(3.2,3.2,1.0);

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