mirror of
https://github.com/3b1b/manim.git
synced 2025-07-28 20:43:56 +08:00
Fixed the random-dimples-on-zeros bug while fixing up the fill shaders
This commit is contained in:
@ -64,7 +64,6 @@ class VMobject(Mobject):
|
||||
('point', np.float32, (3,)),
|
||||
('color', np.float32, (4,)),
|
||||
('fill_all', np.float32, (1,)),
|
||||
('orientation', np.float32, (1,)),
|
||||
],
|
||||
"stroke_dtype": [
|
||||
("point", np.float32, (3,)),
|
||||
@ -984,16 +983,13 @@ class VMobject(Mobject):
|
||||
|
||||
# Triangulate
|
||||
inner_verts = points[inner_vert_indices]
|
||||
inner_tri_indices = inner_vert_indices[
|
||||
earclip_triangulation(inner_verts, rings)
|
||||
]
|
||||
inner_tri_indices = inner_vert_indices[earclip_triangulation(inner_verts, rings)]
|
||||
|
||||
tri_indices = np.hstack([indices, inner_tri_indices])
|
||||
return tri_indices
|
||||
|
||||
def get_fill_shader_data(self):
|
||||
points = self.points
|
||||
|
||||
orientation = self.get_orientation()
|
||||
tri_indices = self.get_triangulation(orientation)
|
||||
|
||||
@ -1007,8 +1003,9 @@ class VMobject(Mobject):
|
||||
# are on the boundary, and the rest are in the interior
|
||||
data["fill_all"][:len(points)] = 0
|
||||
data["fill_all"][len(points):] = 1
|
||||
data["orientation"] = orientation
|
||||
|
||||
# Always send points in a positively oriented way
|
||||
if orientation < 0:
|
||||
data["point"][:len(points)] = points[::-1]
|
||||
return data
|
||||
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
#version 330
|
||||
|
||||
in vec4 color;
|
||||
in float fill_type;
|
||||
in float fill_all; // Either 0 or 1e
|
||||
in float uv_anti_alias_width;
|
||||
|
||||
in vec2 uv_coords;
|
||||
in vec2 wz_coords;
|
||||
in vec2 uv_b2;
|
||||
in float bezier_degree;
|
||||
|
||||
@ -16,7 +15,7 @@ const float FILL_OUTSIDE = 1;
|
||||
const float FILL_ALL = 2;
|
||||
|
||||
|
||||
// Needed for quadratic_bezier_distance
|
||||
// Needed for quadratic_bezier_distance insertion below
|
||||
float modify_distance_for_endpoints(vec2 p, float dist, float t){
|
||||
return dist;
|
||||
}
|
||||
@ -26,27 +25,36 @@ float modify_distance_for_endpoints(vec2 p, float dist, float t){
|
||||
// replaces this line with the contents of quadratic_bezier_sdf.glsl
|
||||
#INSERT quadratic_bezier_distance.glsl
|
||||
|
||||
|
||||
bool is_inside_curve(){
|
||||
if(bezier_degree < 2) return false;
|
||||
|
||||
float value = wz_coords.x * wz_coords.x - wz_coords.y;
|
||||
if(fill_type == FILL_INSIDE) return value < 0;
|
||||
if(fill_type == FILL_OUTSIDE) return value > 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
float sdf(){
|
||||
if(is_inside_curve()) return -1.0;
|
||||
// For really flat curves, just take the distance to the curve
|
||||
if(bezier_degree < 2 || abs(uv_b2.y / uv_b2.x) < uv_anti_alias_width){
|
||||
return min_dist_to_curve(uv_coords, uv_b2, bezier_degree, false);
|
||||
}
|
||||
// This converts uv_coords to a space where the bezier points sit on
|
||||
// (0, 0), (1/2, 0) and (1, 1), so that the curve can be expressed implicityly
|
||||
// as y = x^2.
|
||||
float u2 = uv_b2.x;
|
||||
float v2 = uv_b2.y;
|
||||
mat2 to_simple_space = mat2(
|
||||
v2, 0,
|
||||
2 - u2, 4 * v2
|
||||
);
|
||||
vec2 p = to_simple_space * uv_coords;
|
||||
|
||||
float Fp = sign(v2) * (p.x * p.x - p.y);
|
||||
|
||||
vec2 grad = vec2(
|
||||
- 2 * p.x * v2, // del C / del u
|
||||
4 * v2 - 4 * p.x * (2 - u2) // del C / del v
|
||||
);
|
||||
return Fp / length(grad);
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
if (color.a == 0) discard;
|
||||
frag_color = color;
|
||||
if (fill_type == FILL_ALL) return;
|
||||
// TODO, Add shading based on normal vector, light position and gloss
|
||||
if (fill_all == 1.0) return;
|
||||
frag_color.a *= smoothstep(1, 0, sdf() / uv_anti_alias_width);
|
||||
// frag_color.a += 0.2;
|
||||
}
|
||||
|
@ -11,17 +11,13 @@ uniform vec3 frame_center;
|
||||
in vec3 bp[3];
|
||||
in vec4 v_color[3];
|
||||
in float v_fill_all[3];
|
||||
in float v_orientation[3];
|
||||
|
||||
out vec4 color;
|
||||
out float fill_type;
|
||||
out float fill_all;
|
||||
out float uv_anti_alias_width;
|
||||
|
||||
// uv space is where b0 = (0, 0), b1 = (1, 0), and transform is orthogonal
|
||||
out vec2 uv_coords;
|
||||
out vec2 uv_b2;
|
||||
// wz space is where b0 = (0, 0), b1 = (0.5, 0), b2 = (1, 1)
|
||||
out vec2 wz_coords;
|
||||
|
||||
out float bezier_degree;
|
||||
|
||||
@ -38,30 +34,6 @@ const float SQRT5 = 2.236068;
|
||||
#INSERT quadratic_bezier_geometry_functions.glsl
|
||||
#INSERT scale_and_shift_point_for_frame.glsl
|
||||
|
||||
|
||||
mat3 get_xy_to_wz(vec2 b0, vec2 b1, vec2 b2){
|
||||
// If linear or null, this matrix is not needed
|
||||
if(bezier_degree < 2) return mat3(1.0);
|
||||
|
||||
vec2 inv_col1 = 2 * (b1 - b0);
|
||||
vec2 inv_col2 = b2 - 2 * b1 + b0;
|
||||
float inv_det = cross(inv_col1, inv_col2);
|
||||
|
||||
mat3 transform = mat3(
|
||||
inv_col2.y, -inv_col1.y, 0,
|
||||
-inv_col2.x, inv_col1.x, 0,
|
||||
0, 0, inv_det
|
||||
) / inv_det;
|
||||
|
||||
mat3 shift = mat3(
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
-b0.x, -b0.y, 1
|
||||
);
|
||||
return transform * shift;
|
||||
}
|
||||
|
||||
|
||||
void emit_simple_triangle(){
|
||||
for(int i = 0; i < 3; i++){
|
||||
color = v_color[i];
|
||||
@ -75,29 +47,17 @@ void emit_simple_triangle(){
|
||||
}
|
||||
|
||||
|
||||
void emit_pentagon(vec2 bp0, vec2 bp1, vec2 bp2, float orientation){
|
||||
void emit_pentagon(vec2 bp0, vec2 bp1, vec2 bp2){
|
||||
// Tangent vectors
|
||||
vec2 t01 = normalize(bp1 - bp0);
|
||||
vec2 t12 = normalize(bp2 - bp1);
|
||||
|
||||
// Inside and left turn -> rot right -> -1
|
||||
// Outside and left turn -> rot left -> +1
|
||||
// Inside and right turn -> rot left -> +1
|
||||
// Outside and right turn -> rot right -> -1
|
||||
float c_orient = (cross(t01, t12) > 0) ? 1 : -1;
|
||||
c_orient *= orientation;
|
||||
|
||||
bool fill_in = (c_orient > 0);
|
||||
fill_type = fill_in ? FILL_INSIDE : FILL_OUTSIDE;
|
||||
|
||||
// float orient = in_or_out * c_orient;
|
||||
|
||||
// Normal vectors
|
||||
// Rotate tangent vector 90-degrees clockwise
|
||||
// if the curve is positively oriented, otherwise
|
||||
// rotate it 90-degrees counterclockwise
|
||||
vec2 n01 = orientation * vec2(t01.y, -t01.x);
|
||||
vec2 n12 = orientation * vec2(t12.y, -t12.x);
|
||||
vec2 n01 = vec2(t01.y, -t01.x);
|
||||
vec2 n12 = vec2(t12.y, -t12.x);
|
||||
|
||||
float c_orient = sign(cross(t01, t12));
|
||||
bool fill_in = (c_orient > 0);
|
||||
|
||||
float aaw = anti_alias_width;
|
||||
vec2 nudge1 = fill_in ? 0.5 * aaw * (n01 + n12) : vec2(0);
|
||||
@ -113,29 +73,19 @@ void emit_pentagon(vec2 bp0, vec2 bp1, vec2 bp2, float orientation){
|
||||
if(!fill_in) coords_index_map = int[5](1, 0, 2, 4, 3);
|
||||
|
||||
mat3 xy_to_uv = get_xy_to_uv(bp0, bp1);
|
||||
mat3 xy_to_wz = get_xy_to_wz(bp0, bp1, bp2);
|
||||
uv_b2 = (xy_to_uv * vec3(bp2, 1)).xy;
|
||||
uv_anti_alias_width = anti_alias_width / length(bp1 - bp0);
|
||||
|
||||
int nearest_bp_index_map[5] = int[5](0, 0, 1, 2, 2);
|
||||
for(int i = 0; i < 5; i++){
|
||||
vec2 corner = corners[coords_index_map[i]];
|
||||
float z = bp[nearest_bp_index_map[i]].z;
|
||||
uv_coords = (xy_to_uv * vec3(corner, 1)).xy;
|
||||
wz_coords = (xy_to_wz * vec3(corner, 1)).xy;
|
||||
float z;
|
||||
// I haven't a clue why an index map doesn't work just
|
||||
// as well here, but for some reason it doesn't.
|
||||
if(i < 2){
|
||||
color = v_color[0];
|
||||
z = bp[0].z;
|
||||
}
|
||||
else if(i == 2){
|
||||
color = v_color[1];
|
||||
z = bp[1].z;
|
||||
}
|
||||
else{
|
||||
color = v_color[2];
|
||||
z = bp[2].z;
|
||||
}
|
||||
if(i < 2) color = v_color[0];
|
||||
else if(i == 2) color = v_color[1];
|
||||
else color = v_color[2];
|
||||
gl_Position = vec4(
|
||||
scale_and_shift_point_for_frame(vec3(corner, z)),
|
||||
1.0
|
||||
@ -147,17 +97,16 @@ void emit_pentagon(vec2 bp0, vec2 bp1, vec2 bp2, float orientation){
|
||||
|
||||
|
||||
void main(){
|
||||
float fill_all = v_fill_all[0];
|
||||
fill_all = v_fill_all[0];
|
||||
|
||||
if(fill_all == 1){
|
||||
fill_type = FILL_ALL;
|
||||
emit_simple_triangle();
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 new_bp[3];
|
||||
int n = get_reduced_control_points(bp[0].xy, bp[1].xy, bp[2].xy, new_bp);
|
||||
bezier_degree = float(n);
|
||||
float orientation = v_orientation[0];
|
||||
|
||||
vec2 bp0, bp1, bp2;
|
||||
if(n == 0){
|
||||
return; // Don't emit any vertices
|
||||
@ -172,7 +121,6 @@ void main(){
|
||||
bp2 = new_bp[2];
|
||||
}
|
||||
|
||||
emit_pentagon(bp0, bp1, bp2, orientation);
|
||||
}
|
||||
emit_pentagon(bp0, bp1, bp2);
|
||||
}
|
||||
|
||||
|
@ -2,23 +2,16 @@
|
||||
|
||||
in vec3 point;
|
||||
in vec4 color;
|
||||
// fill_all is 0 or 1
|
||||
in float fill_all;
|
||||
// orientation is +1 for counterclockwise curves, -1 otherwise
|
||||
in float orientation;
|
||||
in float fill_all; // Either 0 or 1
|
||||
|
||||
out vec3 bp; // Bezier control point
|
||||
out vec4 v_color;
|
||||
out float v_fill_all;
|
||||
out float v_orientation;
|
||||
|
||||
|
||||
#INSERT rotate_point_for_frame.glsl
|
||||
|
||||
|
||||
void main(){
|
||||
bp = rotate_point_for_frame(point);
|
||||
v_color = color;
|
||||
v_fill_all = fill_all;
|
||||
v_orientation = orientation;
|
||||
}
|
@ -30,25 +30,25 @@ mat3 get_xy_to_uv(vec2 b0, vec2 b1){
|
||||
// might change. The idea is to inform the caller of the degree,
|
||||
// while also passing tangency information in the linear case.
|
||||
int get_reduced_control_points(vec2 b0, vec2 b1, vec2 b2, out vec2 new_points[3]){
|
||||
float epsilon = 1e-6;
|
||||
float length_threshold = 1e-6;
|
||||
float angle_threshold = 1e-3;
|
||||
vec2 v01 = (b1 - b0);
|
||||
vec2 v12 = (b2 - b1);
|
||||
bool distinct_01 = length(v01) > epsilon; // v01 is considered nonzero
|
||||
bool distinct_12 = length(v12) > epsilon; // v12 is considered nonzero
|
||||
// bool aligned = abs(cross(normalize(v01), normalize(v12))) < angle_threshold;
|
||||
bool aligned = acos(dot(normalize(v01), normalize(v12))) < angle_threshold;
|
||||
bool distinct_01 = length(v01) > length_threshold; // v01 is considered nonzero
|
||||
bool distinct_12 = length(v12) > length_threshold; // v12 is considered nonzero
|
||||
int n_uniques = int(distinct_01) + int(distinct_12);
|
||||
if(n_uniques == 2){
|
||||
bool linear = dot(normalize(v01), normalize(v12)) > 1 - epsilon;
|
||||
if(linear){
|
||||
new_points[0] = b0;
|
||||
new_points[1] = b2;
|
||||
return 1;
|
||||
}else{
|
||||
|
||||
bool quadratic = (n_uniques == 2) && !aligned;
|
||||
bool linear = (n_uniques == 1) || ((n_uniques == 2) && aligned);
|
||||
bool constant = (n_uniques == 0);
|
||||
if(quadratic){
|
||||
new_points[0] = b0;
|
||||
new_points[1] = b1;
|
||||
new_points[2] = b2;
|
||||
return 2;
|
||||
}
|
||||
}else if(n_uniques == 1){
|
||||
}else if(linear){
|
||||
new_points[0] = b0;
|
||||
new_points[1] = b2;
|
||||
return 1;
|
||||
|
Reference in New Issue
Block a user