2

我编写了这个简单的程序,它使用 将图像显示到moderngl上下文中,pygame我的目标是在屏幕上绘制一个矩形。(这显然只是一个最小的工作示例,真正的目标是为纹理制作动画并在屏幕上制作更多的矩形)。

import moderngl
import numpy as np
import pygame
from PIL import Image


class MyPyGame:
    def __init__(self):
        pygame.init()
        self._surface = pygame.display.set_mode((800, 600), pygame.DOUBLEBUF | pygame.OPENGL)

        self.context = moderngl.create_context()

        image = Image.open("test.jpg").transpose(Image.FLIP_TOP_BOTTOM)
        self.texture = self.context.texture(image.size, 3, image.tobytes())
        self.texture.use(0)

        self.program = self.context.program(
            vertex_shader="""
            #version 330
            in vec2 in_position;
            out vec2 uv0;
            void main() {
                gl_Position = vec4(in_position, 0.0, 1.0);
                uv0 = (0.5 * in_position) + vec2(0.5);
            }
            """,
            fragment_shader="""
            #version 330
            out vec4 fragColor;
            uniform sampler2D texture0;
            in vec2 uv0;
            void main() {
                fragColor = texture(texture0, uv0);
            }
            """)

        vertices_quad_2d = np.array([-1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
                                     -1.0, 1.0, 1.0, -1.0, 1.0, 1.0], dtype=np.float32)
        vertex_buffer_quad_2d = self.context.buffer(vertices_quad_2d.tobytes())
        self.vertex_array = self.context.vertex_array(self.program, [(vertex_buffer_quad_2d, "2f", "in_position")])

    def run(self):
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()
            self.vertex_array.render()
            pygame.display.flip()

if __name__ == '__main__':
    app = MyPyGame()
    app.run()

我尝试过的一些事情:

  1. 用“常规”方式绘制一个矩形pygame,即在 main 方法中添加这一行,run在顶点数组渲染之前或之后(两者都不起作用):

     pygame.draw.rect(self._surface, (200, 200, 200), [100, 100, 100, 100])
    
  2. 而不是 flag pygame.OPENGL,使用 flagpygame.OPENGLBLIT然后blit使用矩形(没用,更多信息在这里

  3. 使用moderngl上下文作为主显示器内的窗口,如此处所建议,然后blit将矩形放到主显示器上。这不是我的目标,我希望能够在上下文中显示文本和形状,但仍然想至少尝试一下。也没有工作,下面的代码(替换相应的代码__init__)导致异常cannot detect OpenGL context

     pygame.init()
     self.main_window = pygame.display.set_mode((800, 600))
     self.graphics_window = pygame.Surface((700, 600), pygame.DOUBLEBUF | pygame.OPENGL)
     self.main_window.blit(self.graphics_window, (100, 0))
     self.context = moderngl.create_context()
    
  4. 使用“开箱即用”窗口moderngl_window使用pygame代码here)。同样,没有成功在上下文本身上绘制一个矩形 - 尝试在窗口代码本身内部或当我编写从这个 pygame 窗口继承的我自己的窗口时从 (1) 添加同一行。

[正在运行:Windows10、p​​ython3.6、pygame 1.9.6、moderngl 5.6.1]

如何创建一个既显示图形又具有一层服装对象的窗口?(文本、按钮等)

编辑:也许需要澄清我的动机:我想在背景中有一层图形,在上面的例子中是对输入图像的一些操作。然后,在前台,我想要一些服装 PyGame 对象,如几何形状、按钮等。

4

2 回答 2

3

在混合moderngl 和pygame 时,您可能希望moderngl 对屏幕进行所有重新渲染。你用 pygame 渲染的东西应该被渲染到一个单独的表面。然后将此表面转换为 a moderngl.Texture,以便我们可以使用 OpenGL 将其绘制到屏幕上。

在moderngl-window 项目中甚至还有一个官方示例:https ://github.com/moderngl/moderngl-window/blob/master/examples/advanced/pygame2.py

如果您对 pygame 窗口初始化有任何疑问,可以查看 pygame 窗口后端:https ://github.com/moderngl/moderngl-window/blob/5cf117ca9c0ef8cbde772d51041a039fc611b6c7/moderngl_window/context/pygame2/window.py#L28-L65

我创建了一个将 pygame 表面渲染到屏幕的新示例。它是混合在当前背景之上的 alpha 值。你在 pygame 中渲染的任何东西都需要渲染到这个表面,并且每帧都会上传到图形内存。

新示例位于此处:https ://github.com/moderngl/moderngl-window/blob/master/examples/advanced/pygame2_simple.py

