Clean up fill shader a bit

This commit is contained in:
Grant Sanderson 2023-01-27 08:26:54 -08:00
parent 746b52cda5
commit 1707958e0f
4 changed files with 41 additions and 26 deletions

View file

@ -13,7 +13,7 @@ from manimlib.utils.shaders import get_shader_code_from_file
from manimlib.utils.shaders import get_shader_program
from manimlib.utils.shaders import image_path_to_texture
from manimlib.utils.shaders import get_texture_id
from manimlib.utils.shaders import get_fill_palette
from manimlib.utils.shaders import get_fill_canvas
from manimlib.utils.shaders import release_texture
from typing import TYPE_CHECKING
@ -275,7 +275,7 @@ class FillShaderWrapper(ShaderWrapper):
**kwargs
):
super().__init__(ctx, *args, **kwargs)
self.texture_fbo, self.texture_vao = get_fill_palette(self.ctx)
self.fill_canvas = get_fill_canvas(self.ctx)
def render(self):
vao = self.vao
@ -287,9 +287,10 @@ class FillShaderWrapper(ShaderWrapper):
return
original_fbo = self.ctx.fbo
texture_fbo, texture_vao, null_rgb = self.fill_canvas
self.texture_fbo.clear()
self.texture_fbo.use()
texture_fbo.clear(*null_rgb, 0.0)
texture_fbo.use()
gl.glBlendFuncSeparate(
# Ordinary blending for colors
gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA,
@ -306,6 +307,6 @@ class FillShaderWrapper(ShaderWrapper):
gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA)
gl.glBlendEquation(gl.GL_FUNC_ADD)
self.texture_vao.render(moderngl.TRIANGLE_STRIP)
texture_vao.render(moderngl.TRIANGLE_STRIP)
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)

View file

@ -32,7 +32,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.98 * frag_color.a;
float a = 0.99 * frag_color.a;
if(winding && orientation < 0) a = -a / (1 - a);
frag_color.a = a;

View file

@ -37,8 +37,6 @@ void emit_triangle(vec3 points[3], vec4 v_color[3]){
uv_coords = SIMPLE_QUADRATIC[i];
color = v_color[i];
point = points[i];
// Pure black will be used to discard fragments later
if(winding && color.rgb == vec3(0.0)) color.rgb += vec3(3.0 / 256);
gl_Position = get_gl_Position(points[i]);
EmitVertex();
}

View file

@ -103,10 +103,16 @@ def get_colormap_code(rgb_list: Sequence[float]) -> str:
@lru_cache()
def get_fill_palette(ctx) -> Tuple[Framebuffer, VertexArray]:
def get_fill_canvas(ctx) -> Tuple[Framebuffer, VertexArray, Tuple[float, float, float]]:
"""
Creates a texture, loaded into a frame buffer, and a vao
which can display that texture as a simple quad onto a screen.
Because VMobjects with fill are rendered in a funny way, using
alpha blending to effectively compute the winding number around
each pixel, they need to be rendered to a separate texture, which
is then composited onto the ordinary frame buffer.
This returns a texture, loaded into a frame buffer, and a vao
which can display that texture as a simple quad onto a screen,
along with the rgb value which is meant to be discarded.
"""
cam_config = get_customization()['camera_resolutions']
res_name = cam_config['default_resolution']
@ -118,6 +124,12 @@ def get_fill_palette(ctx) -> Tuple[Framebuffer, VertexArray]:
depth_buffer = ctx.depth_renderbuffer(size) # TODO, currently not used
texture_fbo = ctx.framebuffer(texture, depth_buffer)
# 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
null_rgb = (-0.25, -0.25, -0.25)
simple_program = ctx.program(
vertex_shader='''
#version 330
@ -136,27 +148,30 @@ def get_fill_palette(ctx) -> Tuple[Framebuffer, VertexArray]:
uniform sampler2D Texture;
uniform float v_nudge;
uniform float h_nudge;
uniform vec3 null_rgb;
in vec2 v_textcoord;
out vec4 color;
const float MIN_RGB = 3.0 / 256;
const float MIN_DIST_TO_NULL = 0.2;
void main() {
// Apply poor man's anti-aliasing
vec2 tc0 = v_textcoord + vec2(0, 0);
vec2 tc1 = v_textcoord + vec2(0, h_nudge);
vec2 tc2 = v_textcoord + vec2(v_nudge, 0);
vec2 tc3 = v_textcoord + vec2(v_nudge, h_nudge);
color =
0.25 * texture(Texture, tc0) +
0.25 * texture(Texture, tc1) +
0.25 * texture(Texture, tc2) +
0.25 * texture(Texture, tc3);
if(abs(color.r) < MIN_RGB && abs(color.g) < MIN_RGB && abs(color.b) < MIN_RGB)
discard;
// Counteract scaling in quadratic_bezier_frag
color = color / 0.98;
vec2 nudges[4] = vec2[4](
vec2(0, 0),
vec2(0, h_nudge),
vec2(v_nudge, 0),
vec2(v_nudge, h_nudge)
);
color = vec4(0.0);
for(int i = 0; i < 4; i++){
color += 0.25 * texture(Texture, v_textcoord + nudges[i]);
}
if(distance(color.rgb, null_rgb) < MIN_DIST_TO_NULL) discard;
// Un-blend from the null value
color.rgb -= (1 - color.a) * null_rgb;
//TODO, set gl_FragDepth;
}
''',
@ -166,6 +181,7 @@ def get_fill_palette(ctx) -> Tuple[Framebuffer, VertexArray]:
# Half pixel width/height
simple_program['h_nudge'].value = 0.5 / size[0]
simple_program['v_nudge'].value = 0.5 / size[1]
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(
@ -173,4 +189,4 @@ def get_fill_palette(ctx) -> Tuple[Framebuffer, VertexArray]:
ctx.buffer(verts.astype('f4').tobytes()),
'texcoord',
)
return (texture_fbo, fill_texture_vao)
return (texture_fbo, fill_texture_vao, null_rgb)