#python #performance #opengl #pyopengl #opengl-compat
#python #Производительность #opengl #pyopengl #opengl-compat
Вопрос:
У меня есть класс, который создает сферу на основе переданного количества стеков, количества секторов и радиуса. Проблема в том, что всякий раз, когда я рисую сферу, моя частота кадров падает с 57-60 кадров в секунду до 20 кадров в секунду.
Вот как я рисую свою сферу:
def draw_edges(self):
"""Draws the sphere's edges"""
glPushMatrix()
glTranslate(self.position[0], self.position[1], self.position[2])
glRotate(self.rotation[3],self.rotation[0],self.rotation[1],self.rotation[2])
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
glBegin(GL_TRIANGLES)
for edge in self.edges:
for vertex in edge:
glVertex3fv(self.vertices[vertex])
glEnd()
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
glPopMatrix()
Кто-нибудь знает, как я мог бы ускорить это?
Комментарии:
1. циклы for могут быть довольно медленными в Python. Может быть, есть способ заменить два цикла for.
2. Обратите внимание, что вы используете устаревший конвейер фиксированных функций. Хотя, очевидно, поддерживается в вашей системе, это, вероятно, далеко от оптимального. Вам следует подумать о переходе на альтернативу, основанную на программируемых шейдерах.
3. Или, по крайней мере, списки отображения или VBO.
Ответ №1:
Попробуйте избавиться от вложенных циклов. Смотрите спецификацию Vertex для современного способа рисования сеток с использованием объекта Vertex Buffer и объекта Vertex Array.
Другая (устаревшая) возможность заключается в использовании фиксированных атрибутов функции.
Команды
void VertexPointer( int size, enum type, sizei stride, const void *pointer ); void NormalPointer( enum type, sizei stride, const void *pointer ); void ColorPointer( int size, enum type, sizei stride, const void *pointer ); [...]
укажите местоположение и организацию массивов для хранения координат вершин, нормалей, цветов, […] Отдельный массив включается или отключается вызовом одного из
void EnableClientState( enum array ); void DisableClientState( enum array );
с массивом, установленным в
VERTEX_ARRAY
,NORMAL_ARRAY
,COLOR_ARRAY
, […], для массива vertex, normal, color, […] соответственно.
Создайте список с данными атрибута вершины в конструкторе класса:
def __init__(self):
# [...]
self.vertexArray = []
for edge in self.edges:
for vertex in edge:
self.vertexArray.append(self.vertices[vertex])
Используйте массив, чтобы указать вершины и нарисовать сетку:
def draw_edges(self):
"""Draws the sphere's edges"""
glPushMatrix()
glTranslate(self.position[0], self.position[1], self.position[2])
glRotate(self.rotation[3],self.rotation[0],self.rotation[1],self.rotation[2])
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, self.vertexArray)
glDrawArrays(GL_TRIANGLES, 0, len(self.vertexArray))
glDisableClientState(GL_VERTEX_ARRAY)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
glPopMatrix()
Это первый (небольшой) шаг к современному решению с VBO и VAO.
Дальнейшее повышение производительности может быть достигнуто за счет использования объекта Vertex Buffer:
def __init__(self):
# [...]
self.vertexArray = []
for edge in self.edges:
for vertex in edge:
self.vertexArray = self.verticies[vertex] # <--- flat list
array = (GLfloat * len(self.vertexArray))(*self.vertexArray)
self.vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, array, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0)
def draw_edges(self):
# [...]
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glVertexPointer(3, GL_FLOAT, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glEnableClientState(GL_VERTEX_ARRAY)
glDrawArrays(GL_TRIANGLES, 0, len(self.vertexArray) // 3)
glDisableClientState(GL_VERTEX_ARRAY)
# [...]
Комментарии:
1. Спасибо! Этот метод удвоил мою частоту кадров до чуть более 40 кадров в секунду.
2. @User-92 Спасибо. Всегда пожалуйста. Дальнейшее улучшение может быть достигнуто за счет использования VBO. Я расширю ответ. Всего один момент, пожалуйста…
3. @User-92 Я расширил ответ.
4. Вау, это безумие! Теперь у меня более 70 кадров в секунду. Я не знал, что VBO могут так сильно ускорить производительность. Большое вам спасибо!
5. @User-92 Фокус в том, что массив вершин загружается в графический процессор один раз, в конструкторе. Когда вы рисуете объект, нужно ссылаться только на массив.
self.vbo
это просто идентификатор имени.