如何在 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')
我正在尝试创建一个无头渲染器,它采用 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')