Проблема реализации загрузчика ModernGL .ObjPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Проблема реализации загрузчика ModernGL .Obj

Сообщение Anonymous »

При рендеринге сцены модели Obj отображаются как случайное объединение треугольников.
Я думаю, проблема вызвана тем, как я загружаю файлы Obj, и не могу понять, как решить эту проблему. p>
функция, вызывающая проблему: load_obj_file()
process_obj.py

Код: Выделить всё

import moderngl as mgl
import numpy as np
import glm
import os

from PIL import Image

class Obj:
def __init__(self, app, filepath, mtl_filepath=None, texture_dir=None, position=glm.vec3(0, 0, 0), rotation=glm.vec3(0, 0, 0), scale=glm.vec3(1, 1, 1)):
self.ctx = app.ctx
self.filepath = filepath
self.mtl_filepath = mtl_filepath
self.texture_dir = texture_dir if texture_dir else ""

self.position = position
self.rotation = rotation
self.scale = scale

self.vertices = []
self.normals = []
self.texcoords = []
self.groups = {}
self.materials = {}
self.shader_program = None
self.textures = {}

self.load_obj_file()
self.write_obj_file()

if self.mtl_filepath:
self.load_mtl_file(self.mtl_filepath)

self.model_matrix = glm.mat4(1.0)

def write_obj_file(self):
directory = os.path.dirname(self.filepath)
output_filepath = os.path.join(directory, 'output_obj_debug.obj')

with open(output_filepath, 'w') as file:
# Write vertices
for vertex in self.vertices:
file.write(f"v {vertex[0]} {vertex[1]} {vertex[2]}\n")

# Write normals
for normal in self.normals:
file.write(f"vn {normal[0]} {normal[1]} {normal[2]}\n")

# Write texture coordinates
for texcoord in self.texcoords:
file.write(f"vt {texcoord[0]} {texcoord[1]}\n")

# Write materials and groups (if any)
for group_name, faces in self.groups.items():
file.write(f"g {group_name}\n")
for face in faces:
face_str = ' '.join([
f"{v[0]+1}/{v[1]+1}/{v[2]+1}" if v[1] is not None else f"{v[0]+1}//{v[2]+1}"
for v in face
])
file.write(f"f {face_str}\n")

print(f"OBJ file written to {output_filepath}")

def load_obj_file(self):
current_group = "default_group"
current_material = None

vertices = []
normals = []
texcoords = []
groups = {}

with open(self.filepath, 'r') as file:
for line in file:
line = line.strip()
if len(line) == 0:
continue

parts = line.split()

# Handle vertex positions (v)
if parts[0] == 'v' and len(parts) >= 4:
try:
vertex = [float(x) for x in parts[1:4]]
vertices.append(vertex)

except ValueError:
print(f"Warning: Invalid vertex data in line: {line}")
continue

# Handle normals (vn)
elif parts[0] == 'vn' and len(parts) >= 4:
try:
normal = [float(x) for x in parts[1:4]]
normals.append(normal)

except ValueError:
print(f"Warning: Invalid normal data in line: {line}")
continue

# Handle texture coordinates (vt)
elif parts[0] == 'vt' and len(parts) >= 3:
try:
texcoord = [float(x) for x in parts[1:3]]
texcoords.append(texcoord)

except ValueError:
print(f"Warning: Invalid texture data in line: {line}")
continue

# Handle groups (g)
elif parts[0] == 'g':
current_group = parts[1] if len(parts) >  1 else "default_group"
if current_group not in groups:
groups[current_group] = []

# Handle material (usemtl)
elif parts[0] == 'usemtl':
if len(parts) > 1:
current_material = parts[1]
else:
print(f"Warning: Incomplete material data in line: {line}")

# Handle faces (f)
elif parts[0] == 'f':
face_vertices = []
for vert in parts[1:]:
vertex_data = vert.split('/')

# Data follows the "vertex/texcoord/normal" format
try:
vertex_idx = int(vertex_data[0]) - 1  # 1-based to 0-based index
texcoord_idx = int(vertex_data[1]) - 1 if len(vertex_data) > 1 and vertex_data[1] else None
normal_idx = int(vertex_data[2]) - 1 if len(vertex_data) > 2 and vertex_data[2] else None

face_vertices.append((vertex_idx, texcoord_idx, normal_idx))

except ValueError:
print(f"Warning: Invalid face data in line: {line}")
continue

if current_group not in groups:
groups[current_group] = []
groups[current_group].append(face_vertices)

self.vertices = np.array(vertices, dtype=np.float32)
self.normals = np.array(normals, dtype=np.float32) if normals else np.zeros((len(vertices), 3), dtype=np.float32)
self.texcoords = np.array(texcoords, dtype=np.float32) if texcoords else np.zeros((len(vertices), 2), dtype=np.float32)
self.groups = groups

print("Vertices:", self.vertices)
print("Normals:", self.normals)
print("Texcoords:", self.texcoords)

self.process_faces()

def process_faces(self):
vertex_data = []
index_data = []
index_map = {}
index_counter = 0

for group_name, faces in self.groups.items():
print(f"Processing group: {group_name}")
for face in faces:
for vertex in face:
key = (vertex[0], vertex[1], vertex[2])
if key not in index_map:
index_map[key] = index_counter
index_counter += 1

