저는 PyQt5와 PyOpenGL을 사용하여 작은 응용 프로그램을 만들려고합니다. 모든 것은 잘 작동하지만, 단 하나의 구로 렌더링이 너무 오래 걸립니다. 나는 시도하고 응용 프로그램의 속도를 최적화하는 다른 경로를 시도하고 지금은 OpenGLSurface와 간단한 QWindow를 사용하고 있습니다.PyQt5 OpenGL swapBuffers 매우 느림
나는 그것이 완료하는 데 오랜 시간이 걸리는 context.swapBuffers 호출이라는 것을 알아 냈다. 1 개의 구면에 약간의 음영과 240 개의 정점을 표시 할 때 0.01 초 (괜찮습니다)와 0.05 초 (길다)입니다.
내 질문은 다음과 같습니다. 정상입니까? 그렇다면이 프로세스의 속도를 높이는 방법이 있습니까? 아니면 pyqt가 작동하는 것과 관련이 있습니까? 파이썬이 라이브러리를 감싸고 있기 때문입니다. 기본적으로 : C++을 배울 필요없이이 프로그램을 계속 개발할 수있는 방법이 있습니까? 그것은 단지 원자 구조를 시각화하고 그것을 조작 할 수 있어야하는 아주 간단한 어플리케이션입니다.
pyopengl에서 OpenGL로 작업 할 때 오버 헤드가 적을 수있는 다른 gui 툴킷이 있습니까?
이
가 렌더링을 수행하는 정의입니다 :fmt = QSurfaceFormat()
fmt.setVersion(4, 2)
fmt.setProfile(QSurfaceFormat.CoreProfile)
fmt.setSamples(4)
fmt.setSwapInterval(1)
QSurfaceFormat.setDefaultFormat(fmt)
EDIT1 : 직접 Qt는 OpenGL을 정의를 사용하지 않고
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을 사용하고를, 표면의 형식이 주어진다 : 내 코드 작동 방식에 대한 몇 가지 설명 :
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()
최종 정보 : 쉐이더에 필요한 모든 버텍스 정보는 내가 초기화하고 초기화 정의에서 이전에 바인딩 한 바우트를 통해 제공되며 너무 많은 객체를 포함하지 않습니다. (저는 단지 테스트 중이며 다음과 같은 20 면체를 사용합니다. 구체를 렌더링하는 2 개의 구획, 또한 복제 된 버텍스를 제거했지만 실제로는 병목 현상이 없어야하므로 아무 것도하지 않았습니다.)
몇 가지 질문에 대답하려면 : 나는 gigglez, 변경 사항 없음, vsync없이 시도, 아무것도 변경하지 않고 다른 샘플 크기로 시도했지만 변경되지 않은 다른 버전의 OpenGL을 사용해 보았습니다.
Edit2가 : 단서가 될 수 있음 다음 swapBuffers 시간의 약 0.015s 가장 필요하지만, 내가 많이 주위에 움직이기 시작하면, 그것은 더듬 일부는 렌더링에 대한 0.05s까지 이동합니다. 왜 이런 일이 일어나는 걸까요? 내가 아는 바로는 모든 렌더링이 모든 데이터를 처리해야합니다.
스왑 간격을 '0'으로 설정하여 vsync를 끄려고 했습니까? 비교할 단일 버퍼링 된 컨텍스트를 시도 했습니까? – thokra
'context.swapBuffers' *가 렌더링 파이프 라인을 플러시해야하는 지점이기 때문에 병목 현상으로 보입니다. 버퍼를 교체하기 전에 보류중인 모든 작업을 완료해야하기 때문입니다. 난 당신이 렌더링 코드 또는 선호하는 [mcve] (http://stackoverflow.com/help/mcve) 표시해야 할 것 같아요. –