Шаг 44 - Материалы

В этом шаге мы посмотрим простенький пример работы с материалами.

Вообще-то понятие материала и источника света - это основа 3D графики (да и не только 3D, и не только графики ;) ).

Посмотрим каждый их них в отдельности:

  1. Свет:
    • может быть рассеяным, параллельно направленым, прожектором
    • может излучаться в определенной длинне волны, например, только красный спектр
  2. Материал:
    • обладает различными оптическими свойствами, т.е. может рассеивать, пропускать, отражать или поглащать свет определенной длины волны
    • предмет из определенного материала может быть покрашен определенной краской

Комбинаций свойств материала, источника света и окраски объекта может быть множество. В "Шаг 42 - Два источника света" мы задавали интенсивность источника света. Делали это так:

GLfloat light1_Intensity[4] = {1.0f, 1.0f, 1.0f, 1.0f};

Попробуйте теперь уменьшить красную составляющую на 1/2. Что получилось увидите сами. Объяснение простое. На источник света как бы наложен фильтр, который пропускает только свет определенного спектра.

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

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

GLuint m_lstCube;
GLfloat m_matDiffuse[] = {0.0f, 0.0f, 0.0f};

Первая - это идентификатор списка, в котором будет содержаться куб. Второй - свойства материала рассеивать свет. Каждый элемент массива определяет рассеивает ли этот материал определенную длину волны света.

Теперь зададим это свойство:

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m_matDiffuse);

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

Вот и все. Свойства материала установлены, источник света включен. Все работает. Просто ради наглядности я добавил в обработчик от клавиатуры WM_KEYDOWN обработчики от кнопочек r,g,b.

Нажимая на них можно изименять свойство материала рассеивать ту или иную составляющую света.

case WM_KEYDOWN:
	if(wParam == VK_ESCAPE) SendMessage(hWnd, WM_CLOSE, 0, 0);
	if(wParam == 82)	// r
	{
		if(red<=1.0f)
			red += 0.1f;
		else
			red = 0.0f;
	}
	if(wParam == 71)	// g
	{
		if(green <= 1.0f)
			green += 0.1f;
		else
			green += 0.0f;
	}
	if(wParam == 66)	// b
	{
		if(blue <= 1.0f)
			blue += 0.1f;
		else
			blue = 0.0f;
	}
	if(wParam == 76)	// l (можно отключить и включить источник света)
	{
		if(light)
		{
			light=FALSE;
			glDisable(GL_LIGHTING);
			glDisable(GL_LIGHT0);
		} else {
			light=TRUE;
			glEnable(GL_LIGHTING);
			glEnable(GL_LIGHT0);
		}
	}

	if(wParam == 67)	// c (можно включить или выключить окраску объекта)
	{
		if(color)
		{
			color=FALSE;
			glEnable(GL_COLOR_MATERIAL);
		} else {
			color=TRUE;
			glDisable(GL_COLOR_MATERIAL);
		}
	}

	m_matDiffuse[0] = red;
	m_matDiffuse[1] = green;
	m_matDiffuse[2] = blue;
	glMaterialfv(GL_FRONT, GL_DIFFUSE, m_matDiffuse);

	break;

И еще одна маленькая деталь. Я немного поменял аргументы в команде установки вида:

GLvoid Resize(GLsizei w, GLsizei h)
{
	if(w>=h)
		glViewport ((w-h)/2, 0, (GLsizei) h, (GLsizei) h); 
	if(w<h)
		glViewport (0, (h-w)/2, (GLsizei) w, (GLsizei) w); 

	glMatrixMode (GL_PROJECTION);
	glLoadIdentity();
	glFrustum (-1, 1, -1, 1, 4, 15);
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity();

	glTranslatef(0.0, 0.0, -12.0);
	glRotatef(30.0, 1.0, 0.0, 0.0);
	glRotatef(70.0, 0.0, 1.0, 0.0);
}

Теперь куб - это действительно куб, а не что-то параллелепипедное.

Забыл один небольшой, но важный момент. В тексте я писал слово рассеивать, очень хотелось написать слово отражать, но дело в том, что слово diffuse действительно переводится как рассеивать. По логике работы приложение, нажимая, например, на букву "r" мы как бы говорим OpenGL-ю, что наш материал НЕ БУДЕТ рассеиваить красный свет. У материала есть так же свойство отражения света, т.е. как бы качество полировки поверхности, поэтому не стоит путать diffuse со specular, но об этом в следующем шаге.


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