В данной программе будет представлен пример, как работать с объёмными фигурами в
OpenGL на языке Python. В итоге будет представлен куб в 3-ёх мерном виде.
Среда разработки: PyCharm Community Edition 2020.1.2
Для начала работы потребуется наличие следующих инструментов или пакетов: Python, PyOpenGL, PyGame.
Как установить Python можно посмотреть на официальном сайте, ссылка на него: https://www.python.org/
Далее рассмотрим установку пакетов на Python.
Для того, чтобы загрузить PyOpenGL и PyGame, воспользуемся PyPi. В терминале IDE вводим команды:
pip install pygame pip install PyOpenGL
Загрузив все это, пишем следующий код:
import pygame import OpenGL
Если эти выражения не вызовут ошибок, значит вы готовы к дальнейшей работе. Если возникнут ошибки, значит при установке пакетов произошла ошибка, либо текущие версии пакетов несовместимы с Вашей версией Python. Более детальную информацию можно узнать в документации к используемым пакетам Python'a: PyGame и PyOpenGL.
Отлично, теперь перейдем непосредственно к коду! Если у вас еще сохранился код импорта, который мы только что запускали, сотрите его: мы начнем полностью с чистого листа.
Для начала произведем импорт необходимых библиотек:
import pygame from pygame.locals import * from OpenGL.GL import * from OpenGL.GLU import *
Мы импортируем все из PyGame, а затем все из PyGame.locals. Это вполне стандартный код для PyGame.Затем мы импортируем OpenGL.GL и OpenGL.GLU. OpenGL.GL содержит в себе самые обычные функции библиотеки OpenGL, а вот OpenGL.GLU — более сложных объектов.
Изначально создадим функцию main() для удобства:
def main():
Теперь начнем описывать нашу функцию main().
Давайте же создадим описание наших точек (вершин):
vertices= ( (1.0, -1.0, -1.0), (1.0, 1.0, -1.0), (-1.0, 1.0, -1.0), (-1.0, -1.0, -1.0), (1.0, - 1.0, 1.0), (1.0, 1.0, 1.0), (-1.0, -1.0, 1.0), (-1.0, 1.0, 1.0) )
Здесь мы определили координаты (x, y, z) каждой нашей вершины. Думаю, лучше всего представить это в относительных единицах.
Далее нам надо задать ребра:
edges = ( (0,1), (0,3), (0,4), (2,1), (2,3), (2,7), (6,3), (6,4), (6,7), (5,1), (5,4), (5,7) )
Каждое ребро представлено кортежем, состоящим из двух чисел. Эти числа соответствуют номерам вершин, а ребро их соединяет. Как принято в Python, да и во многих других языках программирования, нумерация начинается с 0. Соответственно, 0 обозначает вершину (1, -1, -1), и так далее.
Теперь, когда у нас все это есть, давайте поработаем над необходимым кодом для работы с OpenGL, чтобы фактически создать сам куб (описывать функцию Cube() мы будем вне функции main()):
def Cube(vertices, edges): glBegin(GL_LINES) for edge in edges: for vertex in edge: glVertex3fv(vertices[vertex]) glEnd()
Как обычно, мы начинаем с задания функции. Поскольку это просто функция, которая будет содержать код OpenGL, мы начинаем этот код со следующего выражения: glBegin (GL_LINES). Это уведомляет OpenGL сначала о том, что мы собираемся бросить в нее какой-то код, а затем — о том, как надо обрабатывать этот код (это указывает аргумент GL_LINES). В данном случае этот код будет рассматриваться как код для рисования линий.
Далее, мы итерируем по всем нашим ребрам (список edges), а затем каждой вершине в ребре (их там две) мы ставим в соответствие вершину из нашего списка вершин vertices (при помощи функции glVertex3fv).
glVertex3fv((1, -1, -1)) glVertex3fv((1, 1, -1))
И так далее. OpenGL, зная, что мы хотим рисовать здесь линии, проведет их между этими точками.
После прохождения всех ребер работа функции заканчивается и мы вызываем glEnd(), чтобы сообщить об этом OpenGL. Подобные открывающие и закрывающие команды используются в OpenGL постоянно.
Это все, что касается нашей функции. Она создает куб, но теперь мы хотим его отобразить и указать его перспективу в нашем окружении, для этого возвращаемся в функцию main() и пишем следующее:
pygame.init() display = (800,600) pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
Это тоже очень типичный для Pygame код. Единственное существенное отличие здесь в том, что после параметра display в функции pygame.display.set_mode мы добавляем еще один параметр. На самом деле это константы, уведомляющие PyGame о том, что мы будем использовать код OpenGL. Константа DOUBLEBUF расшифровывается как двойной буфер. Она обозначает тип буфферизации, в котором есть два буфера для соответствия кадровой частоте монитора. Обратите внимание, что для разделения констант используется символ «|». Мы еще столкнемся с ним в дальнейшем.
Идем дальше. В теле главной функции находится следующий код:
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
Функция gluPerspective определяет перспективу, о чем, впрочем, несложно догадаться из ее названия. Ее первый параметр определяет угол поля зрения и выражается в градусах. Второй параметр — это соотношение сторон дисплея, ширина, деленная на высоту. Следующие два параметра — znear и zfar, которые представляют собой ближнюю и дальнюю плоскости отсечения.
Идем дальше. У нас есть следующая функция:
glTranslatef(0.0, -1.0, -10) glRotatef(20, 10, 0, 0)
Функция glTranslatef, цитируя дословно, «умножает текущую матрицу на матрицу перехода»
Теперь напишем наш типичный цикл для отслеживания событий в PyGame:
while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit()
Это простой цикл отслеживания событий в PyGame, который определяет возможность выхода. Иными словами, он отслеживает нажатие клавиши "x". Далее, под оператором while продолжаем наш код:
glRotatef(1, 0, 1, 0) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) Cube() pygame.display.flip() pygame.time.wait(10)
Функция glRotatef умножает текущую матрицу на матрицу вращения. Ее параметрами являются угол вращения и координаты x, y, и z.
Затем у нас есть функция glClear, работающая, как любая другая функция очистки. Мы указываем в ее параметрах пару констант, которые сообщают OpenGL, что именно мы очищаем.
Как только мы очистим «экран», мы опять вызовем нашу функцию Cube ().
После этого мы вызываем функцию pygame.display.flip (), которая обновляет наш экран.
И наконец, мы вставляем небольшую задержку при помощи функции pygame.time.wait (10).
И в завершении в самой программе просто вызываем функцию main().
Код программы:
import pygame from pygame.locals import * from OpenGL.GL import * from OpenGL.GLU import * def Cube(vertices, edges): glBegin(GL_LINES) for edge in edges: for vertex in edge: glVertex3fv(vertices[vertex]) glEnd() <img src="http://grafika.me/files/les_screens/pygame-window-2020-12-24-12-22-21-_online-video-cutter.com__0.gif" width="650" height="488" alt="" title="" /> def main(): vertices = ( (1.0, -1.0, -1.0), (1.0, 1.0, -1.0), (-1.0, 1.0, -1.0), (-1.0, -1.0, -1.0), (1.0, - 1.0, 1.0), (1.0, 1.0, 1.0), (-1.0, -1.0, 1.0), (-1.0, 1.0, 1.0) ) edges = ( (0, 1), (0, 3), (0, 4), (2, 1), (2, 3), (2, 7), (6, 3), (6, 4), (6, 7), (5, 1), (5, 4), (5, 7) ) 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, -1.0, -10) glRotatef(20, 10, 0, 0) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() glRotatef(1, 0, 1, 0) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) Cube(vertices, edges) pygame.display.flip() pygame.time.wait(10) main()
Прикрепленный файл | Размер |
---|---|
main.rar | 573 байта |
Комментарии
Большое спасибо. Единственный код который прошел без каких либо ошибок. Ура!!!
огромное спасибо за подробное объяснение про 3д графику на питоне, в интернете очень мало подобной информации