Шаг 13 - Текстуры

Ну вот и свершилось наконец-то. Я родил шаг номер 13. Хммм... цифра наводит на мысли ;)

Но не будем о грустном. Как я и обещал когда-то раньше, в этом шаге объекты на экране получат текстуру.

Сначала я хотел пойти в том же ключе, что и раньше, т.е. 2 объекта, текстура на одном, текстура на другом, стереосистема справа, стереосистема слева и ... и потом решил, что все это не интересно. Решил потратить время на "прикольную" текстуру. Начал искать, полез на свою станцию и нашел забавный живой телевизор, он, оказывается, входит в комплект поставки Irix 6.2 от SGI. Но вот проблема встала - телевизор там в видео ролике. И решил я, что надо динамическую текстурку слепить, да посмотреть что из этого получится. Слепил, посмотрел, ничего, жить будет, для учебных целей пойдет.

Прежде всего бросьте читать эти буковки и посмотрите код. Мне кажется и объяснять-то там нечего, но раз уж назвался ... то я полез в печку.

И так - объяснения.

Программка практически копирует предыдущие. Т.е. берем опять скелет win32 приложения (проще всего взять от PiraCube), вырезаем оттуда все лишнее и вставляем все нужное, куда уж проще ;). Ну, а если серьезно, то изменения такие:

В глобальных переменных:

#define FRAME_RATE 7  
Это предельное значение счетчика LoopCount. Нужен он потому, что моя лень победила и мне не хотелось писать код, который бы менял текстуру 25 раз в секунду, т.е. как в TV. Поэтому, если у вас ролик крутится медленно или быстро, то можно поменять эту цыфирьку и станет лучше (может быть ;) )
BOOL Fm;
Сие опять моя лень, т.е. просто булева переменная, по изменению которой мы переключаемся на новый элемент массива текстур
int LoopCount;
Об этом "левом" счетчике я уже говорил. Поместил я его в цикл while(1)
GLint TexNum;

А это собственно и сам номер картинки.

В функциях:

Изменения претерпела функция LoadGLTexture, сейчас она выглядит так:

GLvoid LoadGLTexture(GLvoid)
{
	int i;
	char buffer[30];
	AUX_RGBImageRec *txtre[12];

	for(i=1; i<=12; i++)
	{
		sprintf(buffer,"./Images/0%d.bmp",i);
		txtre[i-1] = auxDIBImageLoad(buffer);

		glBindTexture (GL_TEXTURE_2D, i);
		glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		glTexImage2D(GL_TEXTURE_2D, 0, 3, txtre[i-1]->sizeX, txtre[i-1]->sizeY,
			0, GL_RGB, GL_UNSIGNED_BYTE, txtre[i-1]->data);
	}
}

В начале объявляется массив из 12 указателей на картинки, которые мы загрузим из bmp файлов, а далее в цикле загружаем текстуры в буфер текстур и настраиваем свойства. Я думаю, что перечислять назначение всех функций и их аргументы, это просто повторять MSDN, но в по сути происходит следующее - glBindTexture как бы индексирует текстуру в буфере текстур, glPixelStorei - устанавливает режим pixel storage, glTexParameteri и glexEnvf - устанавливают многочисленные параметры текстур, посмотрите MSDN, его (MSDN) профи пишут, не в пример мне. Ну, а glTexImage2D собственно загружает текстуру.

В Initial добавился вызов функции LoadGLTexture. Изменения в Draw:

glEnable (GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,TexNum);
Соответственно включают режим текстурирования и выбирают текстуру по номеру из тех, что лежат в буфере.
glBegin(GL_QUADS);
glNormal3f(0.0, 0.0, -1.0);
glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, -1.0f);

glNormal3f(0.0, 0.0, 1.0);
glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

glNormal3f(1.0, 0.0, 0.0);
glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f);

glNormal3f(-1.0, 0.0, 0.0);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

glNormal3f(0.0, 1.0, 0.0);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

glNormal3f(0.0, -1.0, 0.0);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glEnd();

glDisable(GL_TEXTURE_2D);

Xrot += 0.1f;
Yrot += 0.2f;
Zrot += 0.25f;

if(Fm)
{
	TexNum++;
	if(TexNum == 13)
		TexNum = 1;
	Fm = FALSE;
}

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

И последнее изменение касается WinMain:

LoopCount++;
if(LoopCount >= FRAME_RATE)
{
	Fm = TRUE;
	LoopCount = 0;
}

Draw();
SwapBuffers(hDC);

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

И последнее - не забудте в настройке проекта добавить библиотеки: opengl32.lib; glu32.lib; glaux.lib;.


Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Kirill V. Ratkin - 06.03.2000