如何在 python-moderngl 中渲染具有不同纹理的多个对象

How do I render multiple objects with different textures in python-moderngl

我正在尝试创建一个无头渲染器,它采用 2 个具有不同纹理的模型,然后将它们渲染成单个图像

    texture = ctx.texture(texture_image.size, 3, texture_image.tobytes())
    texture.build_mipmaps()

    texture1 = ctx.texture(texture_image1.size, 3, texture_image1.tobytes())
    texture1.build_mipmaps()
    # Vertex Buffer and Vertex Array

    vbo = ctx.buffer(vertex_data)
    vao = ctx.simple_vertex_array(
        prog, vbo, *['in_vert', 'in_text', 'in_norm'])
    for i in range(2):


        # Matrices and Uniforms

        # Framebuffers

        fbo = ctx.framebuffer(
            ctx.renderbuffer((512, 512)),
            ctx.depth_renderbuffer((512, 512)),
        )

        # Rendering

        fbo.use()
        ctx.enable(ModernGL.DEPTH_TEST)
        ctx.clear(0.9, 0.9, 0.9)
        texture.use()

        vao.render()

        vbo = ctx.buffer(cylinder)
        vao = ctx.simple_vertex_array(
            prog, vbo, *['in_vert', 'in_text', 'in_norm'])

        fbo.use()
        ctx.enable(ModernGL.DEPTH_TEST)
        # ctx.clear(0.9, 0.9, 0.9)
        texture1.use()

        vao.render()

        # Loading the image using Pillow

        data = fbo.read(components=3, alignment=1)
        img = Image.frombytes('RGB', fbo.size, data, 'raw', 'RGB', 0, -1)
#         del data
#         del img

    img.save(f'output{i}.png')


if __name__ == '__main__':
    import time

    start = time.time()
    main()
    end = time.time()
    print(end-start)

这里只有第二个模型最终导出,初始模型被覆盖。我尝试了很多资源来找到这个问题的答案,但找不到任何答案。

编辑- 添加了我正在尝试创建的图像。第一个模型,即圆柱体,然后是具有不同纹理的手表。

在代码中您创建了两个帧缓冲区。你提到你想要一张图片,我想你可能希望并排显示模型。

这是对您的代码的更正:

完整代码:

texture = ctx.texture(texture_image.size, 3, texture_image.tobytes())
texture.build_mipmaps()

texture1 = ctx.texture(texture_image1.size, 3, texture_image1.tobytes())
texture1.build_mipmaps()
# Vertex Buffer and Vertex Array

vbo = ctx.buffer(vertex_data)
vao = ctx.simple_vertex_array(
    prog, vbo, *['in_vert', 'in_text', 'in_norm'])

# Matrices and Uniforms
# Framebuffers

fbo = ctx.framebuffer(
    ctx.renderbuffer((1024, 512)), # doubled width to get
    ctx.depth_renderbuffer((1024, 512)), # doubled width to get
)

# Rendering

fbo.use()
ctx.enable(ModernGL.DEPTH_TEST)
ctx.viewport = (0, 0, 1024, 512)  # x, y, width, height
ctx.clear(0.9, 0.9, 0.9)

ctx.viewport = (0, 0, 512, 512)  # x, y, width, height
texture.use()  # first texture
vao.render()

ctx.viewport = (512, 0, 512, 512)  # x, y, width, height
texture1.use()  # second texture
vao.render()

data = fbo.read(components=3, alignment=1)
img = Image.frombytes('RGB', fbo.size, data, 'raw', 'RGB', 0, -1)
img.save('output.png')


if __name__ == '__main__':
    import time

    start = time.time()
    main()
    end = time.time()
    print(end-start)

这是一个独立的示例,您可以 运行。它将两个纹理四边形渲染到帧缓冲区并将帧缓冲区内容保存到 png 文件。

如果您正在制作某种绘制循环,请务必不要在该循环内创建资源,除非您知道这意味着什么。

如果这对您的模型不起作用,问题可能出在您没有共享的代码中,例如在着色器或模型本身(可能是放置或投影)中

使用 OpenGL 时,首先创建一个最小版本并逐渐添加内容几乎总是一个好主意。这样可以更容易地确定问题所在。

输出

import moderngl
from array import array
from PIL import Image

ctx = moderngl.create_context(standalone=True)
framebuffer_size = (512, 512)

texture1 = ctx.texture((2, 2), 3, array('B', [200, 0, 0] * 4))
texture2 = ctx.texture((2, 2), 3, array('B', [0, 200, 0] * 4))

fbo = ctx.framebuffer(
    ctx.renderbuffer(framebuffer_size),
    ctx.depth_renderbuffer(framebuffer_size),
)

program = ctx.program(
    vertex_shader="""
    #version 330

    in vec2 in_pos;
    in vec2 in_uv;
    out vec2 uv;

    void main() {
        gl_Position = vec4(in_pos, 0.0, 1.0);
        uv = in_uv;
    }
    """,
    fragment_shader="""
    #version 330

    uniform sampler2D texture0;
    out vec4 fragColor;
    in vec2 uv;

    void main() {
        fragColor = texture(texture0, uv);
    }
    """,
)

buffer1 = ctx.buffer(array('f',
    [
        # pos xy    uv
        -0.75,  0.75, 1.0, 0.0,
        -0.75, -0.75, 0.0, 0.0,
         0.75,  0.75, 1.0, 1.0,
         0.75, -0.75, 1.0, 0.0,
    ]
))

buffer2 = ctx.buffer(array('f',
    [
        # pos xy    uv
        -0.5,  0.5, 1.0, 0.0,
        -0.5, -0.5, 0.0, 0.0,
         0.5,  0.5, 1.0, 1.0,
         0.5, -0.5, 1.0, 0.0,
    ]
))


vao1 = ctx.vertex_array(program, [(buffer1, '2f 2f', 'in_pos', 'in_uv')])
vao2 = ctx.vertex_array(program, [(buffer2, '2f 2f', 'in_pos', 'in_uv')])

# --- Render ---
# Make a loop here if you need to render multiple passes

fbo.use()
fbo.clear()

# draw quad with red texture
texture1.use()
vao1.render(mode=moderngl.TRIANGLE_STRIP)

# draw quad with green texture
texture2.use()
vao2.render(mode=moderngl.TRIANGLE_STRIP)

ctx.finish()

img = Image.frombytes('RGB', fbo.size, fbo.read())
img.save('output.png')