Update fill shader alpha blending, and simplify the fill canvas

This commit is contained in:
Grant Sanderson
2023-02-02 10:42:24 -08:00
parent 0cf9a35367
commit c3823e722d
3 changed files with 14 additions and 33 deletions

View File

@ -287,24 +287,22 @@ class FillShaderWrapper(ShaderWrapper):
return return
original_fbo = self.ctx.fbo original_fbo = self.ctx.fbo
texture_fbo, texture_vao, null_rgb = self.fill_canvas texture_fbo, texture_vao = self.fill_canvas
texture_fbo.clear(*null_rgb, 0.0) texture_fbo.clear()
texture_fbo.use() texture_fbo.use()
gl.glBlendFuncSeparate( gl.glBlendFuncSeparate(
# Ordinary blending for colors # Ordinary blending for colors
gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA, gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA,
# Just take the max of the alphas, given the shenanigans # The effect of blending with -a / (1 - a)
# with how alphas are being used to compute winding numbers # should be to cancel out
gl.GL_ONE, gl.GL_ONE, gl.GL_ONE_MINUS_DST_ALPHA, gl.GL_ONE,
) )
gl.glBlendEquationSeparate(gl.GL_FUNC_ADD, gl.GL_MAX)
super().render() super().render()
original_fbo.use() original_fbo.use()
gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA)
gl.glBlendEquation(gl.GL_FUNC_ADD)
texture_vao.render() texture_vao.render()

View File

@ -33,7 +33,7 @@ void main() {
cap is to make sure the original fragment color can be recovered even after cap is to make sure the original fragment color can be recovered even after
blending with an (alpha = 1) color. blending with an (alpha = 1) color.
*/ */
float a = 0.99 * frag_color.a; float a = 0.95 * frag_color.a;
if(winding && orientation < 0) a = -a / (1 - a); if(winding && orientation < 0) a = -a / (1 - a);
frag_color.a = a; frag_color.a = a;

View File

@ -103,7 +103,7 @@ def get_colormap_code(rgb_list: Sequence[float]) -> str:
@lru_cache() @lru_cache()
def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray, Tuple[float, float, float]]: def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray]:
""" """
Because VMobjects with fill are rendered in a funny way, using Because VMobjects with fill are rendered in a funny way, using
alpha blending to effectively compute the winding number around alpha blending to effectively compute the winding number around
@ -123,26 +123,16 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray, Tu
depth_texture = ctx.depth_texture(size=size) depth_texture = ctx.depth_texture(size=size)
texture_fbo = ctx.framebuffer(texture, depth_texture) texture_fbo = ctx.framebuffer(texture, depth_texture)
# We'll paint onto a canvas with initially negative rgbs, and
# discard any pixels remaining close to this value. This is
# because alphas are effectively being used for another purpose,
# and we don't want to overlap with any colors one might actually
# use. It should be negative enough to be distinguishable from
# ordinary colors with some margin, but the farther it's pulled back
# from zero the more it will be true that overlapping filled objects
# with transparency have an unnaturally bright composition.
null_rgb = (-0.25, -0.25, -0.25)
simple_program = ctx.program( simple_program = ctx.program(
vertex_shader=''' vertex_shader='''
#version 330 #version 330
in vec2 texcoord; in vec2 texcoord;
out vec2 v_textcoord; out vec2 uv;
void main() { void main() {
gl_Position = vec4((2.0 * texcoord - 1.0), 0.0, 1.0); gl_Position = vec4((2.0 * texcoord - 1.0), 0.0, 1.0);
v_textcoord = texcoord; uv = texcoord;
} }
''', ''',
fragment_shader=''' fragment_shader='''
@ -150,31 +140,24 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray, Tu
uniform sampler2D Texture; uniform sampler2D Texture;
uniform sampler2D DepthTexture; uniform sampler2D DepthTexture;
uniform vec3 null_rgb;
in vec2 v_textcoord; in vec2 uv;
out vec4 color; out vec4 color;
const float MIN_DIST_TO_NULL = 0.2;
void main() { void main() {
color = texture(Texture, v_textcoord); color = texture(Texture, uv);
if(color.a == 0) discard; if(color.a == 0) discard;
if(distance(color.rgb, null_rgb) < MIN_DIST_TO_NULL) discard;
// Un-blend from the null value
color.rgb -= (1 - color.a) * null_rgb;
// Counteract scaling in fill frag // Counteract scaling in fill frag
color.a *= 1.01; color.a *= 1.06;
gl_FragDepth = texture(DepthTexture, v_textcoord)[0]; gl_FragDepth = texture(DepthTexture, uv)[0];
} }
''', ''',
) )
simple_program['Texture'].value = get_texture_id(texture) simple_program['Texture'].value = get_texture_id(texture)
simple_program['DepthTexture'].value = get_texture_id(depth_texture) simple_program['DepthTexture'].value = get_texture_id(depth_texture)
simple_program['null_rgb'].value = null_rgb
verts = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) verts = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
fill_texture_vao = ctx.simple_vertex_array( fill_texture_vao = ctx.simple_vertex_array(
@ -183,4 +166,4 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray, Tu
'texcoord', 'texcoord',
mode=moderngl.TRIANGLE_STRIP mode=moderngl.TRIANGLE_STRIP
) )
return (texture_fbo, fill_texture_vao, null_rgb) return (texture_fbo, fill_texture_vao)