Как включить сглаживание в бэкэнде Moderngl EGL? - PullRequest
1 голос
/ 19 апреля 2020

Этот код отображает цветной треугольник, когда нет сглаживания (samples=0). Но когда я включаю сглаживание (samples=1...32), оно не может ничего отрендерить. Как заставить его работать с сглаживанием? Возможно, я не могу читать пиксели из мультисэмпловых fbos или текстур напрямую, но я не знаю, как это исправить.

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 Ответ

2 голосов
/ 19 апреля 2020

Невозможно читать данные из мультисэмплового кадрового буфера напрямую. Обратите внимание, что в мультисэмпловом кадровом буфере пиксели сохраняются для каждого сэмпла. Цвет для каждого образца должен быть смешан до одного цвета. Это может быть достигнуто с помощью glBlitFramebuffer.

Создание 2 кадровых буферов. Создайте кадровый буфер с samples=0, этот кадровый буфер используется для чтения данных пикселей. Создайте кадровый буфер с несколькими образцами, который является целью рендеринга.

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),
)

Скопируйте пиксельные данные из буфера кадров мультисэмпла в буфер буфера одного семпла. Я не нашел ни одного ModernGL класса или метода, который бы обеспечивал это.
В любом случае мультисэмпловый кадровый буфер должен быть связан для чтения, а одиночный примерный кадровый буфер должен быть связан с записью, а данные о цвете должны быть скопировано. В нативном OpenGL это выглядит следующим образом:

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)

Все вместе:

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')

К сожалению, я столкнулся с новой проблемой. Если мультисэмпловый кадровый буфер также имеет буфер глубины, то glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_msaa.glo) по какой-либо причине дает сбой.
Это требует дальнейшего изучения.

Редактировать :

Я только что понял, что нет никаких проблем при использовании Renderbuffer вместо Texture для буфера глубины:

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)
)

Следовательно, это швы, чтобы быть ошибкой в ​​ ModernGL , связанной с вложением буфера глубины текстуры нескольких образцов.

...