/
karik
/
sixteenth
Обзор
Документация
Войти
/
karik
/
sixteenth
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
16.py
284 строки
10 KB
karik
upload files
29 дек 2025, 23:29
29 дек 2025, 23:29
8992970
Код
Авторство
О чём код?
""" Лабораторная работа 11: Визуализация OBJ с материалами MTL Загрузка 3D-модели с материалами и отображение с помощью OpenGL """ from OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import * import sys import os class Material: """Класс для хранения параметров материала""" def __init__(self, name): self.name = name self.Ka = [0.2, 0.2, 0.2] # Ambient self.Kd = [0.8, 0.8, 0.8] # Diffuse self.Ks = [0.0, 0.0, 0.0] # Specular self.Ns = 0.0 # Shininess class OBJModel: """Класс для загрузки и хранения OBJ-модели с материалами""" def __init__(self): self.vertices = [] # Список вершин self.faces = [] # Список граней с материалами self.materials = {} # Словарь материалов self.current_material = None def load_mtl(self, filepath): """Загрузка MTL-файла""" if not os.path.exists(filepath): print(f"Предупреждение: MTL-файл {filepath} не найден") return current_material = None with open(filepath, 'r') as f: for line in f: line = line.strip() if not line or line.startswith('#'): continue parts = line.split() if not parts: continue # Новый материал if parts[0] == 'newmtl': material_name = parts[1] current_material = Material(material_name) self.materials[material_name] = current_material # Ambient цвет elif parts[0] == 'Ka' and current_material: current_material.Ka = [float(parts[1]), float(parts[2]), float(parts[3])] # Diffuse цвет (основной цвет) elif parts[0] == 'Kd' and current_material: current_material.Kd = [float(parts[1]), float(parts[2]), float(parts[3])] # Specular цвет elif parts[0] == 'Ks' and current_material: current_material.Ks = [float(parts[1]), float(parts[2]), float(parts[3])] # Shininess elif parts[0] == 'Ns' and current_material: current_material.Ns = float(parts[1]) print(f"Загружено материалов: {len(self.materials)}") for name in self.materials: print(f" - {name}: Kd = {self.materials[name].Kd}") def load_obj(self, filepath): """Загрузка OBJ-файла""" if not os.path.exists(filepath): print(f"Ошибка: OBJ-файл {filepath} не найден") return False obj_dir = os.path.dirname(filepath) with open(filepath, 'r') as f: for line in f: line = line.strip() if not line or line.startswith('#'): continue parts = line.split() if not parts: continue # Подключение MTL-файла if parts[0] == 'mtllib': mtl_file = os.path.join(obj_dir, parts[1]) self.load_mtl(mtl_file) # Вершина elif parts[0] == 'v': vertex = [float(parts[1]), float(parts[2]), float(parts[3])] self.vertices.append(vertex) # Использование материала elif parts[0] == 'usemtl': self.current_material = parts[1] # Грань elif parts[0] == 'f': # Парсинг индексов вершин (поддержка формата v, v/vt, v/vt/vn) face_vertices = [] for i in range(1, len(parts)): vertex_index = int(parts[i].split('/')[0]) - 1 # OBJ индексы с 1 face_vertices.append(vertex_index) # Сохраняем грань с текущим материалом self.faces.append({ 'vertices': face_vertices, 'material': self.current_material }) print(f"Загружено вершин: {len(self.vertices)}") print(f"Загружено граней: {len(self.faces)}") return True def draw(self): """Отрисовка модели""" for face in self.faces: # Применяем материал грани material_name = face['material'] if material_name and material_name in self.materials: material = self.materials[material_name] glColor3fv(material.Kd) # Используем диффузный цвет else: glColor3f(0.7, 0.7, 0.7) # Цвет по умолчанию # Рисуем грань vertex_indices = face['vertices'] glBegin(GL_POLYGON) for idx in vertex_indices: glVertex3fv(self.vertices[idx]) glEnd() # Глобальные переменные model = OBJModel() rotation_x = 0 rotation_y = 0 last_mouse_x = 0 last_mouse_y = 0 mouse_button_pressed = False def init_opengl(): """Инициализация OpenGL""" glClearColor(0.1, 0.1, 0.15, 1.0) # Тёмно-синий фон glEnable(GL_DEPTH_TEST) # Тест глубины glDepthFunc(GL_LESS) # Настройка проекции glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45, 1.0, 0.1, 50.0) # FOV, aspect, near, far glMatrixMode(GL_MODELVIEW) def display(): """Функция отрисовки""" glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() # Позиционирование камеры gluLookAt(3, 3, 5, # Позиция камеры 0, 0, 0, # Точка, на которую смотрим 0, 1, 0) # Вектор "вверх" # Применяем вращение glRotatef(rotation_x, 1, 0, 0) glRotatef(rotation_y, 0, 1, 0) # Рисуем модель model.draw() # Рисуем оси координат для ориентации draw_axes() glutSwapBuffers() def draw_axes(): """Отрисовка осей координат""" glLineWidth(2.0) glBegin(GL_LINES) # Ось X - красная glColor3f(1, 0, 0) glVertex3f(0, 0, 0) glVertex3f(1.5, 0, 0) # Ось Y - зелёная glColor3f(0, 1, 0) glVertex3f(0, 0, 0) glVertex3f(0, 1.5, 0) # Ось Z - синяя glColor3f(0, 0, 1) glVertex3f(0, 0, 0) glVertex3f(0, 0, 1.5) glEnd() glLineWidth(1.0) def keyboard(key, x, y): """Обработка клавиатуры""" global rotation_x, rotation_y if key == b'\x1b': # ESC sys.exit() elif key == b'r': # Reset rotation_x = 0 rotation_y = 0 glutPostRedisplay() def mouse(button, state, x, y): """Обработка кликов мыши""" global mouse_button_pressed, last_mouse_x, last_mouse_y if button == GLUT_LEFT_BUTTON: if state == GLUT_DOWN: mouse_button_pressed = True last_mouse_x = x last_mouse_y = y else: mouse_button_pressed = False def motion(x, y): """Обработка движения мыши""" global rotation_x, rotation_y, last_mouse_x, last_mouse_y if mouse_button_pressed: dx = x - last_mouse_x dy = y - last_mouse_y rotation_y += dx * 0.5 rotation_x += dy * 0.5 last_mouse_x = x last_mouse_y = y glutPostRedisplay() def idle(): """Функция автоматического вращения (опционально)""" pass def main(): """Главная функция""" print("=" * 60) print("Лабораторная работа 11: OBJ + MTL Viewer") print("=" * 60) # Загрузка модели obj_file = 'model.obj' if not model.load_obj(obj_file): print(f"Не удалось загрузить {obj_file}") sys.exit(1) # Инициализация GLUT glutInit(sys.argv) glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) glutInitWindowSize(800, 800) glutInitWindowPosition(100, 100) glutCreateWindow(b"Lab 11: OBJ Viewer with MTL Materials") # Настройка OpenGL init_opengl() # Регистрация callback-функций glutDisplayFunc(display) glutKeyboardFunc(keyboard) glutMouseFunc(mouse) glutMotionFunc(motion) glutIdleFunc(idle) print("\nУправление:") print(" - Мышь: зажмите левую кнопку и перемещайте для вращения") print(" - R: сброс вращения") print(" - ESC: выход") print("\nМодель загружена успешно!") # Запуск главного цикла glutMainLoop() if __name__ == '__main__': main()