Opengl игорь Тарасов Часть I основы OpenGL



бет3/4
Дата29.05.2016
өлшемі2.21 Mb.
#100716
1   2   3   4

4.12 Трафарет II
Ранее вы познакомились с надоложение трафарета состоящего из массива бит 32х32 точки. Недостатки такого трафарета в его небольшой площади и то, что каждые его элемент является битом, т.е. у такого трафарета всего две зоны(рисуем и не рисуем). Далее вы познакомитесь с полноценным трафаретом.

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


рис. 4.12.1


Мы поставим себе задачу изобразить три рисунка: куб минус сфера, сфера минус куб, пересечение куба и сферы. Как вы понимаете объединение куба и сферы выводится без всякого буфера трафарете по умолчанию. Собственно говоря, оно(объединение) изображено на рисунке 4.12.1. Теперь о том, что такое трафарет и как им пользоваться. Трафарет это двумерный массив целых переменных(тип int). Каждому пикселю в окне соответствует один элемент массива. Использование буфера трафарета происходит в два этапа. Сначала вы его заполняете, потом основываясь на его содержимом рисуете ваши объекты. Буффер трафарета заполняется следующим образом. Вы делите окно вывода на зоны и каждой зоне присваеваете свое значение. Например, для рисунка 4.12.1 область, где нет ничего будет заполнена нулями, область, где выведен куб заполнена единицами и область, где видна сфера двойками.

Обратите внимание, что буффер трафарета - это двумерный массив, а не трехмерный. Теперь вы легко можете представить себе эти области, они собственно и изображены на приведенном рисунке. Также заметьте, что цвет здесь роли не играет. Я бы мог вывести все черным цветом, а буфер трафарета заполнился в зависимости от геометричеких размеров фигур и от их пересечения. Далее мы рассмотрим функции библиотеки OpenGL для работы с трафаретом. Тест трафарета разрешается при помощи функций glEnable\glDisable с параметром GL_STENCIL_TEST. Очищается буфер трафарета при помощи функции glClear с параметром GL_STENCIL_BUFFER_BIT. Заполнение буфера трафарета происходит при помощи следующих двух функций:


void glStencilFunc(GLenum func, GLint ref, GLuint mask)

void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)


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

Не проходит

GL_LESS

Проходит if ( ref & mask) < ( stencil & mask)



GL_LEQUAL

Проходит if ( ref & mask) ? ( stencil & mask)

GL_GREATER

Проходит if ( ref & mask) > ( stencil & mask)

GL_GEQUAL

Проходит if ( ref & mask) ? ( stencil & mask)

GL_EQUAL

Проходит if ( ref & mask) = ( stencil & mask)

GL_NOTEQUAL

Проходит if ( ref & mask) ? ( stencil & mask)

GL_ALWAYS

Всегда проходит


Если тест трафарета не пройден, то фрагмент(пикселы) фигуры не прорисовываются в данном месте, т.е. они не попадают в буффер кадра. Если тест пройден, то фигура рисуется. Вторая функция позволяет задать, как будет инициализироваться буфер трафарета. Параметры fail, zfail и zpass могут принимать одно из следующих значений:
GL_KEEP

Сохранить текущее значение в буфере трафарета

GL_ZERO

Установить значение буфера трафарета в ноль



GL_REPLACE

Заменить значение буфера трафарета на значение переменной ref, заданной функцие glStencilOp

GL_INCR

Увеличить на единицу



GL_DECR

Уменьшить на единицу

GL_INVERT

Поразрадно инвертировать

В случае непрохождения теста трафарета над фрагментом выполняется действие определенной парамметром fail. Например, если мы хотим заполнить область трафарета, где рисуется куб единицами, то можно использовать следующи код:
glStencilFunc(GL_NEVER, 1, 0); // значение mask не используется

glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);

