Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable Anti-aliasing in Moderngl EGL backend?

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')
like image 986
Joys Avatar asked Dec 17 '25 19:12

Joys


1 Answers

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.

like image 157
Rabbid76 Avatar answered Dec 20 '25 12:12

Rabbid76



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!