我的目标是在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_FRONT
和GL_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移动它们来设置正确的点,但输出变得更难看。我用四边形测试了这个,没有变化。
我将感激任何帮助或提示。
1条答案
按热度按时间qjp7pelc1#
顶部的彩色图像似乎是在没有深度测试的情况下渲染的,你必须启用Depth Test并清除深度缓冲区:
第一个