在Pygame中是否有一种方法可以更改导入的.obj文件的位置和大小?

huangapple go评论161阅读模式
英文:

Is there a way to change the location and size of an imported .obj file in Pygame?

问题

我使用Blender创建了一个.obj文件,并使用OBJ文件加载器加载到Pygame中,如sugested by skrx在以下链接中:
https://stackoverflow.com/questions/47660370/error-in-objfileloader

是否有一种简单的方法在导入Pygame后更改导入的.obj文件的位置、高度和宽度?例如,如果您创建了一个tree.obj文件,要能够以不同的大小将相同的树放在不同的位置?

按照下面的代码,可能像这样:

  1. object_obj = OBJ("Tree.obj", swapyz=False)
  2. object_obj.setX = 0
  3. object_obj.setWidth = 3
  4. object_obj.setHeight = 10

或者通过向obj加载器发送额外的参数,改变顶点?

OBJ加载器:

  1. import pygame
  2. from OpenGL.GL import *
  3. def MTL(filename):
  4. filename = 'OBJ/' + filename
  5. contents = {}
  6. mtl = None
  7. for line in open(filename, "r"):
  8. if line.startswith('#'): continue
  9. values = line.split()
  10. if not values: continue
  11. if values[0] == 'newmtl':
  12. mtl = contents[values[1]] = {}
  13. elif mtl is None:
  14. raise ValueError("mtl file doesn't start with newmtl stmt")
  15. elif values[0] == 'map_Kd':
  16. # load the texture referred to by this declaration
  17. mtl[values[0]] = values[1]
  18. surf = pygame.image.load(mtl['map_Kd'])
  19. image = pygame.image.tostring(surf, 'RGBA', 1)
  20. ix, iy = surf.get_rect().size
  21. texid = mtl['texture_Kd'] = glGenTextures(1)
  22. glBindTexture(GL_TEXTURE_2D, texid)
  23. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  24. GL_LINEAR)
  25. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
  26. GL_LINEAR)
  27. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ix, iy, 0, GL_RGBA,
  28. GL_UNSIGNED_BYTE, image)
  29. else:
  30. mtl[values[0]] = list(map(float, values[1:]))
  31. return contents
  32. class OBJ:
  33. def __init__(self, filename, swapyz=False):
  34. """Loads a Wavefront OBJ file."""
  35. self.vertices = []
  36. self.normals = []
  37. self.texcoords = []
  38. self.faces = []
  39. material = None
  40. for line in open(filename, "r"):
  41. if line.startswith('#'): continue
  42. values = line.split()
  43. if not values: continue
  44. if values[0] == 'v':
  45. v = list(map(float, values[1:4]))
  46. if swapyz:
  47. v = v[0], v[2], v[1]
  48. self.vertices.append(v)
  49. elif values[0] == 'vn':
  50. v = list(map(float, values[1:4]))
  51. if swapyz:
  52. v = v[0], v[2], v[1]
  53. self.normals.append(v)
  54. elif values[0] == 'vt':
  55. self.texcoords.append(list(map(float, values[1:3])))
  56. elif values[0] in ('usemtl', 'usemat'):
  57. material = values[1]
  58. elif values[0] == 'mtllib':
  59. self.mtl = MTL(values[1])
  60. elif values[0] == 'f':
  61. face = []
  62. texcoords = []
  63. norms = []
  64. for v in values[1:]:
  65. w = v.split('/')
  66. face.append(int(w[0]))
  67. if len(w) >= 2 and len(w[1]) > 0:
  68. texcoords.append(int(w[1]))
  69. else:
  70. texcoords.append(0)
  71. if len(w) >= 3 and len(w[2]) > 0:
  72. norms.append(int(w[2]))
  73. else:
  74. norms.append(0)
  75. self.faces.append((face, norms, texcoords, material))
  76. self.gl_list = glGenLists(1)
  77. glNewList(self.gl_list, GL_COMPILE)
  78. glEnable(GL_TEXTURE_2D)
  79. glFrontFace(GL_CCW)
  80. for face in self.faces:
  81. vertices, normals, texture_coords, material = face
  82. mtl = self.mtl[material]
  83. if 'texture_Kd' in mtl:
  84. # use diffuse texmap
  85. glBindTexture(GL_TEXTURE_2D, mtl['texture_Kd'])
  86. else:
  87. # just use diffuse colour
  88. glColor(*mtl['Kd'])
  89. glBegin(GL_POLYGON)
  90. for i in range(len(vertices)):
  91. if normals[i] > 0:
  92. glNormal3fv(self.normals[normals[i] - 1])
  93. if texture_coords[i] > 0:
  94. glTexCoord2fv(self.texcoords[texture_coords[i] - 1])
  95. glVertex3fv(self.vertices[vertices[i] - 1])
  96. glEnd()
  97. glDisable(GL_TEXTURE_2D)
  98. glEndList()

