OpenGL в Delphi

       

Получение тени с помощью специальных средств библиотеки OpenGL




Сцена воспроизводится для каждого кадра два раза, над полом окрашенной, под полом - бесцветной.
Для получения сероватой тени от объектов сцены используется смешение цветов и буфер трафарета. Рассмотрим, как это делается.
Параметры, задаваемые для смешения цветов, традиционны:

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Буфер трафарета заполняется нулями до рисования тени, а когда рисуется тень, значение в буфере трафарета увеличивается для каждого пиксела, где она присутствует:

glClearStencil(0);
glStencilOp(GL_INCR, GL_INCR, GL_INCR);
glStencilFunc(GL_EQUAL, 0, $FFFFFFF);

Тестирование буфера трафарета используется для воспроизведения только тех пикселов, где значение в буфере трафарета равно нулю; поскольку значение увеличивается, то соответствующие пикселы исключаются из дальнейшего использования.
В результате каждый пиксел тени используется только один раз, чтобы тень получалась однотонной.
При нажатии на клавишу 'С' можно отключать использование буфера трафарета, в этом случае некоторые участки тени становятся темнее из-за того, что при смешении цвета значение альфа-компонента удваивается при наложении объектов. Булевская переменная usestencil является флагом, задающим режим использования буфера трафарета.
Для проекции объектов на плоскость пола используется пользовательская Матрица проекции с нулем на диагонали, чтобы проецировать Y-координату в нуль:

mtх[0,0] := 1.0;
mtx[1,1] := 0;
totx[2,2] := 1.0;
totх[3,3] := 1.0;

Поскольку объекты будут рисоваться дважды, код для их воспроизведения вынесен в отдельную процедуру DrawScene
Теперь перейдем непосредственно к коду кадра:

// рисуем пол, источник света отключаем, иначе пол чересчур темный
glPushMatrix;
glDisable (GL_LIGHTO);
glDisable (GL_LIGHTING);
glColor3f(0.8, 0.8, 1) ;
glBegin(GL_QUADS);
glVertex3f(-0.5, -0.5, 0.5);
glVertex3f(0.5, -0.5, 0.5);
glVertexSf(0.5, -0.5, -0.5);
glVertex3f(-0.5, -0.5, -0.5);
glEnd;
glEnable (GL_LIGHTING); glEnable (GL_LIGHTO);
glPopMatrix;
// рисуем объекты над полом, в красном цвете
glPushMatrix;
glColor3f(1, 0, 0);
glRotatef(Angle, 1, 1, 1) ;
DrawScene;
glPopMatrix;
// рисуем тень
If useStencil then begin
// используется ли буфер трафарета
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
end;
// проецируем объекты на пол
glPushMatrix;
glColor4f(0, 0, 0, 0.3); // цвет объектов задаем черным
glTranslatef(0, -0.5, 0);
glMultMatrixf(Smtx); // для корректной проекции на плоскость пола
glRotatef(Angle, 1, 1, 1);
glDisable(GL_DEPTH_TEST); // отключаем буфер глубины
DrawScene; // рисуем фальшивую сцену под полом
glEnable(GL_DEPTH_TEST); // возвращаем обычный режим
glPopMatrix; glDisable(GL_STENCIL_TEST);

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



Содержание раздела