Baner
; В начало ; Новости ; Теория ; Ресурсы ; Ссылки ; Форум ; Почта ;
Математика и физика
2D графика

   DirectDraw:
3D графика

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

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

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

	glTranslatef(0,0,-2);	
	glEnable(GL_STENCIL_TEST); //Включаем буффер трафарета
	glClear(GL_STENCIL_BUFFER_BIT);	//Очищаем
	//При прорисовке фрагмента для трафарета
	//устанавливаем значение 1
	glStencilOp(GL_INCR, GL_INCR, GL_INCR);
	//В любом случае разрешаем прорисовку фрагмента
	glStencilFunc(GL_ALWAYS, 1, 1);
	//Разрешаем рисовать только в буффере трафарета
	glColorMask(FALSE,FALSE,FALSE,FALSE);
	glDepthMask(FALSE);
	//Рисуем пол в буффер трафарета
	glBegin(GL_QUADS);		
		glVertex3f(-5, -5, 0);
		glVertex3f( 5, -5, 0);
		glVertex3f( 5,  5, 0);
		glVertex3f(-5,  5, 0);
	glEnd();
	//Разрешаем рисовать везде
	glDepthMask(TRUE);
	glColorMask(TRUE,TRUE,TRUE,TRUE);
	//Разрешаем прорисовку фрагмента только если
	//трафарет в этом месте равен 1
	glStencilFunc(GL_EQUAL, 1, 1);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
Теперь у нас есть загатовка, которая разрешает рисовать только в тех местах, где будет находиться отражающая поверхность. То что нужно! Рисуем эмуляцию отражения, т.е сцену вверх ногами:
	glPushMatrix(); //Запоминаем ситуацию
	glTranslatef(0,0,-2);
	glScalef(1,1,-1); //Переворачиваем сцену вверх ногами
	glRotatef((float)pScene->Phase, 0, 1, 1);
	glRotatef(2*(float)pScene->Phase, 1, 0, 0);
	glCallList(LS_FIGURE);
	glPopMatrix(); //Восстанавливаем ситуацию
	glDisable(GL_STENCIL_TEST); //Трафарет больше не нужен
Теперь необходимо нарисовать само псевдо-зеркало. Просто рисуем полупрозрачную поверхность, при этом чем больше показатель непрозрачности, тем хуже будет отражать зеркало, например для лужи лучше взять 0.3f, а для стола 0.7f. Если вы используете поверхность с текстурой не забудьте вызвать glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) для возможности использования прозрачности.
	glEnable(GL_TEXTURE_2D);	
	m_floorTex.Bind();	
	glBegin(GL_QUADS);
		glColor4f(1,1,1, 0.5f);
		glNormal3f(0,0,1);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-5, -5, 0);
		glTexCoord2f(3.0f, 0.0f); glVertex3f( 5, -5, 0);
		glTexCoord2f(3.0f, 3.0f); glVertex3f( 5,  5, 0);
		glTexCoord2f(0.0f, 3.0f); glVertex3f(-5,  5, 0);
	glEnd();	
	glDisable(GL_TEXTURE_2D);
Дело осталось за малым нарисовать оригинал:
	glPushMatrix();
	glTranslatef(0,0,4);
	glRotatef((float)pScene->Phase, 0, 1, 1);
	glRotatef(2*(float)pScene->Phase, 1, 0, 0);
	glCallList(LS_FIGURE);
	glPopMatrix();
Все изображение создано!

Примечание №1: Если зеркало не расположено в одной из ортогональных плоскостей вместо glScalef(1,1,-1) используйте поворот на удвоеный угол между зеркалом и ортогональной плоскостью.
Примечание №2: Использование текстур на прозрачной поверхности довольно дорогое (в плане скорости) удовольствие. Два раза рисовать одно и то же тоже получается не очень быстро. А потому старайтесь использовать отражение с умом, а то тормозить начнет.
Примечание №3: Вместо текстур на прозрачной поверхности лучше используйте текстуры со своим собственным, готовым Alpha каналом.


MirrorDemo Ну и взавершении, конечно же, демка плоского зеркала.

Cкачать демку.[28 Kb]
Cкачать исходники.[40 Kb]

Используются технологии uCoz