Руководство по работе с графической библиотекой OpenGL. Руководство разработано с учетом опыта чтения курса Компьютерная графика
Скачать 0.66 Mb.
|
2. /* условие всегда выполнено и значение в буфере будет равно 1*/ glStencilFunc (GL_ALWAYS, Oxl, Oxffffffff); /* в любом случае заменяем значение в буфере, маски*/ glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); /* выводим геометрию, по которой затем будет отсечена тень*/ RenderPlane(); 3. /* условие выполнено и тест дает истину только если значение в буфере маски равно 1 */ 8.3. Зеркальные отражения 109 glStencilFunc (GL_EQUAL, 0x1, Oxffffffff); /* значение в буфере равно 2, если тень уже выведена */ glStencilOp (GL_KEEP, GL_KEEP, GL_INCR); /* выводим тени */ RenderShadow (); Строго говоря, даже при применении маскирования остаются некоторые проблемы, связанные с работой z-буфера. В частности, некоторые участки теней могут стать невидимыми. Для решения этой проблемы можно немного приподнять тени над плоскостью с помощью модификации уравнения, описывающего плоскость. Описание других методов выходит за рамки данного пособия. 8.3. Зеркальные отражения В этом разделе мы рассмотрим алгоритм построения отражений от плоских объектов. Такие отражения придают большую достоверность построенному изображению и их относительно легко реализовать. Алгоритм использует интуитивное представление полной сцены с зеркалом как составленной из двух: «настоящей» и «виртуальной»— находящейся за зеркалом. Следовательно, процесс рисования отражений состоит из двух частей: 1) визуализации обычной сцены и 2) построения и визуализации виртуальной. Для каждого объекта «настоящей» сцены строится его отраженный двойник, который наблюдатель и увидит в зеркале. Для иллюстрации рассмотрим комнату с зеркалом на стене. Комната и объекты, находящиеся в ней, выглядят в зеркале так, как если бы зеркало было окном, а за ним была бы еще одна такая же комната с тем же объектами, но симметрично отраженными относительно плоскости, проведенной через поверхность 110 Глава 8. Графические алгоритмы на основе OFENGL Рис. 8.1. Зеркальное отражение зеркала. Упрощенный вариант алгоритма создания плоского отражения состоит из следующих шагов: Рисуем сцену как обычно, но без объектов-зеркал. Используя буфер маски, ограничиваем дальнейший вывод проекцией зеркала на экран. Визуализируем сцену, отраженную относительно плоскости зеркала. При этом буфер маски позволит ограничить вывод формой проекции объекта-зеркала. Эта последовательность действий позволит получить убедительный эффект отражения. Рассмотрим этапы более подробно. Сначала необходимо нарисовать сцену как обычно. Не будем останавливаться на этом этапе подробно. Заметим только, что, очищая буферы OpenGL непосредственно перед рисованием, нужно не забыть очистить буфер маски: 8.3. Зеркальные отражения 111 g 1С1 е а г (GL_COLOR_BUFFER_BEr | GL_DEPTH_BUFFTER_BrT | GL_STENCIL_BUFFER_Brr); Во время визуализации сцены лучше не рисовать объекты, которые затем станут зеркальными. На втором этапе необходимо ограничить дальнейший вывод проекцией зеркального объекта на экран. Для этого настраиваем буфер маски и рисуем зеркало glEnable (GL_STENCIL_TEST) ; /* условие всегда выполнено и значение в буфере будет равно 1*/ glStencilFunc(GL_ALWAYS, 1, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); Render Mirror Object (); В результате мы получили: в буфере кадра — корректно нарисованная сцена, за исключением области зеркала; в области зеркала (там, где мы хотим видеть отражение) значение буфера маски равно 1. На третьем этапе нужно нарисовать сцену, отраженную относительно плоскости зеркального объекта. Сначала настраиваем матрицу отражения. Матрица отражения должна зеркально отражать всю геометрию относительно плоскости, в которой лежит объект-зеркало. Ее можно получить, например, с помощью такой функции (попробуйте получить эту матрицу самостоятельно в качестве упражнения): void reflectionmatrix ( GLfloat reflection_matrix [4] [4] , GLfloat plane_point [3] , Glfloat plane_normal [3]) { GLfloat* p; 112 Глава 8. Графические алгоритмы на основе OFENGL GLfloat* v; float pv; GLfloat* p = ( Glfloat *) plane_point ; Glfloat* v = ( Glfloat *) plane_normal; float pv = p[0]*v[0] + p[l]*v[l] + p[2]*v[2]; reflect reflect reflect reflect reflect reflect reflect reflect reflect reflect reflect reflect on _mat r on _mat r on _mat r on _mat r on _mat r on _mat r on _mat r on _mat r on _mat r on _mat r on _mat r on matr 2 * v[0] * v[0] * v[0] * v[l]; = 1 -= - 2 = - 2 * v[0 * v :2]; = 2 * pv * v [0] ; = - 2 * v[0] * v[l]; = 1- 2 * v[l] * v[l]; = - 2 * v[l] * v[2]; = 2 * pv * v [ 1 ] ; = - 2 * v[0] * v[2]; = - 2 * v[l] * v[2]; = 1 - 2 * v[2] * v[2] ; = 2 * pv * v [ 2 ] ; reflection _ matrix reflection _ matrix reflection _ matrix reflection matrix = 0 = 0 = 0 = 1 } Настраиваем буфер маски на рисование только в областях, где значение буфера равно 1: /* условие выполнено и тест дает истину только если значение в буфере маски равно 1 */ glStencilFunc (GL_EQUAL, Oxl, Oxffffffff); /* ничего не. меняем в буфере */ glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); и рисуем сцену еще раз (без зеркальных объектов) 8Jh. Контрольные вопросы 113 glPushMatrix (); glMultMatrixf (( float *) reflection_matrix ) ; RenderScene (); glPopMatrix () ; Наконец, отключаем маскирование: g 1D i s a b 1 e (GL_STENCIL_TEST); После этого можно опционально еще раз вывести зеркальный объект, например, с альфа-смешением — для создания эффекта замутнения зеркала и т.д. Обратите внимание, что описанный метод корректно работает, только если за зеркальным объектом нет других объектов сцены. Поэтому существует несколько модификаций этого алгоритма, отличающихся последовательностью действий и имеющих разные ограничения на геометрию. 8.4. Контрольные вопросы В результате чего возникает эффект ступенчатости изображения? Опишите алгоритм устранения ступенчатости. Почему в OpenGL нет встроенной поддержки построения теней? Кратко опишите предложенный метод визуализации зеркальных объектов. Почему он не работает, если за зеркалом находятся другие объекты сцены? Что будет отражаться в этом случае? Подумайте, как обойти это ограничение? Глава 9. Оптимизация программ 9.1. Организация приложения На первый взгляд может показаться, что производительность графических приложений, основанных на OpenGL, определяется в первую очередь производительностью реализации самой библиотеки. Это верно, однако организация всего приложения также очень важна. |