Файл: графическая библиотека opengl.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 09.06.2020

Просмотров: 1713

Скачиваний: 4

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

 71

строить

 

всю

 

сцену

даже

 

если

 

проблема

 

отсечения

 

теней

 

по

 

границе

 

будет

 

решена

 

Тени

 

обычно

 

имеют

 

размытые

 

границы

а

 

в

 

приведенном

 

алгоритме

 

они

 

всегда

   

имеют

 

резкие

 

края

Частично

 

избежать

 

этого

 

позволяет

 

расчет

 

теней

 

из

 

нескольких

   

источников

 

света

расположенных

 

рядом

 

и

 

последующее

 

смешение

 

результатов

Имеется

 

решение

 

первой

 

и

 

второй

 

проблемы

Для

 

этого

 

используется

 

буфер

 

маски

 (

см

п

. 6.3) 

Итак

задача

 – 

отсечь

 

вывод

 

геометрии

  (

тени

в

 

данном

 

случае

по

 

границе

 

некоторой

 

произвольной

 

области

 

и

 

избежать

  "

двойного

 

смешения

". 

Общий

 

алгоритм

 

решения

 

с

 

использованием

 

буфера

 

маски

 

таков

1. 

Очищаем

 

буфер

 

маски

 

значением

 0 

2. 

Отображаем

 

заданную

 

область

 

отсечения

устанавливая

 

значения

 

в

  

буфере

 

маски

 

в

 1 

3. 

Рисуем

 

тени

 

в

 

тех

 

областях

где

 

в

 

буфере

 

маски

 

установлены

 

значения

 1. 

Если

 

тест

 

проходит

устанавливаем

 

в

 

эти

 

области

 

значение

 2. 

Теперь

 

рассмотрим

 

эти

 

этапы

 

более

 

подробно

1. 

/* 

очищаем

 

буфер

 

маски

*/ 

glClearStencil(0x0);  

/* 

включаем

 

тест

 */ 

glEnable(GL_STENCIL_TEST);  

 

2. 

/* 

условие

 

всегда

 

выполнено

 

и

 

значение

 

в

 

буфере

 

будет

 

равно

 1*/ 

glStencilFunc (GL_ALWAYS, 0x1, 0xffffffff); 

/* 

в

 

любом

 

случае

 

заменяем

 

значение

 

в

 

буфере

 

маски

*/ 

glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);  

/* 

выводим

 

геометрию

по

 

которой

 

затем

 

будет

 

отсечена

 

тень

*/ 

RenderPlane(); 
 

3. 


background image

 72

/* 

условие

 

выполнено

 

и

 

тест

 

дает

 

истину

 

только

 

если

 

значение

 

в

 

буфере

 

маски

 

равно

 1 */ 

glStencilFunc (GL_EQUAL, 0x1, 0xffffffff); 
/* 

значение

 

в

 

буфере

 

равно

 2,

если

 

тень

 

уже

 

выведена

 */ 

glStencilOp (GL_KEEP, GL_KEEP, GL_INCR); 

/* 

выводим

 

тени

 */ 

RenderShadow(); 
 

Строго

 

говоря

даже

 

при

 

применении

 

маскирования

 

остаются

 

некоторые

 

проблемы

связанные

 

с

 

работой

 z-

буфера

В

 

частности

некоторые

 

участки

 

теней

 

могут

 

стать

 

невидимыми

Для

 

решения

 

этой

 

проблемы

 

можно

 

немного

 

приподнять

 

тени

 

над

 

плоскостью

 c 

помощью

 

модификации

 

уравнения

описывающего

 

плоскость

Описание

 

других

 

методов

 

выходит

 

за

 

рамки

 

данного

 

пособия

7.3. 

Зеркальные

 

отражения

 

В

 

этом

 

разделе

 

мы

 

рассмотрим

 

алгоритм

 

построения

 

отражений

 

от

 

плоских

 

объектов

Такие

 

отражения

 

придают

 

б

ó

льшую

 

достоверность

 

построенному

 

изображению

 

и

 

их

 

относительно

 

легко

 

реализовать

.  

Алгоритм

 

использует

 

интуитивное

 

представление

 

полной

 

сцены

 

с

 

зеркалом

 

как

 

составленной

 