import math
from pathlib import Path
import pygame
import moderngl
import moderngl_window
from moderngl_window import geometry


class Pygame(moderngl_window.WindowConfig):
    """
    Example using pygame with moderngl.
    Needs to run with ``--window pygame2`` option.
    """
    title = "Pygame"
    window_size = 1280, 720
    resource_dir = (Path(__file__) / '../../resources').absolute()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        if self.wnd.name != 'pygame2':
            raise RuntimeError('This example only works with --window pygame2 option')

        self.pg_res = (320, 180)
        # Create a 24bit (rgba) offscreen surface pygame can render to
        self.pg_screen = pygame.Surface(self.pg_res, flags=pygame.SRCALPHA)
        # 24 bit (rgba) moderngl texture
        self.pg_texture = self.ctx.texture(self.pg_res, 4)
        self.pg_texture.filter = moderngl.NEAREST, moderngl.NEAREST

        self.texture_program = self.load_program('programs/texture.glsl')
        self.quad_fs = geometry.quad_fs()

    def render(self, time, frametime):
        self.render_pygame(time)

        self.ctx.clear(
            (math.sin(time) + 1.0) / 2,
            (math.sin(time + 2) + 1.0) / 2,
            (math.sin(time + 3) + 1.0) / 2,
        )
    
        self.ctx.enable(moderngl.BLEND)
        self.pg_texture.use()
        self.quad_fs.render(self.texture_program)
        self.ctx.disable(moderngl.BLEND)

    def render_pygame(self, time):
        """Render to offscreen surface and copy result into moderngl texture"""
        self.pg_screen.fill((0, 0, 0, 0))  # Make sure we clear with alpha 0!
        N = 8
        for i in range(N):
            time_offset = 6.28 / N * i
            pygame.draw.circle(
                self.pg_screen,
                ((i * 50) % 255, (i * 100) % 255, (i * 20) % 255),
                (
                    math.sin(time + time_offset) * 55 + self.pg_res[0] // 2,
                    math.cos(time + time_offset) * 55 + self.pg_res[1] // 2),
                math.sin(time) * 4 + 15,
            )

        # Get the buffer view of the Surface's pixels
        # and write this data into the texture
        texture_data = self.pg_screen.get_view('1')
        self.pg_texture.write(texture_data)


if __name__ == '__main__':
    Pygame.run()
于 2020-07-29T12:55:27.207 回答
0

很大程度上基于上面@Grimmy 的回答,这里是集成的代码modernl-windowPyGame2它基于repo中的一些示例:moderngl-window

from pathlib import Path
import pygame
import moderngl
import moderngl_window
from moderngl_window import geometry


class Pygame(moderngl_window.WindowConfig):
    title = "Pygame"
    window_size = 1280, 720
    resource_dir = (Path(__file__) / '../../resources').absolute()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        # Create a 24bit (rgba) offscreen surface pygame can render to
        self.pg_screen = pygame.Surface(self.window_size, flags=pygame.SRCALPHA)
        # 24 bit (rgba) moderngl texture
        self.pg_texture = self.ctx.texture(self.window_size, 4)
        self.pg_texture.filter = moderngl.NEAREST, moderngl.NEAREST

        self.texture_program = self.load_program('programs/texture.glsl')
        self.quad_texture = self.load_texture_2d('textures/python-bg.png')
        self.quad_fs = geometry.quad_fs()

    def render(self, time, frametime):
        self.ctx.clear()

        self.ctx.enable(moderngl.BLEND)

        # Render background graphics
        self.quad_texture.use()
        self.texture_program['texture0'].value = 0
        self.quad_fs.render(self.texture_program)

        # Render foreground objects
        self.pg_texture.use()
        self.render_pygame(time)
        self.quad_fs.render(self.texture_program)

        self.ctx.disable(moderngl.BLEND)

    def render_pygame(self, time):
        """Render to offscreen surface and copy result into moderngl texture"""
        self.pg_screen.fill((0, 0, 0, 0))  # Make sure we clear with alpha 0!
        pygame.draw.rect(self.pg_screen, (200, 200, 200), [100, 100, 100, 100])

        # Get the buffer view of the Surface's pixels
        # and write this data into the texture
        texture_data = self.pg_screen.get_view('1')
        self.pg_texture.write(texture_data)


if __name__ == '__main__':
    moderngl_window.run_window_config(Pygame, args=('--window', 'pygame2'))
  • 已经在 Ubuntu18.04 上用 Python3.6 测试过
于 2020-08-15T09:34:28.190 回答