Merge pull request #1985 from 3b1b/cleaner-winding-fill

Cleaner winding fill
This commit is contained in:
Grant Sanderson
2023-02-02 11:39:18 -08:00
committed by GitHub
5 changed files with 20 additions and 35 deletions

View File

@ -309,6 +309,8 @@ class VMobjectFromSVGPath(VMobject):
path_string = self.path_obj.d()
if path_string not in PATH_TO_POINTS:
self.handle_commands()
if not self._use_winding_fill:
self.subdivide_intersections()
# Save for future use
PATH_TO_POINTS[path_string] = self.get_points().copy()
else:

View File

@ -867,8 +867,10 @@ class VMobject(Mobject):
# Alignment
def align_points(self, vmobject: VMobject) -> Self:
winding = self._use_winding_fill and vmobject._use_winding_fill
self.use_winding_fill(winding)
vmobject.use_winding_fill(winding)
if winding != self._use_winding_fill:
self.use_winding_fill(winding)
if winding != vmobject._use_winding_fill:
vmobject.use_winding_fill(winding)
if self.get_num_points() == len(vmobject.get_points()):
# If both have fill, and they have the same shape, just
# give them the same triangulation so that it's not recalculated

View File

@ -287,24 +287,22 @@ class FillShaderWrapper(ShaderWrapper):
return
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()
gl.glBlendFuncSeparate(
# Ordinary blending for colors
gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA,
# Just take the max of the alphas, given the shenanigans
# with how alphas are being used to compute winding numbers
gl.GL_ONE, gl.GL_ONE,
# The effect of blending with -a / (1 - a)
# should be to cancel out
gl.GL_ONE_MINUS_DST_ALPHA, gl.GL_ONE,
)
gl.glBlendEquationSeparate(gl.GL_FUNC_ADD, gl.GL_MAX)
super().render()
original_fbo.use()
gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA)
gl.glBlendEquation(gl.GL_FUNC_ADD)
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
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);
frag_color.a = a;

View File

@ -103,7 +103,7 @@ def get_colormap_code(rgb_list: Sequence[float]) -> str:
@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
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)
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(
vertex_shader='''
#version 330
in vec2 texcoord;
out vec2 v_textcoord;
out vec2 uv;
void main() {
gl_Position = vec4((2.0 * texcoord - 1.0), 0.0, 1.0);
v_textcoord = texcoord;
uv = texcoord;
}
''',
fragment_shader='''
@ -150,31 +140,24 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray, Tu
uniform sampler2D Texture;
uniform sampler2D DepthTexture;
uniform vec3 null_rgb;
in vec2 v_textcoord;
in vec2 uv;
out vec4 color;
const float MIN_DIST_TO_NULL = 0.2;
void main() {
color = texture(Texture, v_textcoord);
color = texture(Texture, uv);
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
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['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]])
fill_texture_vao = ctx.simple_vertex_array(
@ -183,4 +166,4 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray, Tu
'texcoord',
mode=moderngl.TRIANGLE_STRIP
)
return (texture_fbo, fill_texture_vao, null_rgb)
return (texture_fbo, fill_texture_vao)