0 Pluspunkte 0 Minuspunkte

Ich habe die Dateien Cube.obj, Cube.mtl und texture.jpg. Wie kann ich mit PyGame den Cube aus einer obj Datei laden (inkl Textur) und den rotieren lassen?

import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *


def main():
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
    
    gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)
    glTranslatef(0.0, 0.0, -5)


    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        
        pygame.display.flip()
        


if __name__ == "__main__":
    main()

von  

1 Antwort

0 Pluspunkte 0 Minuspunkte

Installiere das Modul PIL für die Textur.

from PIL import Image

Zuerst benötigst du eine Funktion, die die Daten aus der obj Datei lädt. Diese Dateien beinhalten die Informationen über die Geometrie, also wie das Modell aufgebaut ist. Das sind die Vertex-Koordinaten, die Flächen die aus den Vertex-Koordinaten gebildet werden, die Normalen (rechten Winkel) auf diesen Flächen und eben auch die Texturkoordinaten und das verwendete Material.

def load_obj(file_path):
    vertices = []
    textures = []
    normals = []
    faces = []
    current_material = None

    with open(file_path, 'r') as f:
        for line in f:
            parts = line.strip().split()
            if not parts:
                continue
            if parts[0] == 'usemtl':
                current_material = parts[1]
            elif parts[0] == 'v':
                vertex = list(map(float, parts[1:]))
                vertices.append(vertex)
            elif parts[0] == 'vt':
                texture = list(map(float, parts[1:]))
                textures.append(texture)
            elif parts[0] == 'vn':
                normal = list(map(float, parts[1:]))
                normals.append(normal)
            elif parts[0] == 'f':
                face = parts[1:]
                face_data = []
                for vertex_data in face:
                    indices = vertex_data.split('/')
                    vertex_index = int(indices[0]) - 1
                    texture_index = int(indices[1]) - 1
                    normal_index = int(indices[2]) - 1
                    face_data.append((vertex_index, texture_index, normal_index, current_material))
                faces.append(face_data)

    return vertices, textures, normals, faces

In der .mtl Datei wird das Material für das Objekt definiert. Die Texturkoordinaten in der .obj-Datei verweisen auf die Texturen, die im .mtl-Datei definiert sind.

def load_mtl(file_path):
    materials = {}
    current_material = None

    with open(file_path, 'r') as f:
        for line in f:
            parts = line.strip().split()
            if not parts:
                continue
            if parts[0] == 'newmtl':
                current_material = parts[1]
                materials[current_material] = {}
            elif current_material is not None:
                materials[current_material][parts[0]] = parts[1:]
    
    return materials

Eine Funktion um die Textur selbst zu laden, welche in der mtl Datei verlinkt ist.

def load_texture(file_path):
    img = Image.open(file_path)
    img_data = img.tobytes()
    texture_id = glGenTextures(1)
    
    glBindTexture(GL_TEXTURE_2D, texture_id)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width, img.height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    
    return texture_id

Dann benötigstdu noch eine Funktion um das Objekt mit Textur zu zeichnen

def draw_obj(vertices, textures, normals, faces, materials):
    glEnable(GL_TEXTURE_2D)
    
    for face in faces:
        glBegin(GL_TRIANGLES)
        for vertex_data in face:
            vertex_index, texture_index, normal_index, material_name = vertex_data
            material = materials.get(material_name, {})
            if 'Kd' in material:
                glColor3fv(list(map(float, material['Kd'])))
            glTexCoord2fv(textures[texture_index])
            glVertex3fv(vertices[vertex_index])
        glEnd()

In der Main Funktion vor dem Eventloop lädst du das Objekt

materials = load_mtl('cube.mtl')  
vertices, textures, normals, faces = load_obj('cube.obj') 
    
# Hier wird zur Vereinfachung nur das erste Material geladen
material_name = faces[0][0][3]
texture_file = materials[material_name]['map_Kd'][0]
texture_id = load_texture(texture_file)

und in der Schleife zeichnest du es

draw_obj(vertices, textures, normals, faces, materials)



Hier nochmal das ganze Beispiel

import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from PIL import Image


def load_texture(file_path):
    img = Image.open(file_path)
    img_data = img.tobytes()
    texture_id = glGenTextures(1)
    
    glBindTexture(GL_TEXTURE_2D, texture_id)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width, img.height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    
    return texture_id

def load_mtl(file_path):
    materials = {}
    current_material = None

    with open(file_path, 'r') as f:
        for line in f:
            parts = line.strip().split()
            if not parts:
                continue
            if parts[0] == 'newmtl':
                current_material = parts[1]
                materials[current_material] = {}
            elif current_material is not None:
                materials[current_material][parts[0]] = parts[1:]
    
    return materials

def load_obj(file_path):
    vertices = []
    textures = []
    normals = []
    faces = []
    current_material = None

    with open(file_path, 'r') as f:
        for line in f:
            parts = line.strip().split()
            if not parts:
                continue
            if parts[0] == 'usemtl':
                current_material = parts[1]
            elif parts[0] == 'v':
                vertex = list(map(float, parts[1:]))
                vertices.append(vertex)
            elif parts[0] == 'vt':
                texture = list(map(float, parts[1:]))
                textures.append(texture)
            elif parts[0] == 'vn':
                normal = list(map(float, parts[1:]))
                normals.append(normal)
            elif parts[0] == 'f':
                face = parts[1:]
                face_data = []
                for vertex_data in face:
                    indices = vertex_data.split('/')
                    vertex_index = int(indices[0]) - 1
                    texture_index = int(indices[1]) - 1
                    normal_index = int(indices[2]) - 1
                    face_data.append((vertex_index, texture_index, normal_index, current_material))
                faces.append(face_data)

    return vertices, textures, normals, faces

def draw_obj(vertices, textures, normals, faces, materials):
    glEnable(GL_TEXTURE_2D)
    
    for face in faces:
        glBegin(GL_TRIANGLES)
        for vertex_data in face:
            vertex_index, texture_index, normal_index, material_name = vertex_data
            material = materials.get(material_name, {})
            if 'Kd' in material:
                glColor3fv(list(map(float, material['Kd'])))
            glTexCoord2fv(textures[texture_index])
            glVertex3fv(vertices[vertex_index])
        glEnd()

def main():
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
    
    gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)
    glTranslatef(0.0, 0.0, -5)
    
    materials = load_mtl('cube.mtl')  # Replace with your .mtl file
    vertices, textures, normals, faces = load_obj('cube.obj')  # Replace with your .obj file
    
    # Load the first material's texture (you can modify this logic as needed)
    material_name = faces[0][0][3]
    texture_file = materials[material_name]['map_Kd'][0]
    texture_id = load_texture(texture_file)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        
        glRotatef(1, 3, 1, 1)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        
        draw_obj(vertices, textures, normals, faces, materials)

        pygame.display.flip()
        
        pygame.time.wait(10)

if __name__ == "__main__":
    main()
von  
Wo müssen die ganzen Funktionen genau hin?
Ich habe ein komplettes Beispiel hinzugefügt, du musst nur noch die Dateinamen anpassen.