{"id":1144,"date":"2022-12-13T19:26:33","date_gmt":"2022-12-13T11:26:33","guid":{"rendered":"http:\/\/www.max-shu.com\/blog\/?p=1144"},"modified":"2022-12-13T19:26:33","modified_gmt":"2022-12-13T11:26:33","slug":"%e4%bd%bf%e7%94%a8python%e6%b8%b2%e6%9f%93opengl%e7%9a%84-obj%e5%92%8c-mtl%e6%96%87%e4%bb%b6","status":"publish","type":"post","link":"http:\/\/www.max-shu.com\/blog\/?p=1144","title":{"rendered":"\u4f7f\u7528Python\u6e32\u67d3OpenGL\u7684.obj\u548c.mtl\u6587\u4ef6"},"content":{"rendered":"<div><b>\u5b89\u88c5\uff1a<\/b><\/div>\n<div>\u5b89\u88c5python\uff0c\u7565\u3002<\/div>\n<div>\u5b89\u88c5pip\uff0c\u7565\u3002<\/div>\n<div>\u5b89\u88c5\u5176\u4ed6\u5e93\uff1a<\/div>\n<div>DOS&gt; pip install pygame<\/div>\n<div>DOS&gt; pip install PyOpenGL<\/div>\n<div>DOS&gt; pip install numpy<\/div>\n<div>DOS&gt; pip install trimesh<\/div>\n<div>DOS&gt; pip install &#8220;pyglet&lt;2&#8221;<\/div>\n<div>DOS&gt; pip install scipy<\/div>\n<div><\/div>\n<div><b>\u4f7f\u7528\uff1a<\/b><\/div>\n<div><span><b>view.py\uff1a<\/b><\/span><\/div>\n<div><\/div>\n<div># Basic OBJ file viewer. needs objloader from:<\/div>\n<div># \u00a0<a href=\"http:\/\/www.pygame.org\/wiki\/OBJFileLoader\">http:\/\/www.pygame.org\/wiki\/OBJFileLoader<\/a><\/div>\n<div># LMB + move: rotate<\/div>\n<div># RMB + move: pan<\/div>\n<div># Scroll wheel: zoom in\/out<\/div>\n<div>import sys, pygame<\/div>\n<div>from pygame.locals import *<\/div>\n<div>from pygame.constants import *<\/div>\n<div>from OpenGL.GL import *<\/div>\n<div>from OpenGL.GLU import *<\/div>\n<div><\/div>\n<div># IMPORT OBJECT LOADER<\/div>\n<div>from objloader import *<\/div>\n<div><\/div>\n<div>pygame.init()<\/div>\n<div>viewport = (800,600)<\/div>\n<div>hx = viewport[0]\/2<\/div>\n<div>hy = viewport[1]\/2<\/div>\n<div>srf = pygame.display.set_mode(viewport, OPENGL | DOUBLEBUF)<\/div>\n<div><\/div>\n<div>glLightfv(GL_LIGHT0, GL_POSITION, \u00a0(-40, 200, 100, 0.0))<\/div>\n<div>glLightfv(GL_LIGHT0, GL_AMBIENT, (0.2, 0.2, 0.2, 1.0))<\/div>\n<div>glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.5, 0.5, 0.5, 1.0))<\/div>\n<div>glEnable(GL_LIGHT0)<\/div>\n<div>glEnable(GL_LIGHTING)<\/div>\n<div>glEnable(GL_COLOR_MATERIAL)<\/div>\n<div>glEnable(GL_DEPTH_TEST)<\/div>\n<div>glShadeModel(GL_SMOOTH) \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # most obj files expect to be smooth-shaded<\/div>\n<div><\/div>\n<div># LOAD OBJECT AFTER PYGAME INIT<\/div>\n<div>obj = OBJ(sys.argv[1], swapyz=True)<\/div>\n<div><\/div>\n<div>clock = pygame.time.Clock()<\/div>\n<div><\/div>\n<div>glMatrixMode(GL_PROJECTION)<\/div>\n<div>glLoadIdentity()<\/div>\n<div>width, height = viewport<\/div>\n<div>gluPerspective(90.0, width\/float(height), 1, 100.0)<\/div>\n<div>glEnable(GL_DEPTH_TEST)<\/div>\n<div>glMatrixMode(GL_MODELVIEW)<\/div>\n<div><\/div>\n<div>rx, ry = (0,0)<\/div>\n<div>tx, ty = (0,0)<\/div>\n<div>zpos = 5<\/div>\n<div>rotate = move = False<\/div>\n<div>while 1:<\/div>\n<div>\u00a0 \u00a0 clock.tick(30)<\/div>\n<div>\u00a0 \u00a0 for e in pygame.event.get():<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 if e.type == QUIT:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 sys.exit()<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 elif e.type == KEYDOWN and e.key == K_ESCAPE:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 sys.exit()<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 elif e.type == MOUSEBUTTONDOWN:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if e.button == 4: zpos = max(1, zpos-1)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif e.button == 5: zpos += 1<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif e.button == 1: rotate = True<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif e.button == 3: move = True<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 elif e.type == MOUSEBUTTONUP:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if e.button == 1: rotate = False<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif e.button == 3: move = False<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 elif e.type == MOUSEMOTION:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 i, j = e.rel<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if rotate:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 rx += i<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ry += j<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if move:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 tx += i<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ty -= j<\/div>\n<div><\/div>\n<div>\u00a0 \u00a0 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)<\/div>\n<div>\u00a0 \u00a0 glLoadIdentity()<\/div>\n<div><\/div>\n<div>\u00a0 \u00a0 # RENDER OBJECT<\/div>\n<div>\u00a0 \u00a0 glTranslate(tx\/20., ty\/20., &#8211; zpos)<\/div>\n<div>\u00a0 \u00a0 glRotate(ry, 1, 0, 0)<\/div>\n<div>\u00a0 \u00a0 glRotate(rx, 0, 1, 0)<\/div>\n<div>\u00a0 \u00a0 glCallList(obj.gl_list)<\/div>\n<div><\/div>\n<div>\u00a0 \u00a0 pygame.display.flip()<\/div>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n<div><b>objloader.py\uff1a<\/b><\/div>\n<div><\/div>\n<div>import numpy<\/div>\n<div>import pygame<\/div>\n<div>from OpenGL.GL import *<\/div>\n<div>from OpenGL.GLU import *<\/div>\n<div>from OpenGL.GLUT import *<\/div>\n<div><\/div>\n<div>def MTL(filename):<\/div>\n<div>\u00a0 \u00a0 contents = {}<\/div>\n<div>\u00a0 \u00a0 mtl = None<\/div>\n<div>\u00a0 \u00a0 for line in open(filename, &#8220;r&#8221;):<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 if line.startswith(&#8216;#&#8217;): continue<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 values = line.split()<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 if not values: continue<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 if values[0] == &#8216;newmtl&#8217;:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 mtl = contents[values[1]] = {}<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 elif mtl is None:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 raise (ValueError, &#8220;mtl file doesn&#8217;t start with newmtl stmt&#8221;)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 elif values[0] == &#8216;map_Kd&#8217;:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # load the texture referred to by this declaration<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 mtl[values[0]] = values[1]<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 print(mtl[&#8216;map_Kd&#8217;])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 surf = pygame.image.load(mtl[&#8216;map_Kd&#8217;])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 image = pygame.image.tostring(surf, &#8216;RGBA&#8217;, 1)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ix, iy = surf.get_rect().size<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 texid = mtl[&#8216;texture_Kd&#8217;] = glGenTextures(1)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glBindTexture(GL_TEXTURE_2D, texid)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 GL_LINEAR)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 GL_LINEAR)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ix, iy, 0, GL_RGBA,<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 GL_UNSIGNED_BYTE, image)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 else:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 mtl[values[0]] = map(float, values[1:])<\/div>\n<div>\u00a0 \u00a0 return contents<\/div>\n<div><\/div>\n<div>class OBJ:<\/div>\n<div>\u00a0 \u00a0 def __init__(self, filename, swapyz=False):<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 &#8220;&#8221;&#8221;Loads a Wavefront OBJ file. &#8220;&#8221;&#8221;<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 self.vertices = []<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 self.normals = []<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 self.texcoords = []<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 self.faces = []<\/div>\n<div><\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 material = None<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 for line in open(filename, &#8220;r&#8221;):<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if line.startswith(&#8216;#&#8217;): continue<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 values = line.split()<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if not values: continue<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if values[0] == &#8216;v&#8217;:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # v = map(float, values[1:4])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 v = list(map(float, values[1:4]))<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if swapyz:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 v = v[0], v[2], v[1]<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.vertices.append(v)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif values[0] == &#8216;vn&#8217;:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # v = map(float, values[1:4])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 v = list(map(float, values[1:4]))<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if swapyz:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 v = v[0], v[2], v[1]<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.normals.append(v)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif values[0] == &#8216;vt&#8217;:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # self.texcoords.append(map(float, values[1:3]))<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.texcoords.append(list(map(float, values[1:3])))<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif values[0] in (&#8216;usemtl&#8217;, &#8216;usemat&#8217;):<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 material = values[1]<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif values[0] == &#8216;mtllib&#8217;:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.mtl = MTL(values[1])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif values[0] == &#8216;f&#8217;:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 face = []<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 texcoords = []<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 norms = []<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 for v in values[1:]:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 w = v.split(&#8216;\/&#8217;)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 face.append(int(w[0]))<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if len(w) &gt;= 2 and len(w[1]) &gt; 0:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 texcoords.append(int(w[1]))<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 else:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 texcoords.append(0)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if len(w) &gt;= 3 and len(w[2]) &gt; 0:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 norms.append(int(w[2]))<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 else:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 norms.append(0)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.faces.append((face, norms, texcoords, material))<\/div>\n<div><\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 self.gl_list = glGenLists(1)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 glNewList(self.gl_list, GL_COMPILE)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 glEnable(GL_TEXTURE_2D)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 glFrontFace(GL_CCW)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 for face in self.faces:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 vertices, normals, texture_coords, material = face<\/div>\n<div><\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 mtl = self.mtl[material]<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if &#8216;texture_Kd&#8217; in mtl:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # use diffuse texmap<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glBindTexture(GL_TEXTURE_2D, mtl[&#8216;texture_Kd&#8217;])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 else:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # just use diffuse colour<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 tmpList = list(mtl[&#8216;Kd&#8217;])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 listLen = len(tmpList)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if listLen == 1:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glColor(tmpList[0])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif listLen == 2:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glColor(tmpList[0], tmpList[1])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif listLen == 3:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glColor(tmpList[0], tmpList[1], tmpList[2])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 elif listLen == 4:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glColor(tmpList[0], tmpList[1], tmpList[2], tmpList[3])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 #glColor(*mtl[&#8216;Kd&#8217;])<\/div>\n<div><\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glBegin(GL_POLYGON)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 for i in range(len(vertices)):<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if normals[i] &gt; 0:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glNormal3fv(self.normals[normals[i] &#8211; 1])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if texture_coords[i] &gt; 0:<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glTexCoord2fv(self.texcoords[texture_coords[i] &#8211; 1])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glVertex3fv(self.vertices[vertices[i] &#8211; 1])<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 glEnd()<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 glDisable(GL_TEXTURE_2D)<\/div>\n<div>\u00a0 \u00a0 \u00a0 \u00a0 glEndList()<\/div>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n<div><b>\u8fd0\u884c\uff1a<\/b><\/div>\n<div>\u9700\u8981\u628a\u4e0a\u9762\u4e24\u4e2a\u6e90\u6587\u4ef6\u548c.obj\u3001.mtl\u3001.png\u7b49\u8d44\u6e90\u6587\u4ef6\u653e\u5230\u4e00\u4e2a\u76ee\u5f55\u4e0b\uff1a<\/div>\n<div>DOS&gt; python view.py\u00a0\u00a0uploads_files_3746622_FK8.obj<\/div>\n<div>\uff08obj\u6587\u4ef6\u91cc\u9762\u542b\u6709\u9700\u8981\u7684mtl\u6587\u4ef6\u540d\uff0cmtl\u6587\u4ef6\u91cc\u9762\u542b\u6709\u9700\u8981\u7684.png\u7b49\u5176\u4ed6\u8d44\u6e90\u6587\u4ef6\u540d\uff09<\/div>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u5b89\u88c5\uff1a \u5b89\u88c5python\uff0c\u7565\u3002 \u5b89\u88c5pip\uff0c\u7565\u3002 \u5b89\u88c5\u5176\u4ed6\u5e93\uff1a DOS&gt; pip install pyg &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[872,871,870,108,873],"class_list":["post-1144","post","type-post","status-publish","format-standard","hentry","category-13","tag-mtl","tag-obj","tag-opengl","tag-python","tag-873"],"views":2218,"_links":{"self":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1144","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1144"}],"version-history":[{"count":1,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1144\/revisions"}],"predecessor-version":[{"id":1145,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1144\/revisions\/1145"}],"wp:attachment":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1144"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1144"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1144"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}