Некорректная окклюзия, выбраковка лицевой стороны в openGL

Я использую свой собственный алгоритм для удаления окклюдированных лицевых граней, которые никогда не должны отображаться. Когда я не выбрасываю лица, у меня есть идеальный набор блоков. Когда я включаю мой выбор лица, у меня неожиданные результаты. Я проверил мой код отбраковки и считаю, что он правильно отбирает соответствующие лица.

Для простоты я сократил вывод до плоскости из 9 ящиков. Например, поле в середине плоскости должно иметь только верхнюю и нижнюю грани. Все остальные лица могут быть отброшены, потому что их просто нигде не будет видно.

Я проверил каждое поле в коде, чтобы определить, правильно ли выбраны лица, и я верю, что это так. Это заставляет меня думать, что это проблема с моими вершинами, индексами или нормалями.

Я использую Pyglet Python, который автоматически создает и управляет VAO и VBO.

Настройки OpenGL:

    glEnable(GL_DEPTH_TEST)
    glEnable(GL_CULL_FACE)

OpenGL On Draw:

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

Код вершины:

        v0 = [1,  1,  1]
        v1 = [-1,  1,  1]
        v2 = [-1, -1,  1]
        v3 = [1, -1,  1]
        v4 = [1, -1, -1]
        v5 = [1,  1, -1]
        v6 = [-1,  1, -1]
        v7 = [-1, -1, -1]
        pt = self.point
        s = getattr(self, 'scale', 0.5)
        faces = ((k, v) for k, v in (
            ('front', [v * s + p for vert in [v0, v1, v2, v3]
                       for v, p in zip(vert, pt)]),
            ('right', [v * s + p for vert in [v0, v3, v4, v5]
                       for v, p in zip(vert, pt)]),
            ('top', [v * s + p for vert in [v0, v5, v6, v1]
                     for v, p in zip(vert, pt)]),
            ('left', [v * s + p for vert in [v1, v6, v7, v2]
                      for v, p in zip(vert, pt)]),
            ('bottom', [v * s + p for vert in [v7, v4, v3, v2]
                        for v, p in zip(vert, pt)]),
            ('back', [v * s + p for vert in [v4, v7, v6, v5]
                      for v, p in zip(vert, pt)]))
            if getattr(self, k)
        )

Нормальный код:

        verts_per_face = 4
        faces = ((k, v) for k, v in (
            ('front', [0, 0, 1] * verts_per_face),
            ('right', [1, 0, 0] * verts_per_face),
            ('top', [0, 1, 0] * verts_per_face),
            ('left', [-1, 0, 0] * verts_per_face),
            ('bottom', [0, -1, 0] * verts_per_face),
            ('back', [0, 0, -1] * verts_per_face))
            if getattr(self, k)
        )

Код индексов:

        t0 = [0,  1,  2]
        t1 = [2,  3,  0]
        t2 = [4,  5,  6]
        t3 = [6,  7,  4]
        t4 = [8,  9, 10]
        t5 = [10, 11,  8]
        t6 = [12, 13, 14]
        t7 = [14, 15, 12]
        t8 = [16, 17, 18]
        t9 = [18, 19, 16]
        t10 = [20, 21, 22]
        t11 = [22, 23, 20]
        triangles = ((k, v) for k, v in (
            ('front', [t for triangle in [t0, t1] for t in triangle]),
            ('right', [t for triangle in [t2, t3] for t in triangle]),
            ('top', [t for triangle in [t4, t5] for t in triangle]),
            ('left', [t for triangle in [t6, t7] for t in triangle]),
            ('bottom', [t for triangle in [t8, t9] for t in triangle]),
            ('back', [t for triangle in [t10, t11] for t in triangle]))
            if getattr(self, k)
        )

Код выбраковки:

                for face, neighbor_point in block.neighbors():
                    # import pdb; pdb.set_trace()
                    if neighbor_point in pts:
                        neighbor = self.blocks.get(neighbor_point)
                        if neighbor:
                            setattr(block, face, False)
                        else:
                            setattr(block, face, True)
                    else:
                        setattr(block, face, True)

Пример вывода после отбраковки передней и левой граней на одном из полей:

<Voxel (1,0,1)  # top right corner box in images /w center point = (1, 0, 1)
[f r t l o a]   # front, right, top, left, bottom, back
[ |+|+| |+|+]   # + = face available,  ' ' = face culled
(1, 0, 0) (1, 0, 0) (1, 0, 0) (1, 0, 0)  # right normals
(0, 1, 0) (0, 1, 0) (0, 1, 0) (0, 1, 0)  # top normals
(0, -1, 0) (0, -1, 0) (0, -1, 0) (0, -1, 0)  # bottom normals 
(0, 0, -1) (0, 0, -1) (0, 0, -1) (0, 0, -1)  # back normals
[ 1.50| 0.50| 1.50|  # right verts
  1.50|-0.50| 1.50| 
  1.50|-0.50| 0.50| 
  1.50| 0.50| 0.50| 
  1.50| 0.50| 1.50|  # top verts
  1.50| 0.50| 0.50| 
  0.50| 0.50| 0.50| 
  0.50| 0.50| 1.50| 
  0.50|-0.50| 0.50|  # bottom verts
  1.50|-0.50| 0.50| 
  1.50|-0.50| 1.50| 
  0.50|-0.50| 1.50| 
  1.50|-0.50| 0.50|  # back verts
  0.50|-0.50| 0.50| 
  0.50| 0.50| 0.50| 
  1.50| 0.50| 0.50]>

Отбраковка, без каркасовНет выбраковки, нет каркасовВыбраковка, каркасыНет выбраковки, каркасы

2 ответа

Смотрите здесь, как реализовать алгоритм отбраковки. В вашем коде отбраковки вы делаете что-то совершенно неактуальное. Чтобы определить, нужно ли отбирать лицо, вам нужно только проверить его порядок намотки (при условии, что вы предоставляете все треугольники в порядке CW или CCW относительно их нормалей). Если ваши треугольники не упорядочены, то для определения отбраковки вы должны проверить z-порядок вершин треугольника, что видеокарта выполняет автоматически. Если вы решите реализовать это самостоятельно, вы будете эффективно реализовывать программный рендеринг (хотя рендеринг выполняется фрагментами треугольника, а не отдельными пикселями).

Я не правильно рассчитывал показатели. Новый метод должен быть:

        t0 = [0,  1,  2]
        t1 = [2,  3,  0]
        t2 = [4,  5,  6]
        t3 = [6,  7,  4]
        t4 = [8,  9, 10]
        t5 = [10, 11,  8]
        t6 = [12, 13, 14]
        t7 = [14, 15, 12]
        t8 = [16, 17, 18]
        t9 = [18, 19, 16]
        t10 = [20, 21, 22]
        t11 = [22, 23, 20]
        triangles = ((k, v) for k, v in (
            ('front', [t for triangle in [t0, t1] for t in triangle]),
            ('right', [t for triangle in [t2, t3] for t in triangle]),
            ('top', [t for triangle in [t4, t5] for t in triangle]),
            ('left', [t for triangle in [t6, t7] for t in triangle]),
            ('bottom', [t for triangle in [t8, t9] for t in triangle]),
            ('back', [t for triangle in [t10, t11] for t in triangle]))
        )
        inds = []
        faces = [f for f, v in self.faces if v]
        for triangle, face in zip(triangles, faces):
            f, tdata = triangle
            inds.extend(tdata)
Другие вопросы по тегам