Шаг 41 - Списки и Свет

В этом шаге посмотрим как сделать две вещи:

Чесно говоря, я устал от этого MFC, захотелось сделать маленькую и шуструю программку. Поэтому я сделал этот шаг на API. Кроме того, как мне кажется, на MFC достаточно сложно сделать программу с максимальной производительностью. (собствено говоря ни одна игровая программа не использует MFC, OWL, VCL и т.д.) Хотя все это не имеет значения. Главное - это правильно подойти к поставленной задаче. Делать CAD систему на API неразумно, равно как и писать 3D шутер с MFC. Так что лучше всего уметь и так и так ;)

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

Давайте посмотрим как создать список:

void CalculateList()
{
	CUBE_LIST = glGenLists(1);
	glNewList(CUBE_LIST, GL_COMPILE);
	DrawCube();
	glEndList();
}

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

Например, запись CUBE_LIST = glGenLists(5) зарезервирует для вас 5 номеров списков и первый номер попадет в переменную CUBE_LIST. Посмотрите код функции DrawCube, он такой же как и в "Шаг 37 - "Симпатишный" кубик". Просто все команды рисования куба заносятся в список. Я выделил эти команды в отдельную функцию для того, чтобы в будущем вернуться к этому примеру (доработав его, конечно) и посмотреть количество fps в режиме со списками и без.

Но это потом. Сейчас посмотрим как использовать этот список:

GLvoid Draw()
{
	static GLfloat rot = 0.0f;

	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glPushMatrix();
	glColor3f (1.0, 1.0, 0.5);
	glCallList(CUBE_LIST);
	glRotatef(rot, 0.0f, 1.0f, 1.0f);

	glPushMatrix();
	glLightfv(GL_LIGHT0, GL_POSITION, light0_Position);
	glTranslatef(light0_Position[0],light0_Position[1],light0_Position[2]);
	glScalef(0.1f, 0.1f, 0.1f);
	glCallList(CUBE_LIST);
	glPopMatrix();

	rot+=1.0f;
	glPopMatrix();

	SwapBuffers(hDC);
}

В начале работы мы заталкиваем в стек текущую матрицу glPushMatrix(), чтобы не портить её ;). Устанавливаем цвет примитивов - glColor3f (1.0, 1.0, 0.5). Вызываем список для рисования большого куба - glCallList(CUBE_LIST). Поворачиваем модельную систему координат на угол rot относительно осей Y и Z. Опять прячем в стек уже повернутую систему координат - glPushMatrix().

Устанавливаем источник света в заданную позицию при помощи оператора:

glLightfv(GL_LIGHT0, GL_POSITION, light0_Position)
.

Переносим систему координат в ту точку где стоит источник света:

glTranslatef(light0_Position[0],light0_Position[1],light0_Position[2])

Масштабируем систему координат, т.е. уменьшаем в 10 раз по всем осям функцией glScalef(0.1f, 0.1f, 0.1f).
Вызываем список, т.е. опять рисуем кубик, но меньшего размера и в другом месте :) (glCallList(CUBE_LIST))
Восстанавливаем матрицу (glPopMatrix())
Увеличиваем угол (rot+=1.0f)
И восстанавливаем исходную матрицу (glPopMatrix())

Вот и все дела. Единственный момент, который мы еще не видели раньше - положение источника света. Все характеристики источников света (не только положение, но и его тип, интенсивность и т.д.) задаются при помощи одной команды glLightfv, где 1-й аргумент это имя источника, второй говорит какое свойство источника будет задано 3-м аргументом. В нашем случае есть глобальный массив light0_Position и он определяет где будет находится источник.

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

Ну вот. Посмотрите на кубики, а я пока напишу текст к следующему шагу, где будет 2 источника света ;)


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