auxSolidCube(2.5);
Объясняю подробней, первая функция говорит о том, что тест трафарета всегда проходит неудачно. Вторая функция задает, что в случае неудачного теста трафарета заменить значение храняцееся в буфере трафарета на значение переменной ref, а его мы задали равным единице. В результате, на экране ничего не нарисуется т.к. тест трафарета завершался неудачно, но в буфере трафарета мы получили проекию куба из единичек, т.е. буфер трафарета заполнен не только нулями. Теперь мы хотим заполнить двойками область, где прорисовывается сфера. Здесь мы уже должны учитывать буфер глубины, иначе мы заполним двойками всю область, где у нас рисуется сфера. Для того чтобы учитывать буфер глубины тест трафарета должен завершиться положительно. Третий параметр zpass функции glStencilOp как раз указывает, что делать, если тест трафарета прошел, а тест глубины нет. Поэтому код выглядит так:
glStencilFunc(GL_ALWAYS, 2, 0); // значение mask не используется

glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

auxSolidSphere(1.5);
В результате получаем буфер трафарета заполненный нулями, где ничего не было, единицами, где виден куб и двойками, где видна сфера. В последнем примере тест трафарета прошел успешно, поэтому на экране была нарисована сфера. Но это нам не мешает мы очистим буфер глубины и буфер цвета, но не буфер трафарета.
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Теперь дело техники нарисовать тотже самый куб без сферы. Надо установить, что тест трафарета проходит, если значение находящееся в буфере трафарета совпадает со сзначением второго параметра функции glStencilFunc. Как вы помните куб в буфере трафарета имел значение единицы. Поэтому получаем:
glStencilFunc(GL_EQUAL, 1, 255); // куб рисуется только там, где

// в буфере трафарета лежат единицы

glColor3d(1,1,1);

auxSolidCube(2.5);


Создайте новый проект с именем stencil. Скопируйте glaux.c в stencil.c и отредактируйте функцию display следующи образом:
void CALLBACK display(void){

// очищаем все буферы

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// разрешаем тест трафарета

glEnable(GL_STENCIL_TEST);


// рисуем куб и заполняем буффер трафарета единицами

// в том месте, где рисуется куб

// тут у меня немного по другому, чем я выше было разоьрано,

// но действие выполняется анологичное

glStencilFunc(GL_ALWAYS, 1, 0);

glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

auxSolidCube(2.5);
// заполняем буффер трафарета двойками

// в том месте, где сфера закрывает куб

glStencilFunc(GL_ALWAYS, 2, 0);

glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

auxSolidSphere(1.5);
// очищаем буфферы цвета и глубины

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


glStencilFunc(GL_EQUAL, 1, 255);

glColor3d(1,1,1);

auxSolidCube(2.5);
// вращаем сцену

glRotated(3, 1,0,0);

glRotated(5, 0,1,0);

glRotated(7, 0,0,1);


auxSwapBuffers();}

рис. 4.12.2


Теперь давайте немного приукрасим нашу программу. Давайте внутри куба нарисуем красный шар, который будут опоясывать зеленый и синий тор. Делается это следующим образом. Как и в предыдущей программе вы составляете буфер трафарета, после чего очищаете буфер глубины и цета, запрещаете тест трафарета, т.к. нам надо просто вывести фигуры без трафарета, выводите шар с торами, и, наконец, включает тест трафарета и выводите куб с отверстиями. Вот код фунции display:
void CALLBACK display(void){

// очищаем все буферы

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// разрешаем тест трафарета

glEnable(GL_STENCIL_TEST);


// рисуем куб и заполняем буффер трафарета единицами

// в том месте, где рисуется куб

// тут у меня немного по другому, чем я выше было разоьрано,

// но действие выполняется анологичное

glStencilFunc(GL_ALWAYS, 1, 0);

glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

auxSolidCube(2.5);
// заполняем буффер трафарета двойками

// в том месте, где сфера закрывает куб

glStencilFunc(GL_ALWAYS, 2, 0);

glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

auxSolidSphere(1.5);
// очищаем буфферы цвета и глубины

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// запрещаем тест трафарета и рисуем красную сферу

glDisable(GL_STENCIL_TEST);

glColor3d(1,0,0);

auxSolidSphere(0.5);

//синий тор

glColor3d(0,0,1);

auxSolidTorus(0.15, 0.6);

// зеленый тор, повернутый на 90 градусов относительно синего

glColor3d(0,1,0);

glPushMatrix();

glRotated(90, 1,0,0);

auxSolidTorus(0.15, 0.6);

glPopMatrix();
//снова разрешаем тест трафарета

glEnable(GL_STENCIL_TEST);


glStencilFunc(GL_EQUAL, 1, 255);

glColor3d(1,1,1);

auxSolidCube(2.5);
// вращаем сцену

glRotated(3, 1,0,0);

glRotated(5, 0,1,0);

glRotated(7, 0,0,1);


auxSwapBuffers();}