из

 

двух

: «

настоящей

» 

и

  «

виртуальной

» – 

находящейся

 

за

 

зеркалом

Следовательно

процесс

 

рисования

 

отражений

 

состоит

 

из

 

двух

 

частей

: 1) 

визуализации

 

обычной

 

сцены

 

и

 2) 

построения

 

и

 

визуализации

 

виртуальной

Для

 

каждого

 

объекта

 

«

настоящей

» 

сцены

 

строится

 

его

 

отраженный

 

двойник

который

 

наблюдатель

 

и

 

увидит

 

в

 

зеркале

.  

 

 

 

 

 

 

 

Рис

. 9 

Зеркальное

 

отражение

 

Зеркало

 

Положение

 

наблюдателя

 

Виртуальный

 

объект

 

Объект

 


background image

 73

Для

 

иллюстрации

 

рассмотрим

 

комнату

 

с

 

зеркалом

 

на

 

стене

Комната

 

и

 

объекты

находящиеся

 

в

 

ней

выглядят

 

в

 

зеркале

 

так

как

 

если

 

бы

 

зеркало

 

было

 

окном

а

 

за

 

ним

 

была

 

бы

 

еще

 

одна

 

такая

 

же

 

комната

 

с

 

тем

 

же

 

объектами

но

 

симметрично

 

отраженными

 

относительно

 

плоскости

проведенной

 

через

 

поверхность

 

зеркала

.  

Упрощенный

 

вариант

 

алгоритма

 

создания

 

плоского

 

отражения

 

состоит

 

из

 

следующих

 

шагов

1. 

Рисуем

 

сцену

 

как

 

обычно

но

 

без

 

объектов

-

зеркал

2. 

Используя

 

буфер

 

маски

ограничиваем

 

дальнейший

 

вывод

 

проекцией

 

зеркала

 

на

 

экран

3. 

Визуализируем

 

сцену

отраженную

 

относительно

 

плоскости

 

зеркала

При

 

этом

 

буфер

 

маски

 

позволит

 

ограничить

 

вывод

 

формой

 

проекции

 

объекта

-

зеркала

Эта

 

последовательность

 

действий

 

позволит

 

получить

 

убедительный

 

эффект

 

отражения

Рассмотрим

 

этапы

 

более

 

подробно

Сначала

 

необходимо

 

нарисовать

 

сцену

 

как

 

обычно

Не

 

будем

 

останавливаться

 

на

 

этом

 

этапе

 

подробно

Заметим

 

только

что

очищая

 

буферы

 OpenGL 

непосредственно

 

перед

 

рисованием

нужно

 

не

 

забыть

 

очистить

 

буфер

 

маски

:  

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT| 
        GL_STENCIL_BUFFER_BIT); 

 

Во

 

время

 

визуализации

 

сцены

 

лучше

 

не

 

рисовать

 

объекты

которые

 

затем

 

станут

 

зеркальными

На

 

втором

 

этапе

 

необходимо

 

ограничить

 

дальнейший

 

вывод

 

проекцией

 

зеркального

 

объекта

 

на

 

экран

.  

Для

 

этого

  

настраиваем

 

буфер

 

маски

 

и

 

рисуем

 

зеркало

  

glEnable(GL_STENCIL_TEST); 

/* 

условие

 

всегда

 

выполнено

 

и

 

значение

 

в

 

буфере

 

будет

 

равно

 1*/ 

glStencilFunc(GL_ALWAYS, 1, 0); 
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); 
 
RenderMirrorObject(); 

 


background image

 74

В

 

результате

 

мы

 

получили

 

в

 

буфере

 

кадра

 – 

корректно

 

нарисованная

 

сцена

за

 

исключением

 

области

 

зеркала

 

в

 

области

 

