有没有办法在 Pygame 中更改导入的 .obj 文件的位置和大小? [英] Is there a way to change the location and size of an imported .obj file in Pygame?

查看:69
本文介绍了有没有办法在 Pygame 中更改导入的 .obj 文件的位置和大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用搅拌机创建了一个 .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()

推荐答案

不要改变顶点坐标.使用 glTranslateglScale 定义模型转换.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