How to enable Anti-aliasing in Moderngl EGL backend?

泪湿孤枕 提交于 2020-05-30 19:19:32

问题


This code renders a colored triangle when there is no anti-aliasing (samples=0). But when I turn on anti-aliasing (samples=1...32) it can't render anything. How to make it work with anti-aliasing? Perhaps I cannot read pixels from multisample fbos or textures directly but I don't know how to fix that.

import numpy as np
from PIL import Image
import moderngl

ctx = moderngl.create_standalone_context(backend='egl')
fbo = ctx.framebuffer(
        color_attachments=ctx.texture((512, 512), 4, samples=2),
        depth_attachment=ctx.depth_texture((512, 512), samples=2)
    )
fbo.use()

vertices = np.array([
    -1.0,  -1.0,   1.0, 0.0, 0.0,
     1.0,  -1.0,   0.0, 1.0, 0.0,
     0.0,   1.0,   0.0, 0.0, 1.0],
    dtype='f4',
)

prog = ctx.program(vertex_shader="""
#version 330
in vec2 in_vert;
in vec3 in_color;
out vec3 color;
void main() {
    gl_Position = vec4(in_vert, 0.0, 1.0);
    color = in_color;
}
""",
fragment_shader="""
#version 330
out vec4 fragColor;
in vec3 color;
void main() {
    fragColor = vec4(color, 1.0);
}
""",
)
vao = ctx.simple_vertex_array(prog, ctx.buffer(vertices), 'in_vert', 'in_color')
vao.render(mode=moderngl.TRIANGLES)

image = Image.frombytes('RGBA', (512, 512), fbo.read(components=4))
image = image.transpose(Image.FLIP_TOP_BOTTOM)
image.save('triangle.png', format='png')

回答1:


It is not possible to read data from a multisample framebuffer directly. Note, in a multisample framebuffer the pixels are stored for each sample. The color for each sample has to be mixed to a single color. That can be achieved by glBlitFramebuffer.

Create 2 framebuffers. Create a framebuffer with samples=0, this framebuffer is used to read the pixel data. Create a mutlisample framebuffer, which is the target of the rendering.

fbo = ctx.framebuffer(
    color_attachments=ctx.texture((512, 512), 4, samples=0),
)

fbo_msaa = ctx.framebuffer(
    color_attachments=ctx.texture((512, 512), 4, samples=8),
)

Copy the pixel data from the multisample framebuffer to the single sample framebuffer. I have not found any ModernGL class or method which provides that.
Anyway the multisample framebuffer has to be bound for reading and the single sample framebuffer has to be bound for writing and the color data has to be copied. In native OpenGL this looks as follows:

gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, fbo_msaa.glo)
gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, fbo.glo)
gl.glBlitFramebuffer(0, 0, 512, 512, 0, 0, 512, 512, gl.GL_COLOR_BUFFER_BIT, gl.GL_LINEAR)

All together:

import numpy as np
from PIL import Image
import moderngl
import OpenGL.GL as gl

ctx = moderngl.create_standalone_context(backend='egl')

fbo = ctx.framebuffer(
        color_attachments=ctx.texture((512, 512), 4, samples=0)
    )

fbo_msaa = ctx.framebuffer(
        color_attachments=ctx.texture((512, 512), 4, samples=8)
    )
fbo_msaa.use()

vertices = np.array([
    -1.0,  -1.0,   1.0, 0.0, 0.0,
     1.0,  -1.0,   0.0, 1.0, 0.0,
     0.0,   1.0,   0.0, 0.0, 1.0],
    dtype='f4',
)

prog = ctx.program(vertex_shader="""
#version 330
in vec2 in_vert;
in vec3 in_color;
out vec3 color;
void main() {
    gl_Position = vec4(in_vert, 0.0, 1.0);
    color = in_color;
}
""",
fragment_shader="""
#version 330
out vec4 fragColor;
in vec3 color;
void main() {
    fragColor = vec4(color, 1.0);
}
""",
)
vao = ctx.simple_vertex_array(prog, ctx.buffer(vertices), 'in_vert', 'in_color')
vao.render(mode=moderngl.TRIANGLES)

gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, fbo_msaa.glo)
gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, fbo.glo)
gl.glBlitFramebuffer(0, 0, 512, 512, 0, 0, 512, 512, gl.GL_COLOR_BUFFER_BIT, gl.GL_LINEAR)

image = Image.frombytes('RGBA', (512, 512), fbo.read(components=4))
image = image.transpose(Image.FLIP_TOP_BOTTOM)
image.save('triangle.png', format='png')

Sadly I encountered a new issue. If the multisampe framebuffer has a depth buffer, too, then glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_msaa.glo) fails, for whatever reason.
This needs to be investigated further.

Edit:

I just figured out, that there is not any issue, when using a Renderbuffer rather than a Texture for the depth buffer:

fbo = ctx.framebuffer(
    color_attachments=ctx.texture((512, 512), 4, samples=0),
)

fbo_msaa = ctx.framebuffer(
    color_attachments=ctx.texture((512, 512), 4, samples=8),
    depth_attachment=ctx.depth_renderbuffer((512, 512), samples=8)
)

Hence, it seams to be a bug in ModernGL, related to multisample texture depth buffer attachment.



来源:https://stackoverflow.com/questions/61302400/how-to-enable-anti-aliasing-in-moderngl-egl-backend

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!