OpenGL в Delphi

       

Простейший пример на получение эффекта зеркального отражения




Код воспроизведения следующий:

procedure TfrmGL. WMPaint(var Msg: TWMPaint);
var
ps: TPaintStruct; Begin
BeginPaint(Handle, ps);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BOFFER_BIT);
glLoadIdentity;
glTranslatef(0, -0. 5, -4);
// здесь пол рисуется только в буфер трафарета
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, $FFFF); // пол рисовать всегда
glColorMask(FALSE, FALSE, FALSE, FALSE);
glDisable(GL_DEPTH_TEST);
DrawFloor; // собственно пол
// восстанавливаем нормальные установки
glColorMask(TRUE, TRUE, TRUE, TRUE);
glEnable(GL_DEPTH_TEST);
// отражение рисуется только там, где значение в буфере
// трафарета равно единице
glStencilFunc(GL_EQUAL, 1, $FFFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// рисуем отраженную сцену
glPushMatrix;
glScalef(l, -1, 1); // переворачиваем по оси Y
DrawObjects;
glPopMatrix;
// рисуем настоящий пол, полупрозрачным, чтобы можно было увидеть
// отраженные объекты
glDepthMask(FALSE);
DrawFloor;
glDepthMask(TRUE);
// для воспроизведения подлинной системы отключаем буфер трафарета,
// иначе она также будет обрезаться областью пола
glDisable(GL_STENCIL_TEST);
DrawObjects;
glFinish;
SwapBuffers(DC);
EndPaint(Handle, ps);
Angle: = (Angle + 2) mod 360; // для поворота в следующем кадре
InvalidateRect(Handle, nil, False);
end;

Все вроде просто, но если вы внимательно посмотрите на пример, то обнаружите мою небольшую хитрость: окно приложения нельзя изменять в размерах.
Сделал я это специально, иначе при сужении окна по вертикали, начинает выглядывать фальшивая система объектов за границей пола.
Ответ на вопрос "а почему?" состоит в том, что третий аргумент команды glstencilOp при подготовке вывода фальшивой системы имеет не совсем
подходящее значение. Этот аргумент должен быть GL__ZERO или GL_INCR, но при таких значениях на поверхности отраженных объектов появляется непрошенный узор.
Мы уже встречали эту проблему и знаем, что она связана с наложением альфа-компонентов для замкнутых фигур, знаем также, что она легко решается сортировкой поверхностей.
Привожу окончательный вариант соответствующего фрагмента кода; можете убедиться, что после внесения изменений все работает совершенно корректно:

glStencilFunc(GL_EQUAL, I, $FFFF) ;
glStencilOp(GLJCEEP, GLJCEEP, GL_INCR);// здесь изменен третий аргумент
glPushMatrix;
glScalefd, -1, 1);
glCullFace (GL_FRONT);//сортировка поверхностей, внутренняя и внешняя
glEnable (GL_CULL_FACE); // поверхности воспроизводятся отдельно
DrawObjects;
glCullFace (GL_BACK);
DrawObjects;
glDisable (GL_CULL_FACE);
glPopMatrix;

Познакомимся теперь, как можно создавать эффект многократного отражения. Рисунок 4.48 демонстрирует работу следующего примера, проекта из подкаталога Ех74: на стенах комнаты висят два зеркала, одно напротив другого, объекты сцены многократно отражаются в этих зеркалах.



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