зеркала

  (

там

где

 

мы

 

хотим

 

видеть

 

отражение

значение

 

буфера

 

маски

 

равно

 1. 

На

 

третьем

 

этапе

 

нужно

 

нарисовать

 

сцену

отраженную

 

относительно

 

плоскости

 

зеркального

 

объекта

Сначала

 

настраиваем

 

матрицу

 

отражения

Матрица

 

отражения

 

должна

 

зеркально

 

отражать

 

всю

 

геометрию

 

относительно

 

плоскости

в

 

которой

 

лежит

 

объект

-

зеркало

Ее

 

можно

 

получить

например

с

 

помощью

 

такой

 

функции

  (

попробуйте

 

получить

 

эту

 

матрицу

 

самостоятельно

 

в

 

качестве

 

упражнения

): 

void  

reflectionmatrix

(GLfloat reflection_matrix[4][4],  

                 GLfloat plane_point[3],  
                 Glfloat plane_normal[3]) 

  GLfloat* p; 
  GLfloat* v; 
  float pv; 
 
  GLfloat* p = (Glfloat*)plane_point; 
  Glfloat* v = (Glfloat*)plane_normal; 
  float pv = p[0]*v[0]+p[1]*v[1]+p[2]*v[2]; 
   
  reflection_matrix[0][0] = 1 - 2 * v[0] * v[0]; 
  reflection_matrix[1][0] = - 2 * v[0] * v[1]; 
  reflection_matrix[2][0] = - 2 * v[0] * v[2]; 
  reflection_matrix[3][0] = 2 * pv * v[0]; 
   
  reflection_matrix[0][1] = - 2 * v[0] * v[1]; 
  reflection_matrix[1][1] = 1- 2 * v[1] * v[1]; 
  reflection_matrix[2][1] = - 2 * v[1] * v[2]; 
  reflection_matrix[3][1] = 2 * pv * v[1]; 
   
  reflection_matrix[0][2] = - 2 * v[0] * v[2]; 

  reflection_matrix[1][2] = - 2 * v[1] * v[2]; 
  reflection_matrix[2][2] = 1 - 2 * v[2] * v[2]; 
  reflection_matrix[3][2] = 2 * pv * v[2]; 
   
  reflection_matrix[0][3] = 0; 
  reflection_matrix[1][3] = 0; 


background image

 75

  reflection_matrix[2][3] = 0; 
  reflection_matrix[3][3] = 1; 

 

Настраиваем

 

буфер

 

маски

 

на

 

рисование

 

только

 

в

 

областях

где

 

значения

 

буфера

 

равно

 1: 

/* 

условие

 

выполнено

 

и

 

тест

 

дает

 

истину

 

только

 

если

 

значение

 

в

 

буфере

 

маски

 

равно

 1 */ 

glStencilFunc (GL_EQUAL, 0x1, 0xffffffff); 
/* 

ничего

 

не

 

меняем

 

в

 

буфере

 */ 

glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); 

 

и

 

рисуем

 

сцену

 

еще

 

раз

 (

без

 

зеркальных

 

объектов

glPushMatrix(); 
glMultMatrixf((float *)reflection_matrix); 
RenderScene(); 
glPopMatrix(); 
 

Наконец

отключаем

 

маскирование

 

glDisable(GL_STENCIL_TEST); 
 

После

 

этого

 

можно

 

опционально

 

еще

 

раз

 

вывести

 

зеркальный

 

объект

например

с

 

альфа

-

смешением

 – 

для

 

создания

 

эффекта

 

замутнения

 

зеркала

 

и

 

т

.

д

Обратите

 

внимание

что

 

описанный

 

метод

 

корректно

 

работает

только

 

если

 

за

 

зеркальным

 

объектом

 

нет

 

других

 

объектов

 

сцены

Поэтому

 

существует

 

несколько

 

модификаций

 

этого

 

алгоритма

отличающихся

 

последовательностью

 

действий

 

и

 

имеющих

 

разные

 

ограничения

 

на

 

геометрию

.  

Контрольные

 

вопросы

 

1. 

В

 

результате

 

чего

 

возникает

 

эффект

 

ступенчатости

 

изображения

Опишите

 

алгоритм

 

устранения

 

ступенчатости

2. 

Почему

 

в

 OpenGL 

нет

 

встроенной

 

поддержки

 

построения

 

теней

3. 

Кратко

 

опишите

   

предложенный

 

метод

 

визуализации

 

зеркальных

 

объектов

.  

Почему

 

он

 

не

 

работает

если

 

за

 

зеркалом

 

находятся

 

другие

 

объекты

 

сцены

Что

 

будет

 

отражаться

 

в

 

этом

 

случае

Подумайте

как

 

обойти

 

это

 

ограничение