Исходный файл смотрите здесь. Исполняемый файл здесь.


4.13 Упражнение "сфера минус куб"
Напишите программу, в которой будет крутиться сфера минус куб.
4.14 Упражнение "пересечение сферы и куба"
Напишите программу, в которой будет крутиться пересечение сферы и куба.
Chapter 5

Работа с картинками

5.1  Общие слова

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

Существует множество графических форматов - bmp, pcx, gif, jpeg и прочие. OpenGL напрямую не поддерживает не один из них. В OpenGL нет функций чтения/записи графических файлов. Но поддерживается работа с массивами пикселей. Вы загружаете графический файл, используя библиотеки других фирм, в память и работаете с ними средствами OpenGL. В массиве данные о пикселах могут располагаться разными способами: RGB, BGR, RGBA; могут присутствовать не все компоненты; каждый компонент цвета может занимать один байт, два, четыре или восемь; выравнивание может быть по байту, слову или двойному слову. В общем, форматов расположения данных о графическом изображении в памяти очень много. Я рассмотрю один из них, наиболее часто применяемый, как мне кажется. Информация о каждом пикселе хранится в формате RGB и занимает три байта, выравнивание по байту. В Auxiliary Library есть функция auxDIBImageLoad(LPCSTR), которая загружает в память bmp-файл и возвращает указатель на структуру:


typedef struct _AUX_RGBImageRec {

GLint sizeX, sizeY;

unsigned char *data;

} AUX_RGBImageRec;


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

В OpenGL имеются функции для вывода массива пикселей на экран(glDrawPixels), копирования(glCopyPixels), масштабирования(gluScaleImage). Здесь мы рассмотрим только glDrawPixels. Все остальные функции работы с изображениями устроены похожим образом. Для того, чтобы отобразить графический файл в окне OpenGL, вы должны загрузить его в память, указать выравнивание, установить точку, с которой начинается вывод изображения, и вывести его на экран. Раздобудьте где-нибудь свою фотографию в формате BMP. Можете взять фотографию своей девушки. Создайте новый проект. Объявите глобальную переменную - AUX_RGBImageRec *image. В функцию main вставьте строку: пmage = auxDIBImageLoad("photo.bmp");", перед вызовом функции auxMainLoop. Выравнивание устанавливается вызывом функции glPixelStorei с параметром GL_UNPACK_ALIGNMENT и вторым параметром - целым числом, которое указывает выравнивание. Изображения выводятся прямо на экран. Поэтому все происходит в двухмерных координатах. Позиция, с которой начинается вывод изображения, указывается при помощи функции glRasterPos2d(x,y). Также вы можете установить размер пикселя, вызвав функцию glPixelZoom. Первый параметр этой функции - ширина, второй - высота пикселя. Я вызываю эту функцию с аргументами (1,1), что соответствует нормальному пикселю. Замените (1,1) на (3,2) и вы увидите, как картинка растянется в три раза по горизонтали и в два раза по вертикали. Это случилось, потому что теперь каждый пиксель изображения соответствует прямоугольнику 3х2 в окне. И наконец, вывод осуществляет функция glDrawPixels. Первые два параметра - это ширина и высота. Далее, вы указываете формат, в котором хранится информация в памяти, и тип элементов массива. Последним указывается массив данных.

