mirror of
https://github.com/3b1b/manim.git
synced 2025-11-13 18:28:06 +00:00
Various cleanups for stroke shader
This commit is contained in:
parent
ae2a253fb1
commit
89d9e260eb
3 changed files with 65 additions and 97 deletions
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue