Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Программирование графики > Сбой буфера глубины?


Автор: ksvsvk 26.07.18, 05:47
Из-за сбоя предыдущей темы, повторяю.

Есть процедура, строящая помещение с зеркалами. Для краткости освещение и текстуры я из нее убрал, а из 6-ти поверхностей оставил одну, т.к. их построения однотипны.
Скрытый текст
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure TGLForm.GenList;
     
      procedure CreateMirror(Level: Byte);
      var
        i, j: GLUint;
        Pl:   array [0..3] of GLDouble;
      begin
        {$REGION 'code'}
        for i := 0 to High(Areas) do with Areas[i] do
        for j := 0 to 5 do
        if Level <= Surfaces[j].Mirror then
        begin
          glPushMatrix;
          case j of
            {$REGION 'Координаты отражений'}
            0:  begin
                  glScalef(1, 1, -1);
                  glTranslatef(0, 0, -2 * FirstNode.Z);
                end;
            {$ENDREGION}
          end;
          CreateMirror(Level + 1);
          glClear(GL_STENCIL_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
          glStencilFunc(GL_NEVER, 1, 255);
          glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
          case j of
            0:  {$REGION 'Зеркальный пол'}
                begin
                  glBegin(GL_QUADS);
                    glVertex3f(FirstNode.X,  FirstNode.Y,  FirstNode.Z);
                    glVertex3f(FirstNode.X,  SecondNode.Y, FirstNode.Z);
                    glVertex3f(SecondNode.X, SecondNode.Y, FirstNode.Z);
                    glVertex3f(SecondNode.X, FirstNode.Y,  FirstNode.Z);
                  glEnd;
                  Pl[0] := 0; Pl[1] := 0; Pl[2] := 1;
                  Pl[3] := FirstNode.Z;
                end;
                {$ENDREGION}
          end;
          glClipPlane(GL_CLIP_PLANE0, @Pl);
          glEnable(GL_CLIP_PLANE0);
          glCallList(1);
          glDisable(GL_CLIP_PLANE0);
          glPopMatrix;
        end;
        {$ENDREGION}
      end;
     
    var
      {$REGION 'var'}
      i, j, k:    GLUint;
      C:          TColor;
      Colors:     array [0..3] of GLFloat;
      PosLamp:    array [0..3] of GLFloat;
      DirLamp:    array [0..2] of GLFloat;
      Coord:      TDoubleRect;
      Surf: array of array [0..1] of Cardinal;
      {$ENDREGION}
    begin
      {$REGION 'code'}
      glDeleteLists(1, 3);
      MaxCount.X := 0; MaxCount.Y := 0; MaxCount.Z := 0;
      MinCount.X := 0; MinCount.Y := 0; MinCount.Z := 0;
      glNewList(1, GL_COMPILE);
        {$REGION 'Основной объем'}
        Colors[3] := 0;
        glLineWidth(1);
        {$REGION 'Глубина зеркал'}
        glDrawBuffer(GL_NONE);
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        for k := Low(Areas) to High(Areas) do with Areas[k] do
        begin
          if Surfaces[0].Mirror > 0 then
          begin
            if MinCount.Z < Surfaces[0].Mirror
            then MinCount.Z := Surfaces[0].Mirror;
            glBegin(GL_QUADS);
              glVertex3f(FirstNode.X,  FirstNode.Y,  FirstNode.Z);
              glVertex3f(SecondNode.X, FirstNode.Y,  FirstNode.Z);
              glVertex3f(SecondNode.X, SecondNode.Y, FirstNode.Z);
              glVertex3f(FirstNode.X,  SecondNode.Y, FirstNode.Z);
            glEnd;
          end;
        end;
        {$ENDREGION}
        for k := Low(Areas) to High(Areas) do with Areas[k] do
        begin
          {$REGION 'Пол'}
            glDrawBuffer(GL_NONE);
            {$REGION 'Генерация карты перекрытия'}
              glStencilFunc(GL_LESS, 1, 255);
              glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
              glDisable(GL_DEPTH_TEST);
              {$REGION 'Анулирование зоны перекрытия'}
              glBegin(GL_QUADS);
                glVertex3f(FirstNode.X, FirstNode.Y, FirstNode.Z);
                glVertex3f(SecondNode.X, FirstNode.Y, FirstNode.Z);
                glVertex3f(SecondNode.X, SecondNode.Y, FirstNode.Z);
                glVertex3f(FirstNode.X, SecondNode.Y, FirstNode.Z);
              glEnd;
              {$ENDREGION}
              glStencilFunc(GL_EQUAL, 1, 255);
              glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
              for i := Low(Areas) to High(Areas) do
                if (i <> k)and
                 (((Areas[i].FirstNode.Z < FirstNode.Z)and(Areas[i].SecondNode.Z > FirstNode.Z)or
                   (Areas[i].SecondNode.Z = FirstNode.Z)or(Areas[i].FirstNode.Z = FirstNode.Z)and(i > k))and
                   (Areas[i].SecondNode.X >= FirstNode.X)and(Areas[i].FirstNode.X <= SecondNode.X)and
                   (Areas[i].SecondNode.Y >= FirstNode.Y)and(Areas[i].FirstNode.Y <= SecondNode.Y))then
                begin
                  glBegin(GL_QUADS);
                    glVertex3f(Areas[i].FirstNode.X, Areas[i].FirstNode.Y, Areas[k].FirstNode.Z);
                    glVertex3f(Areas[i].SecondNode.X, Areas[i].FirstNode.Y, Areas[k].FirstNode.Z);
                    glVertex3f(Areas[i].SecondNode.X, Areas[i].SecondNode.Y, Areas[k].FirstNode.Z);
                    glVertex3f(Areas[i].FirstNode.X, Areas[i].SecondNode.Y, Areas[k].FirstNode.Z);
                  glEnd;
                end;
              glEnable(GL_DEPTH_TEST);
              glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
            {$ENDREGION}
            glDrawBuffer(GL_BACK);
            {$REGION 'Выбор цвета'}
              {$REGION 'Цвет'}
              for j := 0 to 3 do
              begin
                C := Surfaces[0].Colors[j];
                Colors[0] := (C and 255)/ 255;
                C := C shr 8;
                Colors[1] := (C and 255)/ 255;
                C := C shr 8;
                Colors[2] := (C and 255)/ 255;
                case j of
                  0: glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, @Colors);
                  1: glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, @Colors);
                  2: glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, @Colors);
                  3: glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, @Colors);
                end;
              end;
              {$ENDREGION}
            {$ENDREGION}
            if Surfaces[0].Mirror = 0 then
            begin
              glBegin(GL_QUADS);
                {$REGION 'Построение полигонов'}
                try
                  Coord.Left    := Surfaces[0].Left   / Images[Surfaces[0].Tex - 1].Width;
                  Coord.Rigth   := Surfaces[0].Right  / Images[Surfaces[0].Tex - 1].Width;
                  Coord.Bottom  := Surfaces[0].Top    / Images[Surfaces[0].Tex - 1].Height;
                  Coord.Top     := Surfaces[0].Bottom / Images[Surfaces[0].Tex - 1].Height;
                except
                end;
                glNormal3f(0.0, 0.0, 1.0);
                for i := 0 to Count.X - 1 do
                for j := 0 to Count.Y - 1 do
                begin
                  glVertex3f(FirstNode.X + i * Abs(FirstNode.X - SecondNode.X)/Count.X,
                             FirstNode.Y + j * Abs(FirstNode.Y - SecondNode.Y)/Count.Y,
                             FirstNode.Z);
                  glVertex3f(FirstNode.X +(i + 1)* Abs(FirstNode.X - SecondNode.X)/Count.X,
                             FirstNode.Y + j * Abs(FirstNode.Y - SecondNode.Y)/Count.Y,
                             FirstNode.Z);
                  glVertex3f(FirstNode.X +(i + 1)* Abs(FirstNode.X - SecondNode.X)/Count.X,
                             FirstNode.Y +(j + 1)* Abs(FirstNode.Y - SecondNode.Y)/Count.Y,
                             FirstNode.Z);
                  glVertex3f(FirstNode.X + i * Abs(FirstNode.X - SecondNode.X)/Count.X,
                             FirstNode.Y +(j + 1)* Abs(FirstNode.Y - SecondNode.Y)/Count.Y,
                             FirstNode.Z);
                end;
                {$ENDREGION}
              glEnd;
            end;
          {$ENDREGION}
        {$ENDREGION}
      glEndList;
      glNewList(2, GL_COMPILE);
        {$REGION 'Зеркальные поверхности'}
        glClearStencil(0);
        CreateMirror(1);
        glClearStencil(1);
        glClear(GL_STENCIL_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
        glCallList(1);
        {$ENDREGION}
      glEndList;
    end;



В ней реализован следующий подход:

1. Перед построением "физического мира" в списке glNewList(1) в буфер глубины прописываются поверхности зеркал. Это позволяет осечь все, что находится за зеркалом, оставив объекты между зеркалом и наблюдателем. Поверхности зеркал при этом выглядят как черные прямоугольники:

Скрытый текст
1.png (, : 467)


Далее вызывается рекурсивная процедура CreateMirror, которая определяет положение отражения, переворачивает соответствующую координату, отсекает ту часть "реального мира", которая расположена за зеркалом, и вызывает glCallList(1), в котором, как видно на предыдущем изображении, поверхность зеркала, попавшая в отражение, должна быть черной. Но вот в отражении эта "черная заливка" отсутствует:

Скрытый текст
2.png (, : 466)


Почему? Как преобразование

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
      glScalef(1, 1, -1);
      glTranslatef(0, 0, -2 * FirstNode.Z);


повлияло на буфер глубины?

PS не получилось вставить изображения, только ссылки на них :(

Автор: OpenGL 26.07.18, 09:45
Не совсем понял проблему. Что ожидается на втором рисунке? Отсутствие белой задней (по отношению к камере) грани паралелепипеда (т.е. её окраска в чёрный цвет)?

Автор: ksvsvk 27.07.18, 01:08
Отсутствующая грань колонны должна быть черной.

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)