如何从另一个进程添加到 opengl pygame VBO
How to add to opengl pygame VBOs from another process
问题
我只是想制作像 minecraft 这样的游戏,但我无法从另一个进程添加到 vbo。奇怪的是,日志出现了两次,window 立即关闭。
密码
import pygame, multiprocessing
from OpenGL.GL import *
from ctypes import *
pygame.init ()
screen = pygame.display.set_mode ((800,600), pygame.OPENGL|pygame.DOUBLEBUF, 24)
glViewport (0, 0, 800, 600)
glClearColor (0.0, 0.5, 0.5, 1.0)
glEnableClientState (GL_VERTEX_ARRAY)
vbo = glGenBuffers (1)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
def triangle():
vertices = [ 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0 ]
glBufferData (GL_ARRAY_BUFFER, len(vertices)*4, (c_float*len(vertices))(*vertices), GL_STATIC_DRAW)
if __name__ == '__main__':
multiprocessing.Process(target=triangle).start()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
glClear (GL_COLOR_BUFFER_BIT)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
glVertexPointer (3, GL_FLOAT, 0, None)
glDrawArrays (GL_TRIANGLES, 0, 3)
pygame.display.flip ()
日志
pygame 2.1.0 (SDL 2.0.16, Python 3.8.6)
Hello from the pygame community. https://www.pygame.org/contribute.html
Unable to load numpy_formathandler accelerator from OpenGL_accelerate
pygame 2.1.0 (SDL 2.0.16, Python 3.8.6)
Hello from the pygame community. https://www.pygame.org/contribute.html
Unable to load numpy_formathandler accelerator from OpenGL_accelerate
预期产出
更新
我将代码更改为:
import pygame, threading
from pyglet.gl import *
from OpenGL.GL import *
from OpenGL.WGL import *
from ctypes import *
pygame.init ()
screen = pygame.display.set_mode ((800,600), pygame.OPENGL|pygame.DOUBLEBUF, 24)
glViewport (0, 0, 800, 600)
glClearColor (0.0, 0.5, 0.5, 1.0)
glEnableClientState (GL_VERTEX_ARRAY)
vbo = glGenBuffers (1)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
hwnd = pygame.display.get_wm_info()['window']
context = wglGetCurrentContext()
def triangle(window_handle, context):
context2 = wglCreateContext(window_handle)
wglMakeCurrent(window_handle, context2)
vbo2 = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo2)
glBufferData(GL_ARRAY_BUFFER, 12, (GLfloat * 12)(0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0), GL_STATIC_DRAW)
glVertexPointer(3, GL_FLOAT, 0, None)
glFlush()
wglMakeCurrent(None, None)
wglDeleteContext(context2)
if __name__ == '__main__':
threading.Thread(target=triangle, args=[hwnd, context]).start()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
glClear (GL_COLOR_BUFFER_BIT)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
glVertexPointer (3, GL_FLOAT, 0, None)
glDrawArrays (GL_TRIANGLES, 0, 3)
pygame.display.flip ()
但现在它只是打开了 window,然后又关闭了! window 突然关闭。它给出了下面提到的错误。但是如果我注释第 28 行并简单地写 triangle(hwnd, context)
,一切正常。
错误:
Traceback (most recent call last):
File "C:\Users\...\AppData\Local\Programs\Python\Python38\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "C:\Users\...\AppData\Local\Programs\Python\Python38\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "f:/Whosebug - Code/vbo_plus_thread.py", line 27, in triangle
vbo2 = glGenBuffers(1)
File "src/latebind.pyx", line 39, in OpenGL_accelerate.latebind.LateBind.__call__
File "src/wrapper.pyx", line 318, in OpenGL_accelerate.wrapper.Wrapper.__call__
File "src/wrapper.pyx", line 311, in OpenGL_accelerate.wrapper.Wrapper.__call__
File "src/errorchecker.pyx", line 58, in OpenGL_accelerate.errorchecker._ErrorChecker.glCheckError
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glGenBuffers,
pyArgs = (
1,
<object object at 0x000001E23B9B8100>,
),
cArgs = (1, array([0], dtype=uint32)),
cArguments = (1, array([0], dtype=uint32))
)
OpenGL Context 是本地线程。如果你想在另一个线程中使用 OpenGL 上下文,你必须使它成为那里的当前上下文。
上下文一次只能在一个线程中是当前的。当一个线程的上下文成为当前上下文时,它是该线程独有的并被声明,因此它自动不是所有其他线程的当前上下文。如果要在多个线程中使用相同的上下文,则必须锁定使用上下文的部分以确保对上下文的独占访问。这很可能不是您想要的。
如果你想在一个线程中使用缓冲区进行绘图,但同时你想在另一个线程中更改它的内容,你需要2个OpenGL上下文,其中第一个上下文共享第二个上下文。
您的代码还有一些问题:
- 需要以字节为单位指定缓冲区日期的大小。因此数据的大小是 12*4 而不是 12。参见
glBufferData
。
- 顶点属性规范是一种未共享的上下文状态。对象与上下文相关联。所以当上下文被销毁时,对象也被销毁。参见 OpenGL Context。
- 见Minimal Windowless OpenGL Context Initialization, Windowless OpenGL,
OpenGL 上下文依赖于 OpenGL window。所以你需要创建一个隐藏的 OpenGL window 来获得第二个具有正确版本的 OpenGL 上下文。我认为 pygame (Pygame 2 is based on SDL2 甚至不可能做到这一点,可能会有解决方案。
使用 GLFW looks as follows. The vertex buffer object is created on the main thread. In the 2nd thread, a hidden OpenGL window is created that shares the context of the main thread. In this Context the buffer object's data store is updated with glBufferSubData
的基本设置:
from OpenGL.GL import *
from OpenGL.GLU import *
import glfw
import threading
if glfw.init() == glfw.FALSE:
exit()
event = threading.Event()
def shard_context(window, vbo):
glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
window2 = glfw.create_window(300, 300, "Window 2", None, window)
glfw.make_context_current(window2)
event.set()
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferSubData(GL_ARRAY_BUFFER, 0, 12*4, (GLfloat * 12)(0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0))
glFlush()
window = glfw.create_window(300, 300, "Window 1", None, None)
glfw.make_context_current(window)
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, 12 * 4, None, GL_STATIC_DRAW)
glfw.make_context_current(None)
thread = threading.Thread(target=shard_context, args=[window, vbo])
thread.start()
event.wait()
glfw.make_context_current(window)
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, None)
while not glfw.window_should_close(window):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glColor3f(1, 0, 0)
glDrawArrays (GL_TRIANGLES, 0, 3)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.terminate()
exit()
问题
我只是想制作像 minecraft 这样的游戏,但我无法从另一个进程添加到 vbo。奇怪的是,日志出现了两次,window 立即关闭。
密码
import pygame, multiprocessing
from OpenGL.GL import *
from ctypes import *
pygame.init ()
screen = pygame.display.set_mode ((800,600), pygame.OPENGL|pygame.DOUBLEBUF, 24)
glViewport (0, 0, 800, 600)
glClearColor (0.0, 0.5, 0.5, 1.0)
glEnableClientState (GL_VERTEX_ARRAY)
vbo = glGenBuffers (1)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
def triangle():
vertices = [ 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0 ]
glBufferData (GL_ARRAY_BUFFER, len(vertices)*4, (c_float*len(vertices))(*vertices), GL_STATIC_DRAW)
if __name__ == '__main__':
multiprocessing.Process(target=triangle).start()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
glClear (GL_COLOR_BUFFER_BIT)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
glVertexPointer (3, GL_FLOAT, 0, None)
glDrawArrays (GL_TRIANGLES, 0, 3)
pygame.display.flip ()
日志
pygame 2.1.0 (SDL 2.0.16, Python 3.8.6)
Hello from the pygame community. https://www.pygame.org/contribute.html
Unable to load numpy_formathandler accelerator from OpenGL_accelerate
pygame 2.1.0 (SDL 2.0.16, Python 3.8.6)
Hello from the pygame community. https://www.pygame.org/contribute.html
Unable to load numpy_formathandler accelerator from OpenGL_accelerate
预期产出
更新
我将代码更改为:
import pygame, threading
from pyglet.gl import *
from OpenGL.GL import *
from OpenGL.WGL import *
from ctypes import *
pygame.init ()
screen = pygame.display.set_mode ((800,600), pygame.OPENGL|pygame.DOUBLEBUF, 24)
glViewport (0, 0, 800, 600)
glClearColor (0.0, 0.5, 0.5, 1.0)
glEnableClientState (GL_VERTEX_ARRAY)
vbo = glGenBuffers (1)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
hwnd = pygame.display.get_wm_info()['window']
context = wglGetCurrentContext()
def triangle(window_handle, context):
context2 = wglCreateContext(window_handle)
wglMakeCurrent(window_handle, context2)
vbo2 = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo2)
glBufferData(GL_ARRAY_BUFFER, 12, (GLfloat * 12)(0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0), GL_STATIC_DRAW)
glVertexPointer(3, GL_FLOAT, 0, None)
glFlush()
wglMakeCurrent(None, None)
wglDeleteContext(context2)
if __name__ == '__main__':
threading.Thread(target=triangle, args=[hwnd, context]).start()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
glClear (GL_COLOR_BUFFER_BIT)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
glVertexPointer (3, GL_FLOAT, 0, None)
glDrawArrays (GL_TRIANGLES, 0, 3)
pygame.display.flip ()
但现在它只是打开了 window,然后又关闭了! window 突然关闭。它给出了下面提到的错误。但是如果我注释第 28 行并简单地写 triangle(hwnd, context)
,一切正常。
错误:
Traceback (most recent call last):
File "C:\Users\...\AppData\Local\Programs\Python\Python38\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "C:\Users\...\AppData\Local\Programs\Python\Python38\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "f:/Whosebug - Code/vbo_plus_thread.py", line 27, in triangle
vbo2 = glGenBuffers(1)
File "src/latebind.pyx", line 39, in OpenGL_accelerate.latebind.LateBind.__call__
File "src/wrapper.pyx", line 318, in OpenGL_accelerate.wrapper.Wrapper.__call__
File "src/wrapper.pyx", line 311, in OpenGL_accelerate.wrapper.Wrapper.__call__
File "src/errorchecker.pyx", line 58, in OpenGL_accelerate.errorchecker._ErrorChecker.glCheckError
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glGenBuffers,
pyArgs = (
1,
<object object at 0x000001E23B9B8100>,
),
cArgs = (1, array([0], dtype=uint32)),
cArguments = (1, array([0], dtype=uint32))
)
OpenGL Context 是本地线程。如果你想在另一个线程中使用 OpenGL 上下文,你必须使它成为那里的当前上下文。
上下文一次只能在一个线程中是当前的。当一个线程的上下文成为当前上下文时,它是该线程独有的并被声明,因此它自动不是所有其他线程的当前上下文。如果要在多个线程中使用相同的上下文,则必须锁定使用上下文的部分以确保对上下文的独占访问。这很可能不是您想要的。
如果你想在一个线程中使用缓冲区进行绘图,但同时你想在另一个线程中更改它的内容,你需要2个OpenGL上下文,其中第一个上下文共享第二个上下文。
您的代码还有一些问题:
- 需要以字节为单位指定缓冲区日期的大小。因此数据的大小是 12*4 而不是 12。参见
glBufferData
。 - 顶点属性规范是一种未共享的上下文状态。对象与上下文相关联。所以当上下文被销毁时,对象也被销毁。参见 OpenGL Context。
- 见Minimal Windowless OpenGL Context Initialization, Windowless OpenGL,
OpenGL 上下文依赖于 OpenGL window。所以你需要创建一个隐藏的 OpenGL window 来获得第二个具有正确版本的 OpenGL 上下文。我认为 pygame (Pygame 2 is based on SDL2 甚至不可能做到这一点,可能会有解决方案。
使用 GLFW looks as follows. The vertex buffer object is created on the main thread. In the 2nd thread, a hidden OpenGL window is created that shares the context of the main thread. In this Context the buffer object's data store is updated with glBufferSubData
的基本设置:
from OpenGL.GL import *
from OpenGL.GLU import *
import glfw
import threading
if glfw.init() == glfw.FALSE:
exit()
event = threading.Event()
def shard_context(window, vbo):
glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
window2 = glfw.create_window(300, 300, "Window 2", None, window)
glfw.make_context_current(window2)
event.set()
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferSubData(GL_ARRAY_BUFFER, 0, 12*4, (GLfloat * 12)(0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0))
glFlush()
window = glfw.create_window(300, 300, "Window 1", None, None)
glfw.make_context_current(window)
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, 12 * 4, None, GL_STATIC_DRAW)
glfw.make_context_current(None)
thread = threading.Thread(target=shard_context, args=[window, vbo])
thread.start()
event.wait()
glfw.make_context_current(window)
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, None)
while not glfw.window_should_close(window):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glColor3f(1, 0, 0)
glDrawArrays (GL_TRIANGLES, 0, 3)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.terminate()
exit()