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()