3b1b-manim/manimlib/shaders/quadratic_bezier_fill/geom.glsl
2023-01-14 08:00:21 -08:00

131 lines
3.1 KiB
GLSL

#version 330
layout (triangles) in;
layout (triangle_strip, max_vertices = 5) out;
uniform float anti_alias_width;
uniform vec2 pixel_shape;
in vec3 verts[3];
in float v_orientation[3];
in vec4 v_color[3];
in float v_vert_index[3];
out vec4 color;
out float fill_all;
out float uv_anti_alias_width;
out float orientation;
// uv space is where the curve coincides with y = x^2
out vec2 uv_coords;
out float is_linear;
const float ANGLE_THRESHOLD = 1e-3;
// Analog of import for manim only
#INSERT get_gl_Position.glsl
#INSERT get_xy_to_uv.glsl
#INSERT finalize_color.glsl
void emit_vertex_wrapper(vec3 point, int index, vec3 unit_normal){
color = finalize_color(
v_color[index],
point,
unit_normal,
light_source_position,
camera_position,
reflectiveness,
gloss,
shadow
);
gl_Position = get_gl_Position(point);
EmitVertex();
}
void emit_simple_triangle(vec3 unit_normal){
for(int i = 0; i < 3; i++){
emit_vertex_wrapper(verts[i], i, unit_normal);
}
EndPrimitive();
}
void emit_pentagon(
// Triangle vertices
vec3 p0,
vec3 p1,
vec3 p2,
// Unit tangent vector
vec3 t01,
vec3 t12,
vec3 unit_normal
){
// Vectors perpendicular to the curve in the plane of the curve
// pointing outside the curve
vec3 p0_perp = cross(t01, unit_normal);
vec3 p2_perp = cross(t12, unit_normal);
float angle = acos(clamp(dot(t01, t12), -1, 1));
is_linear = float(angle < ANGLE_THRESHOLD);
bool fill_inside = orientation > 0.0;
float aaw = anti_alias_width * frame_shape.y / pixel_shape.y;
vec3 corners[5] = vec3[5](p0, p0, p1, p2, p2);
if(fill_inside || bool(is_linear)){
// Add buffer outside the curve
corners[0] += aaw * p0_perp;
corners[2] += 0.5 * aaw * (p0_perp + p2_perp);
corners[4] += aaw * p2_perp;
}
if(!fill_inside || bool(is_linear)){
// Add buffer inside the curve
corners[1] -= aaw * p0_perp;
corners[3] -= aaw * p2_perp;
}
// Compute xy_to_uv matrix, and potentially re-evaluate bezier degree
mat3 xy_to_uv = get_xy_to_uv(p0.xy, p1.xy, p2.xy, is_linear, is_linear);
uv_anti_alias_width = aaw * length(xy_to_uv[0].xy);
for(int i = 0; i < 5; i++){
int j = int(sign(i - 1) + 1); // Maps i = [0, 1, 2, 3, 4] onto j = [0, 0, 1, 2, 2]
vec3 corner = corners[i];
uv_coords = (xy_to_uv * vec3(corner.xy, 1.0)).xy;
emit_vertex_wrapper(corner, j, unit_normal);
}
EndPrimitive();
}
void main(){
// If vert indices are sequential, don't fill all
fill_all = float(
(v_vert_index[1] - v_vert_index[0]) != 1.0 ||
(v_vert_index[2] - v_vert_index[1]) != 1.0
);
vec3 p0 = verts[0];
vec3 p1 = verts[1];
vec3 p2 = verts[2];
vec3 t01 = p1 - p0;
vec3 t12 = p2 - p1;
vec3 unit_normal = normalize(cross(t01, t12));
if(bool(fill_all)){
emit_simple_triangle(unit_normal);
return;
}
orientation = v_orientation[1];
emit_pentagon(
p0, p1, p2,
normalize(t01),
normalize(t12),
unit_normal
);
}