В функцию display вставьте следующий код:

glRasterPos2d(-4.5,-3); // нижний левый угол

glPixelZoom(1,1);

glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // выравнивание

glDrawPixels(image->sizeX, image->sizeY, // ширина и высота

GL_RGB, GL_UNSIGNED_BYTE, // формат и тип

image->data); // сами данные
Также в OpenGL имеется функция glBitmap для отображения битовых массивов. Битовый массив - это последовательность байт, которые кодируют картинку из двух цветов. Соответственно, каждый байт кодирует 8 пикселей. Среди прилагаемых программ вы найдете мою утилиту pcx_2bpp. Она читает pcx-файл формата один бит на пиксель и направляет на стандартный вывод массив на языке Си.

"Исходный файл смотрите здесь. Исполняемый файл здесь. Моя фотография здесь.


5.3  Упражнение: "Фон для игры Arcanoid"

Найдите красивый фон в формате BMP. Можете опять взять свою фотографию. Подложите этот bmp-файл в качестве фона в игру Дrcanoid". Закомментируйте разрешение всех тестов, кроме GL_DEPTH_TEST, в функции main. Возможно, я уже говорил о том, что вы всегда должны помнить, что дополнительные параметры затормаживают создание объекта, поэтому устанавливайте их очень осторожно. Часть из них можно установить в функции main. Другие же лучше устанавливать и отменять непосредственно при создании объекта.



Исходный файл смотрите здесь. Исполняемый файл здесь. Звездное небо здесь.


5.4  Создаем текстуру в памяти

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

Сначала мы разберем создание и наложение текстур на плоскость. Затем рассмотрим наложение текстур на объекты, описанные в секции 4.1. И наконец, на все прочие, созданные из многоугольников; в частности, тор.

Для того, чтобы наложить текстуру на объект, вы должны:




  1. Загрузить графический файл в память

  2. Создать имя-идентификатор текстуры

  3. Сделать его активным

  4. Создать саму текстуру в памяти

  5. Установить параметры текстуры

  6. Установить параметры взаимодействия текстуры с объектом

  7. Связать координаты текстуры с объектом

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

unsigned int photo_tex;

AUX_RGBImageRec* photo_image;

unsigned int space_tex;

AUX_RGBImageRec* space_image;


Переменные photo_tex и space_tex будут служить идентификаторами текстур. А в photo_image и space_image мы загрузим bmp-файлы. Тут нужно отметить, что текстуры в OpenGL должны иметь размер 2n x 2m, где n и m целые числа. Это сделано для ускорения работы, т.к. сжимать или растягивать такие текстуры быстрее и удобней. Вы, конечно, можете загрузить изображение любого другого размера, но его придется масштабировать. На мой взгляд, это неправильно. Результат масшабирования вас может и не устроить. Так что я использую графические файлы с размером, кратным степени двойки. Мне удобнее отредактировать изображение в каком-нибудь графическом пакете, урезать его или наоборот дополнить, чем потом выяснять, почему оно искажается. Впрочем, тут многое зависит от конкретного случая. Художнику, который делает текстуры, все равно какого размера ее делать, поэтому легче попросить его сделать изображение с подходящими размерами. Вставьте следующий код в функцию main.
photo_image = auxDIBImageLoad("photo.bmp");

space_image = auxDIBImageLoad("space.bmp");


Картинки возьмите из моей программы - Texture. Фотографию можете взять свою.;-) Только размер ее желательно оставить 512x512.