v = self.vertices[vertex[0]]
t = self.texcoords[vertex[1]] if vertex[1] is not None else [0.0, 0.0]
n = self.normals[vertex[2]] if vertex[2] is not None else [0.0, 0.0, 0.0]

vertex_data.append([v[0], v[1], v[2], t[0], t[1], n[0], n[1], n[2]])

index_data.append(index_map[key])

self.vertex_buffer = np.array(vertex_data, dtype=np.float32)
self.index_buffer = np.array(index_data, dtype=np.uint32)

print("Vertex Buffer:", self.vertex_buffer)
print("Index Buffer:", self.index_buffer)

def load_mtl_file(self, mtl_filepath):
current_material = None
with open(mtl_filepath, 'r') as file:
for line in file:
parts = line.strip().split()
if len(parts) >  0:
if parts[0] == 'newmtl':
current_material = parts[1]
self.materials[current_material] = {}

elif parts[0] == 'map_Kd':
if current_material:

texture_filepath = os.path.join(self.texture_dir, parts[1])
print(f"Loading texture: {texture_filepath}")
self.materials[current_material]['diffuse'] = texture_filepath

def load_texture(self, texture_filepath):
try:
image = Image.open(texture_filepath)
image = image.transpose(Image.FLIP_TOP_BOTTOM)
img_data = np.array(image).astype(np.uint8)

texture = self.ctx.texture(
(image.width, image.height),
3,
img_data
)
print(f"Texture loaded: {texture_filepath}")
return texture

except FileNotFoundError as e:
print(f"Texture file not found: {texture_filepath}")
return None

def create_buffers(self):
num_vertices = len(self.vertices)
self.normals = self.normals[:num_vertices] if len(self.normals) >= num_vertices else np.pad(self.normals, ((0, num_vertices - len(self.normals)), (0, 0)), mode='constant')
self.texcoords = self.texcoords[:num_vertices] if len(self.texcoords) >= num_vertices else np.pad(self.texcoords, ((0, num_vertices - len(self.texcoords)), (0, 0)), mode='constant')

# Combine vertex attributes
attributes = np.hstack([self.vertices, self.normals, self.texcoords])

self.vbo = self.ctx.buffer(attributes)
self.vao = self.ctx.simple_vertex_array(self.shader_program, self.vbo, 'in_position', 'in_texcoord')

def set_shader(self, shader_program):
self.shader_program = shader_program
self.create_buffers()

for material_name, material in self.materials.items():
if 'diffuse' in material:
texture_filepath = material['diffuse']
texture = self.load_texture(texture_filepath)
self.textures[material_name] = texture
print(f"Texture for material {material_name} set.")

def set_position(self, position):
self.position = glm.vec3(position)

def set_rotation(self, rotation):
self.rotation = glm.vec3(rotation)

def set_scale(self, scale):
self.scale = glm.vec3(scale)

def update_model_matrix(self):
translation_matrix = glm.translate(glm.mat4(1.0), self.position)
scaling_matrix = glm.scale(glm.mat4(1.0), self.scale)

rotation_x_matrix = glm.rotate(glm.mat4(1.0), self.rotation.x, glm.vec3(1.0, 0.0, 0.0))
rotation_y_matrix = glm.rotate(glm.mat4(1.0), self.rotation.y, glm.vec3(0.0, 1.0, 0.0))
rotation_z_matrix = glm.rotate(glm.mat4(1.0), self.rotation.z, glm.vec3(0.0, 0.0, 1.0))

self.model_matrix = translation_matrix * scaling_matrix * rotation_x_matrix * rotation_y_matrix * rotation_z_matrix

def render(self, view_matrix, projection_matrix):
self.update_model_matrix()

# Pass the matrices to the shader program
self.shader_program['model'].write(self.model_matrix)
self.shader_program['view'].write(view_matrix)
self.shader_program['projection'].write(projection_matrix)

for group_name, faces in self.groups.items():
if group_name in self.textures:
texture = self.textures[group_name]
texture.use(location=0)  # Bind the texture to texture unit 0
print(f"Binding texture for group {group_name}")

self.vao.render(mgl.TRIANGLES)

def update(self):
pass
Я пытался исправить это, упростив логику, но результат был тот же, поэтому я вернулся назад.

Подробнее здесь: https://stackoverflow.com/questions/793 ... tion-issue
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Проблема реализации загрузчика ModernGL .Obj
    Anonymous » » в форуме Python
    0 Ответы
    15 Просмотры
    Последнее сообщение Anonymous
  • Ошибка загрузчика классов - безымянный модуль загрузчика org.springframework.boot.devtools.restart.classloader.RestartCl
    Anonymous » » в форуме JAVA
    0 Ответы
    26 Просмотры
    Последнее сообщение Anonymous
  • Необъявленный идентификатор «nullptr» и ошибка Obj-C при использовании библиотеки Obj-C в Swift
    Anonymous » » в форуме C++
    0 Ответы
    43 Просмотры
    Последнее сообщение Anonymous
  • «equals(Object obj)» следует переопределить вместе с методом «compareTo(T obj)».
    Anonymous » » в форуме JAVA
    0 Ответы
    37 Просмотры
    Последнее сообщение Anonymous
  • C++ QT Копирование объектов QList в другой QList
    Anonymous » » в форуме C++
    0 Ответы
    25 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Python»