OpenGL Python中背面剔除问题

zkure5ic  于 2022-12-12  发布在  Python
关注(0)|答案(1)|浏览(128)

我的目标是在pygame上使用PyOpenGL渲染一个.pmx 3D模型。我找到了pymeshio模块,它可以提取顶点和法向量等。我找到了一个在tkinter上渲染的github repo示例代码。我更改了代码,改为在pygame上渲染,没有更改与OpenGL渲染相关的部分。输出如下:
| | |
| - -|- -|
|

|

|
模型文件没有损坏,我在Blender和MMD上检查了它。我是OpenGL和3D编程的新手,但我认为这可能与背面剔除的顶点序列有关,一些三角形是顺时针的,另一些是逆时针的。
这是渲染代码。它使用draw函数来渲染。

class IndexedVertexArray(object):
    def __init__(self):
        # vertices
        self.vertices=[]
        self.normal=[]
        self.colors=[]
        self.uvlist=[]
        self.b0=[]
        self.b1=[]
        self.w0=[]
        self.materials=[]
        self.indices=[]
        self.buffers=[]

        self.new_vertices=[]
        self.new_normal=[]

    def addVertex(self, pos, normal, uv, color, b0, b1, w0):
        self.vertices+=pos
        self.normal+=normal
        self.colors+=color
        self.uvlist+=uv
        self.b0.append(b0)
        self.b1.append(b1)
        self.w0.append(w0)

    def setIndices(self, indices):
        self.indices=indices

    def addMaterial(self, material):
        self.materials.append(material)

    def create_array_buffer(self, buffer_id, floats):
        # print('create_array_buuffer', buffer_id)
        glBindBuffer(GL_ARRAY_BUFFER, buffer_id)
        glBufferData(GL_ARRAY_BUFFER, 
                len(floats)*4,  # byte size
                (ctypes.c_float*len(floats))(*floats), # 謎のctypes
                GL_STATIC_DRAW)

    def create_vbo(self):
        self.buffers = glGenBuffers(4+1)
        # print("create_vbo", self.buffers)

        self.create_array_buffer(self.buffers[0], self.vertices)
        self.create_array_buffer(self.buffers[1], self.normal)
        self.create_array_buffer(self.buffers[2], self.colors)
        self.create_array_buffer(self.buffers[3], self.uvlist)

        # indices
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.buffers[4])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
                len(self.indices)*4, # byte size
                (ctypes.c_uint*len(self.indices))(*self.indices),  # 謎のctypes
                GL_STATIC_DRAW)

    def draw(self):
        if len(self.buffers)==0:
            self.create_vbo()

        glEnableClientState(GL_VERTEX_ARRAY);
        glBindBuffer(GL_ARRAY_BUFFER, self.buffers[0]);
        glVertexPointer(4, GL_FLOAT, 0, None);

        glEnableClientState(GL_NORMAL_ARRAY);
        glBindBuffer(GL_ARRAY_BUFFER, self.buffers[1]);
        glNormalPointer(GL_FLOAT, 0, None);

        glEnableClientState(GL_COLOR_ARRAY);
        glBindBuffer(GL_ARRAY_BUFFER, self.buffers[2]);
        glColorPointer(4, GL_FLOAT, 0, None);

        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glBindBuffer(GL_ARRAY_BUFFER, self.buffers[3]);
        glTexCoordPointer(2, GL_FLOAT, 0, None);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.buffers[4]);
        index_offset=0
        for i, m in enumerate(self.materials):
            # submesh
            m.begin()
            glDrawElements(GL_TRIANGLES, m.vertex_count, GL_UNSIGNED_INT, ctypes.c_void_p(index_offset));
            index_offset+=m.vertex_count * 4 # byte size
            m.end()

        # cleanup
        glDisableClientState(GL_TEXTURE_COORD_ARRAY)
        glDisableClientState(GL_COLOR_ARRAY)
        glDisableClientState(GL_NORMAL_ARRAY);
        glDisableClientState(GL_VERTEX_ARRAY)

这是与背面剔除相关的部分

class MQOMaterial(object):
    def __init__(self):
        self.rgba=(1, 1, 1, 1)
        self.vcol=False
        self.texture=None

    def __enter__(self):
        self.begin()

    def __exit__(self):
        self.end()

    def begin(self):
        glColor4f(*self.rgba)
        if self.texture:
            self.texture.begin()

        # backface culling
        glEnable(GL_CULL_FACE)
        glFrontFace(GL_CW)
        glCullFace(GL_BACK)
        # glCullFace(GL_FRONT)
        # alpha test
        glEnable(GL_ALPHA_TEST);
        glAlphaFunc(GL_GREATER, 0.5);

    def end(self):
        if self.texture:
            self.texture.end()

首先我禁用了alpha通道,什么也没做。我尝试了GL_FRONTGL_CCW,但没有成功。我尝试了分离顶点组,并使用glVertex3fv渲染它们。原始代码已经将顶点保存为以下格式:

vertices = [v0.x, v0.y, v0.z, 1, v1.x, v1.y, v1.z, 1, v2.x, v2.y, v2.z, 1, ...]
            ___________________  ___________________  ___________________
                   v0                    v1                  v2
normal = [v0.normal.x, v0.normal.y, v0.normal.z, v1.normal.x, v1.normal.y, v1.normal.z, ...]
          _____________________________________  _____________________________________
                          v0                                   v1
indices = [0, 1, 2, 1, 4, 5, 2, 4, 6, ...]
           -------  -------  -------
           group0   group1    group2

我尝试用以下代码渲染三角形:

def _draw(self):
    glBegin(GL_TRIANGLES)
    for i in range(len(self.indices) // 3):
      # glTexCoord2fv( tex_coords[ti] )
      if i == len(self.new_normal):
          break
          # glNormal3fv( self.new_normal[i] )
          glVertex3fv( self.new_vertices[i])
    glEnd()

def new_sort(self):
    for i in range(len(self.indices) // 3):
       if i <= -1:
           continue
       k = 4 * i
       j = 3 * i
       if k + 2 >= len(self.vertices) or j + 2 >= len(self.normal):
            break
       self.new_vertices.append(tuple((self.vertices[k], self.vertices[k + 1], self.vertices[k + 2] )))
       self.new_normal.append(tuple((self.normal[j], self.normal[j + 1], self.normal[j + 2] )))

输出

我想可能是错误的点在一起,所以用1和2移动它们来设置正确的点,但输出变得更难看。我用四边形测试了这个,没有变化。
我将感激任何帮助或提示。

qjp7pelc

qjp7pelc1#

顶部的彩色图像似乎是在没有深度测试的情况下渲染的,你必须启用Depth Test并清除深度缓冲区:
第一个

相关问题