Теперь вы должны создать имя-идентификатор текстуры. Его нужно создавать, когда у вас в приложении используется более одной текстуры, чтобы была возможность как-то их различать. В противном случае, когда текстура только одна, идентификатор ей не нужен. В следующем примере, при наложение текстуры на сферу, у нас будет ровно одна текстура, и я покажу вызовы каких функций необязательны. А пока, я предполагаю, что вам нужно использовать несколько текстур. Кстати, я просматривал много примеров при написание книги. Среди них были примеры из широко известной Red Book, примеры из MSDN, из интернета и других источников, но все, что касалось текстур, работало только с одной текстурой. Для элементарной программы-примера, конечно, подойдет и одна тектура, а вот для серьезных приложений вряд ли. Моя команда занимается написанием серьезных приложений, поэтому и возникла потребность в использовании нескольких текстур. Функция glGenTextures принимает на вход два параметра. Первый указывает количество имен-идентификаторов текстур, которые нужно создать. Второй параметр - указатель на массив элементов типа unsigned int. Количество элементов в массиве должно совпадать с числом, указанным в качестве первого параметра. Например, следующий код создает десять имен текстур.


unsigned int names[10];

glGenTetures(10, names);


Хранить идентификаторы текстур в массиве не всегда удобно. Такой способ подходит для хранения задних фонов или типов стен - кирпичная, каменная и т.п. В общем, в массиве хранят те элементы, между которыми есть что-то общее. В нашем случае, два изображения связаны, т.к. используюся в одном приложении, поэтому я создал два различных идентификатора. Так что добавьте следующий код в функцию main.
glGenTextures(1, &photo_tex);

glGenTextures(1, &space_tex);


Теперь мы привязываемся к текстуре фотографии, т.е. делаем ее активной. Для этого служит функция glBindTexture. Первый параметр должен быть \\\\\\\\GL_TEXTURE_2D или GL_TEXTURE_1D. Он показывает, с одномерным или двумерным изображением будем работать. Все примеры здесь касаются двумерных тектур. Для одномерной тектуры я просто не нашел красивого примера. Впрочем, в Red Book есть пример с одномерной текстурой. Там чайник разукрашивают красной лентой. Где взять эти примеры и многое другое смотрите в приложении 'A'. Второй параметр glBindTexture - идентификатор, который мы создали выше при помощи glGenTextures. Теперь добавьте вызов этой функции в main.
glBindTexture(GL_TEXTURE_2D, photo_tex);
Теперь мы должны создать саму текстуру в памяти. Массив байт в структуре AUX_RGBImageRec не является еще текстурой, потому что у текстуры много различных параметров. Создав текстуру, мы наделим ее определенными свойствами. Среди параметров текстуры вы указываете уровень детализации, способ масшабирования и связывания текстуры с объектом. Уровень детализации нужен для наложения текстуры на меньшие объекты, т.е. когда площадь на экране меньше размеров изображения. Нулевой уровень детализации соответствует исходному изображению размером 2nx2m, первый уровень - 2n-1x2m-1, k-ый уровень - 2n-kx2m-k. Число уровней соответствует min(n,m). Для создания текстуры имеется две функции glTexImage[1/2]D и gluBuild[1/2]DMipmaps.
glTexImage2D( gluBuild2DMipmaps(

GLenum target, GLenum target,

GLint lavel, GLint components,

GLint components, GLsizei width,

GLsizei width, GLsizei height,

GLsizei height, GLenum format,

GLint border, GLenum type,

GLenum format, const GLvoid* pixels)

GLenum type,

const GLvoid* pixels)


Основное различие в том, что первая функция создает текстуру одного определенного уровня детализации и воспринимает только изображения , размер которых кратен степени двойки. Вторая функция более гибкая. Она генерирует текстуры всех уровней детализации. Также эта функция не требует, чтобы размер изображения был кратен степени двойки. Она сама сожмет/растянет изображение подходящим образом, хотя возможно окажется, что и не вполне подходящим. Я воспользуюсь функцией glTexImage2D. Первый параметр этой функции должен быть GL_TEXTURE_2D. Второй - уровень детализации. Нам нужно исходное изображение, поэтому уровень детализации - ноль. Третий параметр указывает количество компонентов цвета. У нас изображение хранится в формате RGB. Поэтому значение этого параметра равно трем. Четвертый и пятый параметры - ширина и высота изображения. Шестой - ширина границы; у нас гарницы не будет, поэтому значение этого параметра - ноль. Далее, седьмой параметр - формат хранения пикселей в массиве - GL_RGB и тип - GL_UNSIGNED_BYTE. И наконец, восьмой параметр - указатель на массив данных. Еще вы должны вызвать функцию glPixelStorei и задать, что выравнивание в массиве данных идет по байту. Добавьте следующий код в функцию main.
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

