diff --git a/manimlib/shaders/inserts/quadratic_bezier_distance.glsl b/manimlib/shaders/inserts/quadratic_bezier_distance.glsl index 173e4aec..c36ecf1d 100644 --- a/manimlib/shaders/inserts/quadratic_bezier_distance.glsl +++ b/manimlib/shaders/inserts/quadratic_bezier_distance.glsl @@ -1,14 +1,11 @@ -// Must be inserted in a context with a definition for modify_distance_for_endpoints - // All of this is with respect to a curve that's been rotated/scaled // so that b0 = (0, 0) and b1 = (1, 0). That is, b2 entirely // determines the shape of the curve +uniform float joint_type; + + vec2 bezier(float t, vec2 b2){ - // Quick returns for the 0 and 1 cases - if (t == 0) return vec2(0, 0); - else if (t == 1) return b2; - // Everything else return vec2( 2 * t * (1 - t) + b2.x * t*t, b2.y * t * t @@ -64,22 +61,19 @@ int cubic_solve(float a, float b, float c, float d, out float roots[3]){ return n_valid_roots; } -float dist_to_line(vec2 p, vec2 b2){ - float t = clamp(p.x / b2.x, 0, 1); - float dist; - if(t == 0) dist = length(p); - else if(t == 1) dist = distance(p, b2); - else dist = abs(p.y); - return modify_distance_for_endpoints(p, dist, t); +float dist_to_line(vec2 p, vec2 b2){ + if(joint_type == 1){ + float t = p.x / b2.x; + if (t < 0) return length(p); + if (t > 1) return distance(p, b2); + } + return abs(p.y); } float dist_to_point_on_curve(vec2 p, float t, vec2 b2){ - t = clamp(t, 0, 1); - return modify_distance_for_endpoints( - p, length(p - bezier(t, b2)), t - ); + return length(p - bezier(t, b2)); } diff --git a/manimlib/shaders/quadratic_bezier_stroke/frag.glsl b/manimlib/shaders/quadratic_bezier_stroke/frag.glsl index f795a487..aae49883 100644 --- a/manimlib/shaders/quadratic_bezier_stroke/frag.glsl +++ b/manimlib/shaders/quadratic_bezier_stroke/frag.glsl @@ -11,81 +11,59 @@ in float uv_anti_alias_width; in float has_prev; in float has_next; -in float bevel; -in float angle_from_prev; -in float angle_to_next; - in float bezier_degree; out vec4 frag_color; +#INSERT quadratic_bezier_distance.glsl + + float cross2d(vec2 v, vec2 w){ return v.x * w.y - w.x * v.y; } - float modify_distance_for_endpoints(vec2 p, float dist, float t){ + if (0 <= t && t <= 1) return dist; + float buff = 0.5 * uv_stroke_width - uv_anti_alias_width; // Check the beginning of the curve - if(t == 0){ - // Clip the start - if(has_prev == 0) return max(dist, -p.x + buff); - // Bevel start - if(bevel == 1){ - float a = angle_from_prev; - mat2 rot = mat2( - cos(a), sin(a), - -sin(a), cos(a) - ); - // Dist for intersection of two lines - float bevel_d = max(abs(p.y), abs((rot * p).y)); - // Dist for union of this intersection with the real curve - // intersected with radius 2 away from curve to smooth out - // really sharp corners - return max(min(dist, bevel_d), dist / 2); - } - // Otherwise, start will be rounded off - }else if(t == 1){ + if(t < 0 && has_prev == 0) return max(dist, -p.x + buff); + + if(t > 1){ // Check the end of the curve - // TODO, too much code repetition - vec2 v21 = (bezier_degree == 2) ? vec2(1, 0) - uv_b2 : vec2(-1, 0); + vec2 v21 = vec2(1, 0) - uv_b2; float len_v21 = length(v21); - if(len_v21 == 0){ - v21 = -uv_b2; - len_v21 = length(v21); - } + if(len_v21 == 0) len_v21 = length(-uv_b2); float perp_dist = dot(p - uv_b2, v21) / len_v21; if(has_next == 0) return max(dist, -perp_dist + buff); - // Bevel end - if(bevel == 1){ - float a = -angle_to_next; - mat2 rot = mat2( - cos(a), sin(a), - -sin(a), cos(a) - ); - vec2 v21_unit = v21 / length(v21); - float bevel_d = max( - abs(cross2d(p - uv_b2, v21_unit)), - abs(cross2d((rot * (p - uv_b2)), v21_unit)) - ); - return max(min(dist, bevel_d), dist / 2); - } - // Otherwise, end will be rounded off } return dist; } -#INSERT quadratic_bezier_distance.glsl +float dist_to_curve(){ + float dist = min_dist_to_curve(uv_coords, uv_b2, bezier_degree); + if(has_prev == 0 && uv_coords.x < 0){ + float buff = 0.5 * uv_stroke_width - uv_anti_alias_width; + return max(-uv_coords.x + buff, dist); + } + if(has_next == 0 && uv_coords.x > uv_b2.x){ + float buff = 0.5 * uv_stroke_width - uv_anti_alias_width; + vec2 v12 = normalize(uv_b2 - vec2(1, 0)); + float perp_dist = dot(uv_coords - uv_b2, v12); + if (perp_dist > 0) return max(perp_dist + buff, dist); + } + return dist; +} void main() { if (uv_stroke_width == 0) discard; - float dist_to_curve = min_dist_to_curve(uv_coords, uv_b2, bezier_degree); + // An sdf for the region around the curve we wish to color. - float signed_dist = abs(dist_to_curve) - 0.5 * uv_stroke_width; + float signed_dist = abs(dist_to_curve()) - 0.5 * uv_stroke_width; frag_color = color; frag_color.a *= smoothstep(0.5, -0.5, signed_dist / uv_anti_alias_width); diff --git a/manimlib/shaders/quadratic_bezier_stroke/geom.glsl b/manimlib/shaders/quadratic_bezier_stroke/geom.glsl index 5e4bdf3c..9ac28714 100644 --- a/manimlib/shaders/quadratic_bezier_stroke/geom.glsl +++ b/manimlib/shaders/quadratic_bezier_stroke/geom.glsl @@ -32,17 +32,11 @@ out float uv_anti_alias_width; out float has_prev; out float has_next; -out float bevel; -out float angle_from_prev; -out float angle_to_next; - out float bezier_degree; out vec2 uv_coords; out vec2 uv_b2; -vec3 unit_normal; - // Codes for joint types const float AUTO_JOINT = 0; const float ROUND_JOINT = 1; @@ -93,7 +87,14 @@ void create_joint(float angle, vec2 unit_tan, float buff, // This function is responsible for finding the corners of // a bounding region around the bezier curve, which can be // emitted as a triangle fan -int get_corners(vec2 controls[3], int degree, float stroke_widths[3], out vec2 corners[5]){ +int get_corners( + vec2 controls[3], + int degree, + float stroke_widths[3], + float angle_from_prev, + float angle_to_next, + out vec2 corners[5] +){ vec2 p0 = controls[0]; vec2 p1 = controls[1]; vec2 p2 = controls[2]; @@ -141,30 +142,9 @@ int get_corners(vec2 controls[3], int degree, float stroke_widths[3], out vec2 c } -void find_joint_info(){ - angle_from_prev = v_joint_angle[0]; - angle_to_next = v_joint_angle[2]; - has_prev = 1.0; - has_next = 1.0; - if(angle_from_prev == DISJOINT_CONST){ - angle_from_prev = 0.0; - has_prev = 0.0; - } - if(angle_to_next == DISJOINT_CONST){ - angle_to_next = 0.0; - has_next = 0.0; - } - bool should_bevel = ( - (joint_type == AUTO_JOINT && bezier_degree == 1.0) || - joint_type == BEVEL_JOINT - ); - bevel = float(should_bevel); -} - - void main() { bezier_degree = (abs(v_joint_angle[1]) < 1e-3) ? 1.0 : 2.0; - unit_normal = get_unit_normal(vec3[3](verts[0], verts[1], verts[2])); + vec3 unit_normal = get_unit_normal(vec3[3](verts[0], verts[1], verts[2])); // Adjust stroke width based on distance from the camera float scaled_strokes[3]; @@ -185,17 +165,33 @@ void main() { float sf = perspective_scale_factor(verts[i].z, focal_distance); flat_controls[i] = sf * verts[i].xy; } + // If the curve is flat, put the middle control in the midpoint if (bezier_degree == 1.0){ flat_controls[1] = 0.5 * (flat_controls[0] + flat_controls[2]); } - // Set joint angles, etc. - find_joint_info(); + // Set joint information + float angle_from_prev = v_joint_angle[0]; + float angle_to_next = v_joint_angle[2]; + has_prev = 1.0; + has_next = 1.0; + if(angle_from_prev == DISJOINT_CONST){ + angle_from_prev = 0.0; + has_prev = 0.0; + } + if(angle_to_next == DISJOINT_CONST){ + angle_to_next = 0.0; + has_next = 0.0; + } // Corners of a bounding region around curve vec2 corners[5]; - int n_corners = get_corners(flat_controls, int(bezier_degree), scaled_strokes, corners); + int n_corners = get_corners( + flat_controls, int(bezier_degree), scaled_strokes, + angle_from_prev, angle_to_next, + corners + ); int index_map[5] = int[5](0, 0, 1, 2, 2); if(n_corners == 4) index_map[2] = 2;