我正在熟悉 ModernGL,特别是渲染到各个 glfw 窗口。我计划在单个应用程序中拥有多个 glfw 窗口,每个窗口都包含在自己的 QtWidgets (PyQt5) 中,每个窗口具有独特的几何形状和纹理渲染,并在它们自己的单独线程上进行。但是,我在将简单的彩色三角形渲染到两个 glfw 窗口时遇到了麻烦。
请参阅下面的示例代码:
import glfw
import moderngl
import numpy as np
# Initialize glfw
if not glfw.init():
raise Exception("glfw can not be initialized!")
# Create the first windowed mode window and its OpenGL context. We call it window 1.
window1 = glfw.create_window(400, 400, "OpenGL Window 1", None, None)
if not window1:
glfw.terminate()
raise Exception("glfw window can not be created!")
# Make the window's context current
glfw.make_context_current(window1)
# Create ModernGL context
ctx1 = moderngl.create_context()
# Create the second windowed mode window and its OpenGL context. We call it window 2.
window2 = glfw.create_window(400, 400, "OpenGL Window 2", None, None)
if not window2:
glfw.terminate()
raise Exception("glfw window can not be created!")
# Make the window's context current
glfw.make_context_current(window2)
# Create ModernGL context
ctx2 = moderngl.create_context()
print(ctx1)
print(ctx2)
print(window1)
print(window2)
# Create a simple shader program for ctx1
prog1 = ctx1.program(
vertex_shader="""
#version 330 core
in vec3 in_position;
void main() {
gl_Position = vec4(in_position, 1.0);
}
""",
fragment_shader="""
#version 330 core
layout (location = 0) out vec4 fragColor;
void main() {
vec3 color = vec3(1, 0, 0);
fragColor = vec4(color, 1.0);
}
"""
)
# Create a simple shader program for ctx2
prog2 = ctx2.program(
vertex_shader="""
#version 330 core
in vec3 in_position;
void main() {
gl_Position = vec4(in_position, 1.0);
}
""",
fragment_shader="""
#version 330 core
layout (location = 0) out vec4 fragColor;
void main() {
vec3 color = vec3(1, 0, 0);
fragColor = vec4(color, 1.0);
}
"""
)
print(prog1)
print(prog2)
vertices = np.array([
0.5, 0.0, 0.0,
0.25, 0.5, 0.0,
0.0, 0.0, 0.0,
], dtype='f4')
vbo1 = ctx1.buffer(vertices.tobytes())
vao1 = ctx1.vertex_array(prog1, [(vbo1, '3f', 'in_position')])
vbo2 = ctx2.buffer(vertices.tobytes())
vao2 = ctx2.vertex_array(prog2, [(vbo2, '3f', 'in_position')])
# Render to window1
glfw.make_context_current(window1)
print("Current context: ", ctx1, "Current window (Should be window 1): ", window1)
FrameBuffer1 = ctx1.detect_framebuffer()
print(f"Framebuffer ID for ctx1: {FrameBuffer1.glo}")
ctx1.clear(0.0, 1.0, 1.0, 1.0)
vao1.render(moderngl.TRIANGLES)
glfw.swap_buffers(window1)
glfw.make_context_current(None)
# Render to window2
glfw.make_context_current(window2)
print("Current context: ", ctx2, "Current window: (Should be window 2)", window2)
FrameBuffer2 = ctx2.detect_framebuffer()
print(f"Framebuffer ID for ctx2: {FrameBuffer2.glo}")
ctx2.clear(1.0, 1.0, 0.0, 1.0)
vao2.render(moderngl.TRIANGLES)
glfw.swap_buffers(window2)
glfw.make_context_current(None)
# Hold the windows open until they are closed
while not glfw.window_should_close(window1) and not glfw.window_should_close(window2):
# Poll for and process events
glfw.poll_events()
# Terminate glfw
glfw.terminate()
这是渲染结果: 红色三角形仅渲染到第二个窗口
我已经仔细检查了片段着色器中的 RGB/Alpha 值。我相信我正确地将各自的上下文设置为当前上下文,然后根据需要发布它们。我添加了调试打印输出来验证以下对象的唯一性:
ModernGL Context 1
ModernGL Context 2
glfw Window 1
glfw Window 2
ModernGL Context 1 Shader Program
ModernGL Context 2 Shader Program
Current context/window prior to attempting to render to window 1
Framebuffer ID with respect to context 1
Current context/window prior to attempting to render to window 2
Framebuffer ID with respect to context 2
调试打印输出为:
<moderngl.Context object at 0x0000022CB0A2AD20>
<moderngl.Context object at 0x0000022CB0A2BD40>
<glfw.LP__GLFWwindow object at 0x0000022CB0A408D0>
<glfw.LP__GLFWwindow object at 0x0000022CDF34F3D0>
<moderngl.Program object at 0x0000022CDF2724E0>
<moderngl.Program object at 0x0000022CDF2BAEA0>
Current context: <moderngl.Context object at 0x0000022CB0A2AD20> Current window (Should be window 1): <glfw.LP__GLFWwindow object at 0x0000022CB0A408D0>
Framebuffer ID for ctx1: 0
Current context: <moderngl.Context object at 0x0000022CB0A2BD40> Current window: (Should be window 2) <glfw.LP__GLFWwindow object at 0x0000022CDF34F3D0>
Framebuffer ID for ctx2: 0
因此,我相信我有两个独特的 ModernGL 上下文,每个上下文都有自己的 glfw 窗口、着色器程序和帧缓冲区。
我一直不明白为什么我没有两个三角形而只有一个,我在尝试浏览 ModernGL 和 OpenGL 文档时问了这个问题。
关于为什么会发生这种行为以及我可以采取什么方法来解决这个问题有什么想法吗?这是我在调用“moderngl.create_context()”时必须共享上下文的问题吗(即“ctx2=moderngl.create_context(shared=ctx1)”)?在一些尝试解决此问题的代码中,我确实成功地使用共享 ModernGL 上下文和共享着色器程序创建了多个 glfw 窗口,但我只能渲染白色三角形,并且三角形不是红色;让我觉得也许这样的方向并不正确。
看来我能够找到解决这个问题的方法。
解决方案:在着色器创建和 vao/vbo 定义之前和之后添加 glfw.make_context_current() 语句:
import glfw
import moderngl
import numpy as np
# Initialize glfw
if not glfw.init():
raise Exception("glfw can not be initialized!")
# Create a windowed mode window and its OpenGL context
window1 = glfw.create_window(400, 400, "OpenGL Window 1", None, None)
if not window1:
glfw.terminate()
raise Exception("glfw window can not be created!")
# Make the window's context current
glfw.make_context_current(window1)
# Create ModernGL context
ctx1 = moderngl.create_context()
# Create a windowed mode window and its OpenGL context
window2 = glfw.create_window(400, 400, "OpenGL Window 2", None, None)
if not window2:
glfw.terminate()
raise Exception("glfw window can not be created!")
# Make the window's context current
glfw.make_context_current(window2)
# Create ModernGL context
ctx2 = moderngl.create_context()
print(ctx1)
print(ctx2)
print(window1)
print(window2)
glfw.make_context_current(window1)
# Create a simple shader program for ctx1
prog1 = ctx1.program(
vertex_shader="""
#version 330 core
in vec3 in_position;
void main() {
gl_Position = vec4(in_position, 1.0);
}
""",
fragment_shader="""
#version 330 core
layout (location = 0) out vec4 fragColor;
void main() {
vec3 color = vec3(0, 0, 1);
fragColor = vec4(color, 1.0);
}
"""
)
glfw.make_context_current(None)
glfw.make_context_current(window2)
# Create a simple shader program for ctx2
prog2 = ctx2.program(
vertex_shader="""
#version 330 core
in vec3 in_position;
void main() {
gl_Position = vec4(in_position, 1.0);
}
""",
fragment_shader="""
#version 330 core
layout (location = 0) out vec4 fragColor;
void main() {
vec3 color = vec3(0, 1, 0);
fragColor = vec4(color, 1.0);
}
"""
)
glfw.make_context_current(None)
print(prog1)
print(prog2)
glfw.make_context_current(window1)
vertices = np.array([
-0.5, 0.0, 0.0,
-0.25, -0.5, 0.0,
0.0, 0.0, 0.0,
], dtype='f4')
vbo1 = ctx1.buffer(vertices.tobytes())
vao1 = ctx1.vertex_array(prog1, [(vbo1, '3f', 'in_position')])
glfw.make_context_current(None)
glfw.make_context_current(window2)
vertices = np.array([
0.0, 0.5, 0.0,
0.0, 0.0, 0.0,
0.25, 0.5, 0.0,
], dtype='f4')
vbo2 = ctx2.buffer(vertices.tobytes())
vao2 = ctx2.vertex_array(prog2, [(vbo2, '3f', 'in_position')])
glfw.make_context_current(None)
# Render to window1
glfw.make_context_current(window1)
print("Current context: ", ctx1, "Current window (Should be window 1): ", window1)
FrameBuffer1 = ctx1.detect_framebuffer()
print(f"Framebuffer ID for ctx1: {FrameBuffer1.glo}")
ctx1.clear(0.0, 1.0, 1.0, 1.0)
vao1.render(moderngl.TRIANGLES)
glfw.swap_buffers(window1)
glfw.make_context_current(None)
# Render to window2
glfw.make_context_current(window2)
print("Current context: ", ctx2, "Current window: (Should be window 2)", window2)
FrameBuffer2 = ctx2.detect_framebuffer()
print(f"Framebuffer ID for ctx2: {FrameBuffer2.glo}")
ctx2.clear(1.0, 1.0, 0.0, 1.0)
vao2.render(moderngl.TRIANGLES)
glfw.swap_buffers(window2)
glfw.make_context_current(None)
# Hold the windows open until they are closed
while not glfw.window_should_close(window1) and not glfw.window_should_close(window2):
# Poll for and process events
glfw.poll_events()
# Terminate glfw
glfw.terminate()
因此最初的输出是: 红色三角形现在在两个窗口中渲染
为了验证此解决方案的正确性,我通过修改上下文特定的顶点数据以及上下文特定的片段着色器来更改三角形的位置和颜色,以检查 glfw 视口是否单独反映了各自的预期修改行为上下文:
所以这似乎是一个有效的解决方案。希望这对其他人有帮助,谢谢。