glTexImage2D(GL_TEXTURE_2D, 0, 3,

photo_image->sizeX,

photo_image->sizeY,

0, GL_RGB, GL_UNSIGNED_BYTE,

photo_image->data);


Аналогичный результат можно получить, вставив вызов gluBuild2DMipmaps с параметрами, указанными ниже.
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,

photo_image->sizeX,

photo_image->sizeY,

GL_RGB, GL_UNSIGNED_BYTE,

photo_image->data);
Теперь нужно установить параметры текстуры. Для этого служит функция
glTexParameter[if](GLenum target, GLenum pname, GLenum param)
Первый параметр принимает значение GL_TEXTURE_1D или GL_TEXTURE_2D. Второй - pname - определяетя параметр текстуры, который вы будете изменять. И третий параметр - это устанавливаемое значение. Если вы воспользовались gluBuild2DMipmaps вместо glTexImage2D, то вам не надо устанавливать следующие параметры, т.к. уже сформированы текстуры всех уровней детализации, и OpenGL сможет подобрать текстуру нужного уровня, если площадь объекта не совпадает с площадью текстуры. В противном случае, вы должны добавить следующие строки:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);


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

Еще вы можете установить взаимодействие текстуры с объектом. Тут имеются два режима при использовании трех компонентов цвета. Первый режим, установленный по умолчанию, когда у вас учитывается цвет объекта и цвет текстуры. Результирующий цвет получается перемножением компонентов цвета текстуры на компоненты цвета объекта. Скажем, если цвет текстуры - (r,g,b), а цвет объекта, на который она накладывается, - (r0,g0,b0), то результирующим цветом будет - (r*r0,g*g0,b*b0). В случае, если цвет объекта черный - (0,0,0), то вы не увидите на нем текстуру, так как она вся будет черной. Второй режим взаимодействия, когда цвет объекта не учитывается. Результирующим цветом будет цвет текстуры. Эти параметры можно установить следующим образом.


glTexEnv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)

glTexEnv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)


По умолчанию, как я уже сказал, является режим GL_MODULATE. Теперь сделайте активной текстуру space_tex. И повторите для нее то же самое. На этом заканчивается создание текстуры. Осталось связать координаты текстуры с координатами объекта. Отредактируйте функцию display так:
glEnable(GL_TEXTURE_2D);

glColor3d(1,1,1);


glBindTexture(GL_TEXTURE_2D, space_tex );

glBegin(GL_QUADS);

glTexCoord2d(0,0); glVertex3d(-5,-5, -0.1);

glTexCoord2d(0,1); glVertex3d(-5, 5, -0.1);

glTexCoord2d(1,1); glVertex3d( 5, 5, -0.1);

glTexCoord2d(1,0); glVertex3d( 5,-5, -0.1);

glEnd();
glBindTexture(GL_TEXTURE_2D, photo_tex);

glBegin(GL_QUADS);

glTexCoord2d(0,0); glVertex2d(-4,-4);

glTexCoord2d(0,1); glVertex2d(-4, 4);

glTexCoord2d(1,1); glVertex2d( 4, 4);

glTexCoord2d(1,0); glVertex2d( 4,-4);

glEnd();
glDisable(GL_TEXTURE_2D);
Как вы, наверное, догадались, glTexCoord2d сопоставляет координаты текстуры вершинам четырехугольника. Скажу только, что нижний левый угол текстуры имеет координаты (0,0), а верхний правый - (1,1).

Исходный файл смотрите здесь. Исполняемый файл здесь.




Достарыңызбен бөлісу:
1   2   3   4




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет