我試圖讓使用PyQt5和PyOpenGL一個小應用程序。一切正常,但即使只有一個球體,渲染也需要很長時間。我嘗試了不同的路線來嘗試優化應用程序的速度,現在我正在使用帶有OpenGLSurface的簡單QWindow。PyQt5的OpenGL swapBuffers很慢
我設法弄清楚,它是context.swapBuffers調用需要很長的時間才能完成,大約之間變化。 0.01s(這很好)和0.05s(這是很長的一段時間),當顯示一個帶有一些陰影和240個頂點的球體時。
現在我的問題如下:這是正常的嗎?如果是這樣,有沒有辦法加快這個過程,或者這與pyqt的工作方式有關,因爲它是一個圍繞庫的python包裝?基本上:有沒有辦法讓我繼續開發這個程序,而不需要學習C++。這是一個相當簡單的應用程序,只需要可視化一些原子結構並能夠操縱它。
是否有其他GUI工具包從pyopengl OpenGL的工作時,我可能會使用較少的開銷?
這是做渲染的定義:
fmt = QSurfaceFormat()
fmt.setVersion(4, 2)
fmt.setProfile(QSurfaceFormat.CoreProfile)
fmt.setSamples(4)
fmt.setSwapInterval(1)
QSurfaceFormat.setDefaultFormat(fmt)
EDIT1:
def renderNow(self):
if not self.isExposed():
return
self.m_update_pending = False
needsInitialize = False
if self.m_context is None:
self.m_context = QOpenGLContext(self)
self.m_context.setFormat(self.requestedFormat())
self.m_context.create()
needsInitialize = True
self.m_context.makeCurrent(self)
if needsInitialize:
self.m_gl = self.m_context.versionFunctions()
self.m_gl.initializeOpenGLFunctions()
self.initialize()
self.render()
self.m_context.swapBuffers(self)
if self.m_animating:
self.renderLater()
我使用OpenGL的情況下直接使用Qt OpenGL的定義,表面格式爲: 關於我的代碼如何工作的更多說明:
def render(self):
t1 = time.time()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
wtvMatrix = self.camera.get_wtv_mat()
transformMatrix = matrices.get_projection_matrix(60, self.width()/self.height(), 0.1, 30, matrix=wtvMatrix)
transformMatrixLocation = glGetUniformLocation(self.shader,"transformMatrix")
glUniformMatrix4fv(transformMatrixLocation,1,GL_FALSE,transformMatrix)
eye_pos_loc = glGetUniformLocation(self.shader, "eye_world_pos0")
glUniform3f(eye_pos_loc, self.camera.position[0], self.camera.position[1], self.camera.position[2])
glDrawElementsInstanced(GL_TRIANGLES,self.num_vertices,GL_UNSIGNED_INT,None,self.num_objects)
print("drawing took:{}".format(time.time()-t1))
self.frame+=1
t1=time.time()
self.m_context.swapBuffers(self)
print('swapping buffers took:{}'.format(time.time()-t1))
這是我調用的唯一drawElementsInstanced。着色器設置如下(遺憾的混亂):
VERTEX_SHADER = compileShader("""#version 410
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec3 vertex_colour;
layout(location = 2) in vec3 vertex_normal;
layout(location = 3) in mat4 model_mat;
layout(location = 7) in float mat_specular_intensity;
layout(location = 8) in float mat_specular_power;
uniform mat4 transformMatrix;
uniform vec3 eye_world_pos0;
out vec3 normal0;
out vec3 colour;
out vec3 world_pos;
out float specular_intensity;
out float specular_power;
out vec3 eye_world_pos;
void main() {
colour = vertex_colour;
normal0 = (model_mat*vec4(vertex_normal,0.0)).xyz;
world_pos = (model_mat*vec4(vertex_position,1.0)).xyz;
eye_world_pos = eye_world_pos0;
specular_intensity = mat_specular_intensity;
specular_power = mat_specular_power;
gl_Position = transformMatrix*model_mat*vec4(vertex_position,1.0);
}""", GL_VERTEX_SHADER)
FRAGMENT_SHADER = compileShader("""#version 410
in vec3 colour;
in vec3 normal0;
in vec3 world_pos;
in float specular_intensity;
in float specular_power;
in vec3 eye_world_pos;
out vec4 frag_colour;
struct directional_light {
vec3 colour;
float amb_intensity;
float diff_intensity;
vec3 direction;
};
uniform directional_light gdirectional_light;
void main() {
vec4 ambient_colour = vec4(gdirectional_light.colour * gdirectional_light.amb_intensity,1.0f);
vec3 light_direction = -gdirectional_light.direction;
vec3 normal = normalize(normal0);
float diffuse_factor = dot(normal,light_direction);
vec4 diffuse_colour = vec4(0,0,0,0);
vec4 specular_colour = vec4(0,0,0,0);
if (diffuse_factor>0){
diffuse_colour = vec4(gdirectional_light.colour,1.0f) * gdirectional_light.diff_intensity*diffuse_factor;
vec3 vertex_to_eye = normalize(eye_world_pos-world_pos);
vec3 light_reflect = normalize(reflect(gdirectional_light.direction,normal));
float specular_factor = dot(vertex_to_eye, light_reflect);
if(specular_factor>0) {
specular_factor = pow(specular_factor,specular_power);
specular_colour = vec4(gdirectional_light.colour*specular_intensity*specular_factor,1.0f);
}
}
frag_colour = vec4(colour,1.0)*(ambient_colour+diffuse_colour+specular_colour);
}""", GL_FRAGMENT_SHADER)
現在,當我想旋轉的情景,我使用的代碼如下(相機更新等作爲正常AFAIK完成):
def mouseMoveEvent(self, event):
dx = event.x() - self.lastPos.x()
dy = event.y() - self.lastPos.y()
self.lastPos = event.pos()
if event.buttons() & QtCore.Qt.RightButton:
self.camera.mouse_update(dx,dy)
elif event.buttons()& QtCore.Qt.LeftButton:
pass
self.renderNow()
最後的一些信息:在着色器所需的所有頂點信息通過我初始化和更早版本的初始化定義綁定一個給定的VAO,並不包含太多的對象(我只是測試它使用一個二十面體與2個細分來渲染一個球體,同樣,我刪除了重複的頂點,但是這並沒有做任何事情,因爲這實際上不應該是我認爲的瓶頸)。
要回答一些問題:我做了只爲gigglez雜色山雀不同版本的OpenGL的嘗試,沒有任何變化,嘗試沒有垂直同步,沒有什麼變化,試圖用不同的樣本大小,沒有變化。
EDIT2: 可能是一個線索:swapBuffers大約需要0.015s的大部分時間,但是當我開始周圍有很多動人,口吃以及跳起來0.05S一些渲染。這是爲什麼發生?據我所知,每個渲染都必須處理所有的數據呢?
您是否嘗試通過將交換間隔設置爲'0'來關閉vsync?您是否嘗試過單緩衝上下文比較? – thokra
我懷疑'context.swapBuffers' *出現*是瓶頸,因爲這是渲染管道必須刷新的地方 - 所有掛起的操作必須在緩衝區交換之前完成。我認爲你需要顯示你的渲染代碼或最好是[mcve](http://stackoverflow.com/help/mcve)。 –