diff --git a/manimlib/shader_wrapper.py b/manimlib/shader_wrapper.py index da042544..aa733f8e 100644 --- a/manimlib/shader_wrapper.py +++ b/manimlib/shader_wrapper.py @@ -289,10 +289,9 @@ class FillShaderWrapper(ShaderWrapper): texture_fbo.clear() texture_fbo.use() - self.ctx.blend_func = (moderngl.ONE, moderngl.ONE) - vao.render(self.render_primitive) + vao.render() - self.ctx.blend_func = (moderngl.ONE, moderngl.ONE_MINUS_SRC_ALPHA) original_fbo.use() + self.ctx.blend_func = (moderngl.ONE, moderngl.ONE_MINUS_SRC_ALPHA) texture_vao.render(moderngl.TRIANGLE_STRIP) - self.ctx.blend_func = moderngl.DEFAULT_BLENDING + self.ctx.blend_func = (moderngl.DEFAULT_BLENDING) diff --git a/manimlib/shaders/quadratic_bezier_fill/frag.glsl b/manimlib/shaders/quadratic_bezier_fill/frag.glsl index ae17b366..94fc495a 100644 --- a/manimlib/shaders/quadratic_bezier_fill/frag.glsl +++ b/manimlib/shaders/quadratic_bezier_fill/frag.glsl @@ -13,12 +13,26 @@ void main() { if (color.a == 0) discard; frag_color = color; - // Pre-multiply alphas - if(winding) frag_color *= frag_color.a; + /* + We want negatively oriented triangles to be canceled with positively + oriented ones. The easiest way to do this is to give them negative alpha, + and change the blend function to just add them. However, this messes with + usual blending, so instead the following line is meant to let this canceling + work even for the normal blending equation: - // Give a sign based on orientation so that - // additive blending cancels as needed - if(winding && orientation < 0) frag_color *= -1; + (1 - alpha) * dst + alpha * src + + We want the effect of blending with a positively oriented triangle followed + by a negatively oriented one to return to whatever the original frag value + was. You can work out this will work if the alpha for negative orientations + is changed to -alpha / (1 - alpha). This has a singularity at alpha = 1, + so we cap it at a value very close to 1. Effectively, the purpose of this + cap is to make sure the original fragment color can be recovered even after + blending with an alpha = 1 color. + */ + float a = 0.999 * frag_color.a; + if(winding && orientation < 0) a = -a / (1 - a); + frag_color.a = a; if (bool(fill_all)) return; diff --git a/manimlib/shaders/quadratic_bezier_fill/geom.glsl b/manimlib/shaders/quadratic_bezier_fill/geom.glsl index 1326c365..284be5e6 100644 --- a/manimlib/shaders/quadratic_bezier_fill/geom.glsl +++ b/manimlib/shaders/quadratic_bezier_fill/geom.glsl @@ -36,6 +36,11 @@ void emit_triangle(vec3 points[3], vec4 v_color[3]){ for(int i = 0; i < 3; i++){ uv_coords = SIMPLE_QUADRATIC[i]; color = finalize_color(v_color[i], points[i], unit_normal); + if(winding){ + // Pure black will be used to discard fragments later + if(color.rgb == vec3(0.0)) color.rgb += vec3(0.01); + // color.a = sqrt(color.a); + } gl_Position = get_gl_Position(points[i]); EmitVertex(); } diff --git a/manimlib/utils/shaders.py b/manimlib/utils/shaders.py index 8436fc8a..1556015b 100644 --- a/manimlib/utils/shaders.py +++ b/manimlib/utils/shaders.py @@ -110,7 +110,7 @@ def get_fill_palette(ctx) -> Tuple[Framebuffer, VertexArray]: size = (2 * DEFAULT_PIXEL_WIDTH, 2 * DEFAULT_PIXEL_HEIGHT) # Important to make sure dtype is floating point (not fixed point) # so that alpha values can be negative and are not clipped - texture = ctx.texture(size=size, components=4, dtype='f2') + texture = ctx.texture(size=size, components=4, dtype='f4') depth_buffer = ctx.depth_renderbuffer(size) # TODO, currently not used texture_fbo = ctx.framebuffer(texture, depth_buffer) @@ -147,8 +147,7 @@ def get_fill_palette(ctx) -> Tuple[Framebuffer, VertexArray]: 0.25 * texture(Texture, tc1) + 0.25 * texture(Texture, tc2) + 0.25 * texture(Texture, tc3); - if(frag_color.a == 0) discard; - frag_color = abs(frag_color); + if(distance(frag_color.rgb, vec3(0.0)) < 1e-3) discard; //TODO, set gl_FragDepth; } ''',