在Pygame中显示.OBJ文件:

  1. # Basic OBJ file viewer. needs objloader from:
  2. # http://www.pygame.org/wiki/OBJFileLoader
  3. # LMB + move: rotate
  4. # RMB + move: pan
  5. # Scroll wheel: zoom in/out
  6. import sys, pygame
  7. from pygame.locals import *
  8. from pygame.constants import *
  9. from OpenGL.GL import *
  10. from OpenGL.GLU import *
  11. # IMPORT OBJECT LOADER
  12. from OBJ_Loader import *
  13. pygame.init()
  14. viewport = (800,600)
  15. hx = viewport[0]/2
  16. hy = viewport[1]/2
  17. srf = pygame.display.set_mode(viewport, OPENGL | DOUBLEBUF)
  18. glLightfv(GL_LIGHT0, GL_POSITION, (-40, 200, 100, 0.0))
  19. glLightfv(GL_LIGHT0, GL_AMBIENT, (0.2, 0.2, 0.2, 1.0))
  20. glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.5, 0.5, 0.5, 1.0))
  21. glEnable(GL_LIGHT0)
  22. glEnable(GL_LIGHTING)
  23. glEnable(GL_COLOR_MATERIAL)
  24. glEnable(GL_DEPTH_TEST)
  25. glShadeModel(GL_SMOOTH) # most obj files expect to be smooth-shaded
  26. # LOAD OBJECT AFTER PYGAME INIT
  27. object_obj = OBJ("Tree.obj", swapyz=False)
  28. clock = pygame.time.Clock()
  29. glMatrixMode(GL_PROJECTION)
  30. glLoadIdentity()
  31. width, height = viewport
  32. gluPerspective(90, 1, 0.001, 1000.0)
  33. glEnable(GL_DEPTH_TEST)
  34. glMatrixMode(GL_MODELVIEW)
  35. rx, ry = (0,0)
  36. tx, ty = (0,0)
  37. zpos = 1
  38. rotate = move = False
  39. while 1:
  40. clock.tick(30)
  41. for e in pygame.event.get():
  42. if e.type == QUIT:
  43. sys.exit()
  44. elif e.type == KEYDOWN and e.key == K_ESCAPE:
  45. sys.exit()
  46. elif
  47. <details>
  48. <summary>英文:</summary>
  49. I created an .obj file using blender and loaded into Pygame using the OBJfileloader as sugested by skrx in:
  50. [https://stackoverflow.com/questions/47660370/error-in-objfileloader][1]
  51. [1]: https://stackoverflow.com/questions/47660370/error-in-objfileloader
  52. Is there an easy way to change the location, height and width of the imported .obj file after importing it into Pygame? As an example, if you create a tree.obj file, to be able to place that same tree in different places with different sizes?
  53. Following the code below, maybe something like:
  54. ```py
  55. object_obj = OBJ(&quot;Tree.obj&quot;, swapyz=False)
  56. object_obj.setX = 0
  57. object_obj.setWidth = 3
  58. object_obj.setHeight =10

Or by sending extra parameters to the obj loader, changing the vertices?

OBJ Loader:

  1. import pygame
  2. from OpenGL.GL import *
  3. def MTL(filename):
  4. filename = &#39;OBJ/&#39;+filename
  5. contents = {}
  6. mtl = None
  7. for line in open(filename, &quot;r&quot;):
  8. if line.startswith(&#39;#&#39;): continue
  9. values = line.split()
  10. if not values: continue
  11. if values[0] == &#39;newmtl&#39;:
  12. mtl = contents[values[1]] = {}
  13. elif mtl is None:
  14. raise ValueError(&quot;mtl file doesn&#39;t start with newmtl stmt&quot;)
  15. elif values[0] == &#39;map_Kd&#39;:
  16. # load the texture referred to by this declaration
  17. mtl[values[0]] = values[1]
  18. surf = pygame.image.load(mtl[&#39;map_Kd&#39;])
  19. image = pygame.image.tostring(surf, &#39;RGBA&#39;, 1)
  20. ix, iy = surf.get_rect().size
  21. texid = mtl[&#39;texture_Kd&#39;] = glGenTextures(1)
  22. glBindTexture(GL_TEXTURE_2D, texid)
  23. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  24. GL_LINEAR)
  25. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
  26. GL_LINEAR)
  27. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ix, iy, 0, GL_RGBA,
  28. GL_UNSIGNED_BYTE, image)
  29. else:
  30. mtl[values[0]] = list(map(float, values[1:]))
  31. return contents
  32. class OBJ:
  33. def __init__(self, filename, swapyz=False):
  34. &quot;&quot;&quot;Loads a Wavefront OBJ file. &quot;&quot;&quot;
  35. self.vertices = []
  36. self.normals = []
  37. self.texcoords = []
  38. self.faces = []
  39. material = None
  40. for line in open(filename, &quot;r&quot;):
  41. if line.startswith(&#39;#&#39;): continue
  42. values = line.split()
  43. if not values: continue
  44. if values[0] == &#39;v&#39;:
  45. v = list(map(float, values[1:4]))
  46. if swapyz:
  47. v = v[0], v[2], v[1]
  48. self.vertices.append(v)
  49. elif values[0] == &#39;vn&#39;:
  50. v = list(map(float, values[1:4]))
  51. if swapyz:
  52. v = v[0], v[2], v[1]
  53. self.normals.append(v)
  54. elif values[0] == &#39;vt&#39;:
  55. self.texcoords.append(list(map(float, values[1:3])))
  56. elif values[0] in (&#39;usemtl&#39;, &#39;usemat&#39;):
  57. material = values[1]
  58. elif values[0] == &#39;mtllib&#39;:
  59. self.mtl = MTL(values[1])
  60. elif values[0] == &#39;f&#39;:
  61. face = []
  62. texcoords = []
  63. norms = []
  64. for v in values[1:]:
  65. w = v.split(&#39;/&#39;)
  66. face.append(int(w[0]))
  67. if len(w) &gt;= 2 and len(w[1]) &gt; 0:
  68. texcoords.append(int(w[1]))
  69. else:
  70. texcoords.append(0)
  71. if len(w) &gt;= 3 and len(w[2]) &gt; 0:
  72. norms.append(int(w[2]))
  73. else:
  74. norms.append(0)
  75. self.faces.append((face, norms, texcoords, material))
  76. self.gl_list = glGenLists(1)
  77. glNewList(self.gl_list, GL_COMPILE)
  78. glEnable(GL_TEXTURE_2D)
  79. glFrontFace(GL_CCW)
  80. for face in self.faces:
  81. vertices, normals, texture_coords, material = face
  82. mtl = self.mtl[material]
  83. if &#39;texture_Kd&#39; in mtl:
  84. # use diffuse texmap
  85. glBindTexture(GL_TEXTURE_2D, mtl[&#39;texture_Kd&#39;])
  86. else:
  87. # just use diffuse colour
  88. glColor(*mtl[&#39;Kd&#39;])
  89. glBegin(GL_POLYGON)
  90. for i in range(len(vertices)):
  91. if normals[i] &gt; 0:
  92. glNormal3fv(self.normals[normals[i] - 1])
  93. if texture_coords[i] &gt; 0:
  94. glTexCoord2fv(self.texcoords[texture_coords[i] - 1])
  95. glVertex3fv(self.vertices[vertices[i] - 1])
  96. glEnd()
  97. glDisable(GL_TEXTURE_2D)
  98. glEndList()

Displaying .OBJ file in Pygame:

  1. # Basic OBJ file viewer. needs objloader from:
  2. # http://www.pygame.org/wiki/OBJFileLoader
  3. # LMB + move: rotate
  4. # RMB + move: pan
  5. # Scroll wheel: zoom in/out
  6. import sys, pygame
  7. from pygame.locals import *
  8. from pygame.constants import *
  9. from OpenGL.GL import *
  10. from OpenGL.GLU import *
  11. # IMPORT OBJECT LOADER
  12. from OBJ_Loader import *
  13. pygame.init()
  14. viewport = (800,600)
  15. hx = viewport[0]/2
  16. hy = viewport[1]/2
  17. srf = pygame.display.set_mode(viewport, OPENGL | DOUBLEBUF)
  18. glLightfv(GL_LIGHT0, GL_POSITION, (-40, 200, 100, 0.0))
  19. glLightfv(GL_LIGHT0, GL_AMBIENT, (0.2, 0.2, 0.2, 1.0))
  20. glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.5, 0.5, 0.5, 1.0))
  21. glEnable(GL_LIGHT0)
  22. glEnable(GL_LIGHTING)
  23. glEnable(GL_COLOR_MATERIAL)
  24. glEnable(GL_DEPTH_TEST)
  25. glShadeModel(GL_SMOOTH) # most obj files expect to be smooth-shaded
  26. # LOAD OBJECT AFTER PYGAME INIT
  27. object_obj = OBJ(&quot;Tree.obj&quot;, swapyz=False)
  28. clock = pygame.time.Clock()
  29. glMatrixMode(GL_PROJECTION)
  30. glLoadIdentity()
  31. width, height = viewport
  32. gluPerspective(90, 1, 0.001, 1000.0)
  33. glEnable(GL_DEPTH_TEST)
  34. glMatrixMode(GL_MODELVIEW)
  35. rx, ry = (0,0)
  36. tx, ty = (0,0)
  37. zpos = 1
  38. rotate = move = False
  39. while 1:
  40. clock.tick(30)
  41. for e in pygame.event.get():
  42. if e.type == QUIT:
  43. sys.exit()
  44. elif e.type == KEYDOWN and e.key == K_ESCAPE:
  45. sys.exit()
  46. elif e.type == MOUSEBUTTONDOWN:
  47. if e.button == 4: zpos = max(1, zpos-1)
  48. elif e.button == 5: zpos += 1
  49. elif e.button == 1: rotate = True
  50. elif e.button == 3: move = True
  51. elif e.type == MOUSEBUTTONUP:
  52. if e.button == 1: rotate = False
  53. elif e.button == 3: move = False
  54. elif e.type == MOUSEMOTION:
  55. i, j = e.rel
  56. if rotate:
  57. rx += i
  58. ry += j
  59. if move:
  60. tx += i
  61. ty -= j
  62. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
  63. glLoadIdentity()
  64. # RENDER OBJECT
  65. glTranslate(tx/20., ty/20., - zpos)
  66. glRotate(ry, 1, 0, 0)
  67. glRotate(rx, 0, 1, 0)
  68. glCallList(obj.gl_list)
  69. pygame.display.flip()

答案1

得分: 3

  1. &lt;kbd&gt;[![][1] repl.it/@Rabbid76/pygame-opengl-wavefront-obj](https://replit.com/@Rabbid76/pygame-opengl-wavefront-obj#main.py)&lt;/kbd&gt;
  2. 不要更改顶点坐标。使用 [`glTranslate`](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml) 和 [`glScale`](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glScale.xml) 来定义模型变换。
  3. 在读取顶点坐标时计算 [轴对齐边界框](https://en.wikipedia.org/wiki/Bounding_volume):
  4. ```py
  5. class OBJ:
  6. def __init__(self, filename, swapyz=False):
  7. &quot;&quot;&quot;加载 Wavefront OBJ 文件。&quot;&quot;&quot;
  8. self.vertices = []
  9. self.normals = []
  10. self.texcoords = []
  11. self.faces = []
  12. self.min_v = [float(&quot;inf&quot;), float(&quot;inf&quot;), float(&quot;inf&quot;)]
  13. self.max_v = [-float(&quot;inf&quot;), -float(&quot;inf&quot;), -float(&quot;inf&quot;)]
  14. material = None
  15. for line in open(filename, &quot;r&quot;):
  16. if line.startswith(&#39;#&#39;): continue
  17. values = line.split()
  18. if not values: continue
  19. if values[0] == &#39;v&#39;:
  20. v = list(map(float, values[1:4]))
  21. if swapyz:
  22. v = v[0], v[2], v[1]
  23. for i in range(3):
  24. self.min_v[i] = min(self.min_v[i], v[i])
  25. self.max_v[i] = max(self.max_v[i], v[i])
  26. self.vertices.append(v)
  27. # [...]
  28. self.size = [self.max_v[i]-self.min_v[i] for i in range(3)]
  29. # [...]

在绘制对象时进行缩放和平移。使用 glPushMatrix / glPopMatrix 来保存和恢复当前矩阵,在变换前后使用:

  1. # 渲染对象
  2. glTranslate(tx/20., ty/20., - zpos)
  3. glRotate(ry, 1, 0, 0)
  4. glRotate(rx, 0, 1, 0)
  5. pos = [0, 0, -5]
  6. size = [3, 3, 10]
  7. scale = [size[i]/obj.size[i] for i in range(3)]
  8. glPushMatrix()
  9. glTranslate(*pos)
  10. glScale(*scale)
  11. glCallList(obj.gl_list)
  12. glPopMatrix()

或者也可以在显示列表中完成:

  1. self.gl_list = glGenLists(1)
  2. glNewList(self.gl_list, GL_COMPILE)
  3. glEnable(GL_TEXTURE_2D)
  4. glFrontFace(GL_CCW)
  5. glPushMatrix()
  6. glTranslate(*pos)
  7. glScale(*scale)
  8. for face in self.faces:
  9. vertices, normals, texture_coords, material = face
  10. # [...]
  11. glDisable(GL_TEXTURE_2D)
  12. glPopMatrix()
  13. glEndList()
  1. <details>
  2. <summary>英文:</summary>
  3. &lt;kbd&gt;[![][1] repl.it/@Rabbid76/pygame-opengl-wavefront-obj](https://replit.com/@Rabbid76/pygame-opengl-wavefront-obj#main.py)&lt;/kbd&gt;
  4. Do not change the vertex coordinates. Use [`glTranslate`](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml) and [`glScale`](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glScale.xml) to define a model transformation.
  5. Compute the [Axis Aligned Bounding Box](https://en.wikipedia.org/wiki/Bounding_volume), when the vertex coordinates are read:
  6. ```py
  7. class OBJ:
  8. def __init__(self, filename, swapyz=False):
  9. &quot;&quot;&quot;Loads a Wavefront OBJ file. &quot;&quot;&quot;
  10. self.vertices = []
  11. self.normals = []
  12. self.texcoords = []
  13. self.faces = []
  14. self.min_v = [float(&quot;inf&quot;), float(&quot;inf&quot;), float(&quot;inf&quot;)]
  15. self.max_v = [-float(&quot;inf&quot;), -float(&quot;inf&quot;), -float(&quot;inf&quot;)]
  16. material = None
  17. for line in open(filename, &quot;r&quot;):
  18. if line.startswith(&#39;#&#39;): continue
  19. values = line.split()
  20. if not values: continue
  21. if values[0] == &#39;v&#39;:
  22. v = list(map(float, values[1:4]))
  23. if swapyz:
  24. v = v[0], v[2], v[1]
  25. for i in range(3):
  26. self.min_v[i] = min(self.min_v[i], v[i])
  27. self.max_v[i] = max(self.max_v[i], v[i])
  28. self.vertices.append(v)
  29. # [...]
  30. self.size = [self.max_v[i]-self.min_v[i] for i in range(3)]
  31. # [...]

Scale and translate the object when it is drawn. Use glPushMatrix / glPopMatrix to save and restore the current matrix before and after the transformations:

  1. # RENDER OBJECT
  2. glTranslate(tx/20., ty/20., - zpos)
  3. glRotate(ry, 1, 0, 0)
  4. glRotate(rx, 0, 1, 0)
  5. pos = [0, 0, -5]
  6. size = [3, 3, 10]
  7. scale = [size[i]/obj.size[i] for i in range(3)]
  8. glPushMatrix()
  9. glTranslate(*pos)
  10. glScale(*scale)
  11. glCallList(obj.gl_list)
  12. glPopMatrix()

Alternatively that can be done in the display list, too:

  1. self.gl_list = glGenLists(1)
  2. glNewList(self.gl_list, GL_COMPILE)
  3. glEnable(GL_TEXTURE_2D)
  4. glFrontFace(GL_CCW)
  5. glPushMatrix()
  6. glTranslate(*pos)
  7. glScale(*scale)
  8. for face in self.faces:
  9. vertices, normals, texture_coords, material = face
  10. # [...]
  11. glDisable(GL_TEXTURE_2D)
  12. glPopMatrix()
  13. glEndList()

huangapple
  • 本文由 发表于 2020年1月6日 17:47:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/59609837.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定