mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Have border width pre-multiply by alpha, and don't use a separate texture for that border width
This commit is contained in:
parent
d0cb5b4eea
commit
dfc5f152dd
3 changed files with 30 additions and 53 deletions
|
@ -249,13 +249,22 @@ class VShaderWrapper(ShaderWrapper):
|
||||||
geometry_shader=self.program_code["fill_geom"],
|
geometry_shader=self.program_code["fill_geom"],
|
||||||
fragment_shader=self.program_code["fill_frag"],
|
fragment_shader=self.program_code["fill_frag"],
|
||||||
)
|
)
|
||||||
|
self.fill_border_program = get_shader_program(
|
||||||
|
self.ctx,
|
||||||
|
vertex_shader=self.program_code["stroke_vert"],
|
||||||
|
geometry_shader=self.program_code["stroke_geom"],
|
||||||
|
fragment_shader=self.program_code["stroke_frag"].replace(
|
||||||
|
"// MODIFY FRAG COLOR",
|
||||||
|
"frag_color.a *= 0.95; frag_color.rgb *= frag_color.a;",
|
||||||
|
)
|
||||||
|
)
|
||||||
self.fill_depth_program = get_shader_program(
|
self.fill_depth_program = get_shader_program(
|
||||||
self.ctx,
|
self.ctx,
|
||||||
vertex_shader=self.program_code["depth_vert"],
|
vertex_shader=self.program_code["depth_vert"],
|
||||||
geometry_shader=self.program_code["depth_geom"],
|
geometry_shader=self.program_code["depth_geom"],
|
||||||
fragment_shader=self.program_code["depth_frag"],
|
fragment_shader=self.program_code["depth_frag"],
|
||||||
)
|
)
|
||||||
self.programs = [self.stroke_program, self.fill_program, self.fill_depth_program]
|
self.programs = [self.stroke_program, self.fill_program, self.fill_border_program, self.fill_depth_program]
|
||||||
|
|
||||||
# Full vert format looks like this (total of 4x23 = 92 bytes):
|
# Full vert format looks like this (total of 4x23 = 92 bytes):
|
||||||
# point 3
|
# point 3
|
||||||
|
@ -296,7 +305,7 @@ class VShaderWrapper(ShaderWrapper):
|
||||||
mode=self.render_primitive,
|
mode=self.render_primitive,
|
||||||
)
|
)
|
||||||
self.fill_border_vao = self.ctx.vertex_array(
|
self.fill_border_vao = self.ctx.vertex_array(
|
||||||
program=self.stroke_program,
|
program=self.fill_border_program,
|
||||||
content=[(self.vbo, self.fill_border_vert_format, *self.fill_border_vert_attributes)],
|
content=[(self.vbo, self.fill_border_vert_format, *self.fill_border_vert_attributes)],
|
||||||
mode=self.render_primitive,
|
mode=self.render_primitive,
|
||||||
)
|
)
|
||||||
|
@ -325,12 +334,7 @@ class VShaderWrapper(ShaderWrapper):
|
||||||
return
|
return
|
||||||
|
|
||||||
original_fbo = self.ctx.fbo
|
original_fbo = self.ctx.fbo
|
||||||
fill_tx_fbo, fill_tx_vao, border_tx_fbo, border_tx_vao, depth_tx_fbo = self.fill_canvas
|
fill_tx_fbo, fill_tx_vao, depth_tx_fbo = self.fill_canvas
|
||||||
|
|
||||||
# First, draw the border for antialiasing
|
|
||||||
border_tx_fbo.clear()
|
|
||||||
border_tx_fbo.use()
|
|
||||||
self.fill_border_vao.render()
|
|
||||||
|
|
||||||
# Render to a separate texture, due to strange alpha compositing
|
# Render to a separate texture, due to strange alpha compositing
|
||||||
# for the blended winding calculation
|
# for the blended winding calculation
|
||||||
|
@ -340,13 +344,13 @@ class VShaderWrapper(ShaderWrapper):
|
||||||
# Be sure not to apply depth test while rendering fill
|
# Be sure not to apply depth test while rendering fill
|
||||||
# but set it back to where it was after
|
# but set it back to where it was after
|
||||||
apply_depth_test = bool(gl.glGetBooleanv(gl.GL_DEPTH_TEST))
|
apply_depth_test = bool(gl.glGetBooleanv(gl.GL_DEPTH_TEST))
|
||||||
|
|
||||||
self.ctx.disable(moderngl.DEPTH_TEST)
|
self.ctx.disable(moderngl.DEPTH_TEST)
|
||||||
|
|
||||||
|
# With this blend function, the effect of blending alpha a with
|
||||||
|
# -a / (1 - a) cancels out, so we can cancel positively and negatively
|
||||||
|
# oriented triangles
|
||||||
gl.glBlendFuncSeparate(
|
gl.glBlendFuncSeparate(
|
||||||
gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA,
|
gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA,
|
||||||
# With this blend function, the effect of blending alpha a with
|
|
||||||
# -a / (1 - a) cancels out, so we can cancel positively and negatively
|
|
||||||
# oriented triangles
|
|
||||||
gl.GL_ONE_MINUS_DST_ALPHA, gl.GL_ONE
|
gl.GL_ONE_MINUS_DST_ALPHA, gl.GL_ONE
|
||||||
)
|
)
|
||||||
self.fill_vao.render()
|
self.fill_vao.render()
|
||||||
|
@ -359,18 +363,20 @@ class VShaderWrapper(ShaderWrapper):
|
||||||
self.fill_depth_vao.render()
|
self.fill_depth_vao.render()
|
||||||
self.ctx.enable(moderngl.DEPTH_TEST)
|
self.ctx.enable(moderngl.DEPTH_TEST)
|
||||||
|
|
||||||
# Render fill onto the border_width fbo
|
# Now add border, just taking the max alpha
|
||||||
# two alphas, before compositing back to the rest of the scene
|
|
||||||
border_tx_fbo.use()
|
|
||||||
gl.glEnable(gl.GL_BLEND)
|
|
||||||
gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE)
|
gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE)
|
||||||
gl.glBlendEquation(gl.GL_MAX)
|
gl.glBlendEquation(gl.GL_MAX)
|
||||||
|
self.fill_border_vao.render()
|
||||||
|
|
||||||
|
# Take the texture we were just drawing to, and render it to
|
||||||
|
# the main scene. Account for how alphas have been premultiplied
|
||||||
|
original_fbo.use()
|
||||||
|
gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA)
|
||||||
|
gl.glBlendEquation(gl.GL_FUNC_ADD)
|
||||||
fill_tx_vao.render()
|
fill_tx_vao.render()
|
||||||
|
|
||||||
original_fbo.use()
|
# Return to original blending state
|
||||||
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
|
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
|
||||||
gl.glBlendEquation(gl.GL_FUNC_ADD)
|
|
||||||
border_tx_vao.render()
|
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
if self.stroke_behind:
|
if self.stroke_behind:
|
||||||
|
|
|
@ -13,4 +13,6 @@ void main() {
|
||||||
// sdf for the region around the curve we wish to color.
|
// sdf for the region around the curve we wish to color.
|
||||||
float signed_dist_to_region = abs(dist_to_aaw) - half_width_to_aaw;
|
float signed_dist_to_region = abs(dist_to_aaw) - half_width_to_aaw;
|
||||||
frag_color.a *= smoothstep(0.5, -0.5, signed_dist_to_region);
|
frag_color.a *= smoothstep(0.5, -0.5, signed_dist_to_region);
|
||||||
|
// This line is replaced in VShaderWrapper
|
||||||
|
// MODIFY FRAG COLOR
|
||||||
}
|
}
|
|
@ -153,13 +153,10 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray]:
|
||||||
# Important to make sure dtype is floating point (not fixed point)
|
# Important to make sure dtype is floating point (not fixed point)
|
||||||
# so that alpha values can be negative and are not clipped
|
# so that alpha values can be negative and are not clipped
|
||||||
fill_texture = ctx.texture(size=size, components=4, dtype='f2')
|
fill_texture = ctx.texture(size=size, components=4, dtype='f2')
|
||||||
# Use a separate texture to firset render the antialiased border
|
# Use another one to keep track of depth
|
||||||
border_texture = ctx.texture(size=size, components=4, dtype='f1')
|
|
||||||
# Use yet another one to keep track of depth
|
|
||||||
depth_texture = ctx.texture(size=size, components=1, dtype='f4')
|
depth_texture = ctx.texture(size=size, components=1, dtype='f4')
|
||||||
|
|
||||||
fill_texture_fbo = ctx.framebuffer(fill_texture)
|
fill_texture_fbo = ctx.framebuffer(fill_texture)
|
||||||
border_texture_fbo = ctx.framebuffer(border_texture)
|
|
||||||
depth_texture_fbo = ctx.framebuffer(depth_texture)
|
depth_texture_fbo = ctx.framebuffer(depth_texture)
|
||||||
|
|
||||||
simple_vert = '''
|
simple_vert = '''
|
||||||
|
@ -187,38 +184,18 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray]:
|
||||||
if(color.a == 0) discard;
|
if(color.a == 0) discard;
|
||||||
|
|
||||||
// Counteract scaling in fill frag
|
// Counteract scaling in fill frag
|
||||||
color.a *= 1.06;
|
color *= 1.06;
|
||||||
// Cancel out what was effectively a premultiplication
|
|
||||||
color.rgb /= color.a;
|
|
||||||
|
|
||||||
gl_FragDepth = texture(DepthTexture, uv)[0];
|
gl_FragDepth = texture(DepthTexture, uv)[0];
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
simple_frag = '''
|
|
||||||
#version 330
|
|
||||||
|
|
||||||
uniform sampler2D Texture;
|
|
||||||
|
|
||||||
in vec2 uv;
|
|
||||||
out vec4 color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
color = texture(Texture, uv);
|
|
||||||
if(color.a == 0) discard;
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
fill_program = ctx.program(
|
fill_program = ctx.program(
|
||||||
vertex_shader=simple_vert,
|
vertex_shader=simple_vert,
|
||||||
fragment_shader=alpha_adjust_frag,
|
fragment_shader=alpha_adjust_frag,
|
||||||
)
|
)
|
||||||
border_program = ctx.program(
|
|
||||||
vertex_shader=simple_vert,
|
|
||||||
fragment_shader=simple_frag,
|
|
||||||
)
|
|
||||||
|
|
||||||
fill_program['Texture'].value = get_texture_id(fill_texture)
|
fill_program['Texture'].value = get_texture_id(fill_texture)
|
||||||
fill_program['DepthTexture'].value = get_texture_id(depth_texture)
|
fill_program['DepthTexture'].value = get_texture_id(depth_texture)
|
||||||
border_program['Texture'].value = get_texture_id(border_texture)
|
|
||||||
|
|
||||||
verts = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
|
verts = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
|
||||||
simple_vbo = ctx.buffer(verts.astype('f4').tobytes())
|
simple_vbo = ctx.buffer(verts.astype('f4').tobytes())
|
||||||
|
@ -226,12 +203,4 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray]:
|
||||||
fill_program, simple_vbo, 'texcoord',
|
fill_program, simple_vbo, 'texcoord',
|
||||||
mode=moderngl.TRIANGLE_STRIP
|
mode=moderngl.TRIANGLE_STRIP
|
||||||
)
|
)
|
||||||
border_texture_vao = ctx.simple_vertex_array(
|
return (fill_texture_fbo, fill_texture_vao, depth_texture_fbo)
|
||||||
border_program, simple_vbo, 'texcoord',
|
|
||||||
mode=moderngl.TRIANGLE_STRIP
|
|
||||||
)
|
|
||||||
return (
|
|
||||||
fill_texture_fbo, fill_texture_vao,
|
|
||||||
border_texture_fbo, border_texture_vao,
|
|
||||||
depth_texture_fbo,
|
|
||||||
)
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue