有没有办法在 Pygame 中更改导入的 .obj 文件的位置和大小? [英] Is there a way to change the location and size of an imported .obj file in Pygame?
问题描述
我使用搅拌机创建了一个 .obj 文件,并使用 skrx 建议的 OBJfileloader 加载到 Pygame 中:OBJFileLoader 中的错误
I created an .obj file using blender and loaded into Pygame using the OBJfileloader as sugested by skrx in: Error in OBJFileLoader
有没有一种简单的方法可以在将导入的 .obj 文件导入 Pygame 后更改其位置、高度和宽度?例如,如果您创建一个 tree.obj 文件,是否能够将同一棵树放置在不同大小的不同位置?
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?
按照下面的代码,可能是这样的:
Following the code below, maybe something like:
object_obj = OBJ("Tree.obj", swapyz=False)
object_obj.setX = 0
object_obj.setWidth = 3
object_obj.setHeight =10
或者通过向 obj 加载器发送额外的参数来改变顶点?
Or by sending extra parameters to the obj loader, changing the vertices?
OBJ 加载器:
import pygame
from OpenGL.GL import *
def MTL(filename):
filename = 'OBJ/'+filename
contents = {}
mtl = None
for line in open(filename, "r"):
if line.startswith('#'): continue
values = line.split()
if not values: continue
if values[0] == 'newmtl':
mtl = contents[values[1]] = {}
elif mtl is None:
raise ValueError("mtl file doesn't start with newmtl stmt")
elif values[0] == 'map_Kd':
# load the texture referred to by this declaration
mtl[values[0]] = values[1]
surf = pygame.image.load(mtl['map_Kd'])
image = pygame.image.tostring(surf, 'RGBA', 1)
ix, iy = surf.get_rect().size
texid = mtl['texture_Kd'] = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texid)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ix, iy, 0, GL_RGBA,
GL_UNSIGNED_BYTE, image)
else:
mtl[values[0]] = list(map(float, values[1:]))
return contents
class OBJ:
def __init__(self, filename, swapyz=False):
"""Loads a Wavefront OBJ file. """
self.vertices = []
self.normals = []
self.texcoords = []
self.faces = []
material = None
for line in open(filename, "r"):
if line.startswith('#'): continue
values = line.split()
if not values: continue
if values[0] == 'v':
v = list(map(float, values[1:4]))
if swapyz:
v = v[0], v[2], v[1]
self.vertices.append(v)
elif values[0] == 'vn':
v = list(map(float, values[1:4]))
if swapyz:
v = v[0], v[2], v[1]
self.normals.append(v)
elif values[0] == 'vt':
self.texcoords.append(list(map(float, values[1:3])))
elif values[0] in ('usemtl', 'usemat'):
material = values[1]
elif values[0] == 'mtllib':
self.mtl = MTL(values[1])
elif values[0] == 'f':
face = []
texcoords = []
norms = []
for v in values[1:]:
w = v.split('/')
face.append(int(w[0]))
if len(w) >= 2 and len(w[1]) > 0:
texcoords.append(int(w[1]))
else:
texcoords.append(0)
if len(w) >= 3 and len(w[2]) > 0:
norms.append(int(w[2]))
else:
norms.append(0)
self.faces.append((face, norms, texcoords, material))
self.gl_list = glGenLists(1)
glNewList(self.gl_list, GL_COMPILE)
glEnable(GL_TEXTURE_2D)
glFrontFace(GL_CCW)
for face in self.faces:
vertices, normals, texture_coords, material = face
mtl = self.mtl[material]
if 'texture_Kd' in mtl:
# use diffuse texmap
glBindTexture(GL_TEXTURE_2D, mtl['texture_Kd'])
else:
# just use diffuse colour
glColor(*mtl['Kd'])
glBegin(GL_POLYGON)
for i in range(len(vertices)):
if normals[i] > 0:
glNormal3fv(self.normals[normals[i] - 1])
if texture_coords[i] > 0:
glTexCoord2fv(self.texcoords[texture_coords[i] - 1])
glVertex3fv(self.vertices[vertices[i] - 1])
glEnd()
glDisable(GL_TEXTURE_2D)
glEndList()
在 Pygame 中显示 .OBJ 文件:
Displaying .OBJ file in Pygame:
# Basic OBJ file viewer. needs objloader from:
# http://www.pygame.org/wiki/OBJFileLoader
# LMB + move: rotate
# RMB + move: pan
# Scroll wheel: zoom in/out
import sys, pygame
from pygame.locals import *
from pygame.constants import *
from OpenGL.GL import *
from OpenGL.GLU import *
# IMPORT OBJECT LOADER
from OBJ_Loader import *
pygame.init()
viewport = (800,600)
hx = viewport[0]/2
hy = viewport[1]/2
srf = pygame.display.set_mode(viewport, OPENGL | DOUBLEBUF)
glLightfv(GL_LIGHT0, GL_POSITION, (-40, 200, 100, 0.0))
glLightfv(GL_LIGHT0, GL_AMBIENT, (0.2, 0.2, 0.2, 1.0))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.5, 0.5, 0.5, 1.0))
glEnable(GL_LIGHT0)
glEnable(GL_LIGHTING)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_DEPTH_TEST)
glShadeModel(GL_SMOOTH) # most obj files expect to be smooth-shaded
# LOAD OBJECT AFTER PYGAME INIT
object_obj = OBJ("Tree.obj", swapyz=False)
clock = pygame.time.Clock()
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
width, height = viewport
gluPerspective(90, 1, 0.001, 1000.0)
glEnable(GL_DEPTH_TEST)
glMatrixMode(GL_MODELVIEW)
rx, ry = (0,0)
tx, ty = (0,0)
zpos = 1
rotate = move = False
while 1:
clock.tick(30)
for e in pygame.event.get():
if e.type == QUIT:
sys.exit()
elif e.type == KEYDOWN and e.key == K_ESCAPE:
sys.exit()
elif e.type == MOUSEBUTTONDOWN:
if e.button == 4: zpos = max(1, zpos-1)
elif e.button == 5: zpos += 1
elif e.button == 1: rotate = True
elif e.button == 3: move = True
elif e.type == MOUSEBUTTONUP:
if e.button == 1: rotate = False
elif e.button == 3: move = False
elif e.type == MOUSEMOTION:
i, j = e.rel
if rotate:
rx += i
ry += j
if move:
tx += i
ty -= j
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
# RENDER OBJECT
glTranslate(tx/20., ty/20., - zpos)
glRotate(ry, 1, 0, 0)
glRotate(rx, 0, 1, 0)
glCallList(obj.gl_list)
pygame.display.flip()
推荐答案
不要改变顶点坐标.使用 glTranslate
和 glScale
定义模型转换.
Do not change the vertex coordinates. Use glTranslate
and glScale
to define a model transformation.
在读取顶点坐标时计算轴对齐边界框:
Compute the Axis Aligned Bounding Box, when the vertex coordinates are read:
class OBJ:
def __init__(self, filename, swapyz=False):
"""Loads a Wavefront OBJ file. """
self.vertices = []
self.normals = []
self.texcoords = []
self.faces = []
self.min_v = [float("inf"), float("inf"), float("inf")]
self.max_v = [-float("inf"), -float("inf"), -float("inf")]
material = None
for line in open(filename, "r"):
if line.startswith('#'): continue
values = line.split()
if not values: continue
if values[0] == 'v':
v = list(map(float, values[1:4]))
if swapyz:
v = v[0], v[2], v[1]
for i in range(3):
self.min_v[i] = min(self.min_v[i], v[i])
self.max_v[i] = max(self.max_v[i], v[i])
self.vertices.append(v)
# [...]
self.size = [self.max_v[i]-self.min_v[i] for i in range(3)]
# [...]
在绘制对象时缩放和平移对象.使用 glPushMatrix
/glPopMatrix
保存和恢复变换前后的当前矩阵:
Scale and translate the object when it is drawn. Use glPushMatrix
/ glPopMatrix
to save and restore the current matrix before and after the transformations:
# RENDER OBJECT
glTranslate(tx/20., ty/20., - zpos)
glRotate(ry, 1, 0, 0)
glRotate(rx, 0, 1, 0)
pos = [0, 0, -5]
size = [3, 3, 10]
scale = [size[i]/obj.size[i] for i in range(3)]
glPushMatrix()
glTranslate(*pos)
glScale(*scale)
glCallList(obj.gl_list)
glPopMatrix()
或者,也可以在显示列表中完成:
Alternatively that can be done in the display list, too:
self.gl_list = glGenLists(1)
glNewList(self.gl_list, GL_COMPILE)
glEnable(GL_TEXTURE_2D)
glFrontFace(GL_CCW)
glPushMatrix()
glTranslate(*pos)
glScale(*scale)
for face in self.faces:
vertices, normals, texture_coords, material = face
# [...]
glDisable(GL_TEXTURE_2D)
glPopMatrix()
glEndList()
这篇关于有没有办法在 Pygame 中更改导入的 .obj 文件的位置和大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!