diff --git a/manimlib/shader_wrapper.py b/manimlib/shader_wrapper.py index 49f9782e..b175d3ed 100644 --- a/manimlib/shader_wrapper.py +++ b/manimlib/shader_wrapper.py @@ -277,7 +277,7 @@ class VShaderWrapper(ShaderWrapper): f"{vtype}_{name}": get_shader_code_from_file( os.path.join(f"quadratic_bezier_{vtype}", f"{name}.glsl") ) - for vtype in ["stroke", "fill"] + for vtype in ["stroke", "fill", "depth"] for name in ["vert", "geom", "frag"] } @@ -294,7 +294,13 @@ class VShaderWrapper(ShaderWrapper): geometry_shader=self.program_code["fill_geom"], fragment_shader=self.program_code["fill_frag"], ) - self.programs = [self.stroke_program, self.fill_program] + self.fill_depth_program = get_shader_program( + self.ctx, + vertex_shader=self.program_code["depth_vert"], + geometry_shader=self.program_code["depth_geom"], + fragment_shader=self.program_code["depth_frag"], + ) + self.programs = [self.stroke_program, self.fill_program, self.fill_depth_program] # Full vert format looks like this (total of 4x23 = 92 bytes): # point 3 @@ -314,6 +320,9 @@ class VShaderWrapper(ShaderWrapper): self.fill_border_vert_format = '3f 20x 4f 4f 24x 1f' self.fill_border_vert_attributes = ['point', 'joint_product', 'stroke_rgba', 'stroke_width'] + self.fill_depth_vert_format = '3f 52x 3f 16x' + self.fill_depth_vert_attributes = ['point', 'base_point'] + def init_vertex_objects(self): self.vbo = None self.stroke_vao = None @@ -337,7 +346,12 @@ class VShaderWrapper(ShaderWrapper): content=[(self.vbo, self.fill_border_vert_format, *self.fill_border_vert_attributes)], mode=self.render_primitive, ) - self.vaos = [self.stroke_vao, self.fill_vao, self.fill_border_vao] + self.fill_depth_vao = self.ctx.vertex_array( + program=self.fill_depth_program, + content=[(self.vbo, self.fill_depth_vert_format, *self.fill_depth_vert_attributes)], + mode=self.render_primitive, + ) + self.vaos = [self.stroke_vao, self.fill_vao, self.fill_border_vao, self.fill_depth_vao] def set_backstroke(self, value: bool = True): self.stroke_behind = value @@ -366,7 +380,7 @@ class VShaderWrapper(ShaderWrapper): return original_fbo = self.ctx.fbo - texture_fbo, texture_vao = self.fill_canvas + texture_fbo, depth_texture_fbo, texture_vao = self.fill_canvas texture_fbo.clear() texture_fbo.use() @@ -384,17 +398,27 @@ class VShaderWrapper(ShaderWrapper): self.ctx.disable(moderngl.DEPTH_TEST) self.fill_vao.render() if apply_depth_test: + depth_texture_fbo.clear(1.0) + depth_texture_fbo.use() + gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE) + gl.glBlendEquation(gl.GL_MIN) + self.fill_depth_vao.render() self.ctx.enable(moderngl.DEPTH_TEST) - original_fbo.use() - gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA) - - texture_vao.render() - - gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) - + # Border width is used for antialiasing. Take the maximum between these + # two alphas, before compositing back to the rest of the scene + gl.glBlendFuncSeparate( + gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA, + gl.GL_ONE, gl.GL_ZERO + ) + gl.glBlendEquationSeparate(gl.GL_FUNC_ADD, gl.GL_MAX) self.fill_border_vao.render() + original_fbo.use() + gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) + gl.glBlendEquation(gl.GL_FUNC_ADD) + texture_vao.render() + def render(self): if self.stroke_behind: self.render_stroke() diff --git a/manimlib/shaders/quadratic_bezier_depth/frag.glsl b/manimlib/shaders/quadratic_bezier_depth/frag.glsl new file mode 100644 index 00000000..5d68a965 --- /dev/null +++ b/manimlib/shaders/quadratic_bezier_depth/frag.glsl @@ -0,0 +1,7 @@ +#version 330 + +out float frag_depth; + +void main() { + frag_depth = gl_FragCoord.z; +} diff --git a/manimlib/shaders/quadratic_bezier_depth/geom.glsl b/manimlib/shaders/quadratic_bezier_depth/geom.glsl new file mode 100644 index 00000000..fe07b440 --- /dev/null +++ b/manimlib/shaders/quadratic_bezier_depth/geom.glsl @@ -0,0 +1,39 @@ +#version 330 + +layout (triangles) in; +layout (triangle_strip, max_vertices = 6) out; + +in vec3 verts[3]; +in vec3 v_base_point[3]; +in int v_vert_index[3]; + +out float depth; + +#INSERT emit_gl_Position.glsl + + +void emit_triangle(vec3 points[3]){ + for(int i = 0; i < 3; i++){ + emit_gl_Position(points[i]); + // float z = gl_Position.z / gl_Position.w; + // depth = 0.5 * z + 0.5; + EmitVertex(); + } + EndPrimitive(); +} + + +void main(){ + // Vector graphic shaders use TRIANGLE_STRIP, but only + // every other one needs to be rendered + if (v_vert_index[0] % 2 != 0) return; + + // Curves are marked as ended when the handle after + // the first anchor is set equal to that anchor + if (verts[0] == verts[1]) return; + + // Emit main triangle + emit_triangle(vec3[3](v_base_point[0], verts[0], verts[2])); + emit_triangle(vec3[3](verts[0], verts[1], verts[2])); +} + diff --git a/manimlib/shaders/quadratic_bezier_depth/vert.glsl b/manimlib/shaders/quadratic_bezier_depth/vert.glsl new file mode 100644 index 00000000..1f4c8654 --- /dev/null +++ b/manimlib/shaders/quadratic_bezier_depth/vert.glsl @@ -0,0 +1,14 @@ +#version 330 + +in vec3 point; +in vec3 base_point; + +out vec3 verts; +out vec3 v_base_point; +out int v_vert_index; + +void main(){ + verts = point; + v_base_point = base_point; + v_vert_index = gl_VertexID; +} \ No newline at end of file diff --git a/manimlib/utils/shaders.py b/manimlib/utils/shaders.py index d21c812c..010362c4 100644 --- a/manimlib/utils/shaders.py +++ b/manimlib/utils/shaders.py @@ -148,14 +148,14 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray]: along with the rgb value which is meant to be discarded. """ cam_config = get_configuration(parse_cli())['camera_config'] - # Double the size so as to effectively to 4x multi-sample antialiasing - size = (2 * cam_config['pixel_width'], 2 * cam_config['pixel_height']) + size = (cam_config['pixel_width'], cam_config['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') - depth_texture = ctx.depth_texture(size=size) - texture_fbo = ctx.framebuffer(texture, depth_texture) + depth_texture = ctx.texture(size=size, components=1, dtype='f4') + texture_fbo = ctx.framebuffer(texture) + depth_texture_fbo = ctx.framebuffer(depth_texture) simple_program = ctx.program( vertex_shader=''' @@ -200,4 +200,4 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray]: 'texcoord', mode=moderngl.TRIANGLE_STRIP ) - return (texture_fbo, fill_texture_vao) + return (texture_fbo, depth_texture_fbo, fill_texture_vao)