2020-02-03 10:52:39 -08:00
|
|
|
#version 330
|
|
|
|
|
|
|
|
layout (triangles) in;
|
|
|
|
layout (triangle_strip, max_vertices = 5) out;
|
|
|
|
|
2020-06-01 16:21:18 -07:00
|
|
|
// Needed for get_gl_Position
|
2020-06-08 17:55:41 -07:00
|
|
|
uniform vec2 frame_shape;
|
2022-12-28 18:52:05 -08:00
|
|
|
uniform vec2 pixel_shape;
|
2020-06-02 16:18:44 -07:00
|
|
|
uniform float focal_distance;
|
2020-06-08 20:27:07 -07:00
|
|
|
uniform float is_fixed_in_frame;
|
2021-01-04 13:26:14 -08:00
|
|
|
|
2020-02-03 10:52:39 -08:00
|
|
|
uniform float anti_alias_width;
|
2021-01-08 22:28:34 -08:00
|
|
|
uniform float flat_stroke;
|
2023-01-09 12:02:50 -08:00
|
|
|
uniform mat3 camera_rotation;
|
2021-01-04 13:26:14 -08:00
|
|
|
|
|
|
|
//Needed for lighting
|
2020-06-06 09:26:18 -07:00
|
|
|
uniform vec3 light_source_position;
|
2021-11-08 21:43:57 -08:00
|
|
|
uniform vec3 camera_position;
|
2020-06-08 16:03:08 -07:00
|
|
|
uniform float joint_type;
|
2021-11-08 21:43:57 -08:00
|
|
|
uniform float reflectiveness;
|
2020-06-28 12:13:25 -07:00
|
|
|
uniform float gloss;
|
|
|
|
uniform float shadow;
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2023-01-08 21:53:43 -05:00
|
|
|
in vec3 verts[3];
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2023-01-08 20:29:31 -05:00
|
|
|
in float v_joint_angle[3];
|
2020-02-03 10:52:39 -08:00
|
|
|
in float v_stroke_width[3];
|
2023-01-08 20:29:31 -05:00
|
|
|
in vec4 v_color[3];
|
2020-02-03 10:52:39 -08:00
|
|
|
|
|
|
|
out vec4 color;
|
|
|
|
out float uv_stroke_width;
|
|
|
|
out float uv_anti_alias_width;
|
|
|
|
|
2023-01-10 08:54:02 -08:00
|
|
|
out float is_linear;
|
2020-02-03 10:52:39 -08:00
|
|
|
|
|
|
|
out vec2 uv_coords;
|
|
|
|
|
|
|
|
// Codes for joint types
|
2023-01-10 11:06:41 -08:00
|
|
|
const int NO_JOINT = 0;
|
|
|
|
const int AUTO_JOINT = 1;
|
|
|
|
const int BEVEL_JOINT = 2;
|
|
|
|
const int MITER_JOINT = 3;
|
2023-01-09 10:52:12 -08:00
|
|
|
|
2021-01-08 22:28:34 -08:00
|
|
|
const float PI = 3.141592653;
|
2023-01-08 20:29:31 -05:00
|
|
|
const float DISJOINT_CONST = 404.0;
|
2023-01-09 10:52:12 -08:00
|
|
|
const float ANGLE_THRESHOLD = 1e-3;
|
2020-02-03 10:52:39 -08:00
|
|
|
|
|
|
|
|
2023-01-10 09:53:17 -08:00
|
|
|
#INSERT get_xy_to_uv.glsl
|
2020-06-01 16:21:18 -07:00
|
|
|
#INSERT get_gl_Position.glsl
|
2020-06-02 16:18:44 -07:00
|
|
|
#INSERT get_unit_normal.glsl
|
2021-01-09 22:11:38 -08:00
|
|
|
#INSERT finalize_color.glsl
|
2023-01-10 15:17:08 -08:00
|
|
|
#INSERT rotate.glsl
|
|
|
|
|
|
|
|
|
|
|
|
float angle_between(vec2 v1, vec2 v2){
|
|
|
|
float abs_angle = acos(clamp(dot(normalize(v1), normalize(v2)), -1.0, 1.0));
|
|
|
|
float sgn = sign(cross2d(v1, v2));
|
|
|
|
return sgn * abs_angle;
|
|
|
|
}
|
2020-02-03 10:52:39 -08:00
|
|
|
|
|
|
|
|
2021-01-08 22:28:34 -08:00
|
|
|
void create_joint(float angle, vec2 unit_tan, float buff,
|
|
|
|
vec2 static_c0, out vec2 changing_c0,
|
|
|
|
vec2 static_c1, out vec2 changing_c1){
|
2020-02-03 10:52:39 -08:00
|
|
|
float shift;
|
2023-01-10 15:17:08 -08:00
|
|
|
if(abs(angle) < ANGLE_THRESHOLD || abs(angle) > 0.99 * PI || int(joint_type) == NO_JOINT){
|
2020-02-03 10:52:39 -08:00
|
|
|
// No joint
|
|
|
|
shift = 0;
|
2023-01-10 15:17:08 -08:00
|
|
|
// }else if(int(joint_type) == MITER_JOINT || (int(joint_type) == AUTO_JOINT && abs(angle) > 0.95 * PI)){
|
|
|
|
}else if(int(joint_type) == MITER_JOINT){
|
2020-02-03 10:52:39 -08:00
|
|
|
shift = buff * (-1.0 - cos(angle)) / sin(angle);
|
|
|
|
}else{
|
|
|
|
// For a Bevel joint
|
|
|
|
shift = buff * (1.0 - cos(angle)) / sin(angle);
|
|
|
|
}
|
|
|
|
changing_c0 = static_c0 - shift * unit_tan;
|
|
|
|
changing_c1 = static_c1 + shift * unit_tan;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// This function is responsible for finding the corners of
|
|
|
|
// a bounding region around the bezier curve, which can be
|
|
|
|
// emitted as a triangle fan
|
2023-01-08 23:33:39 -05:00
|
|
|
int get_corners(
|
|
|
|
vec2 controls[3],
|
|
|
|
float stroke_widths[3],
|
2023-01-10 12:26:16 -08:00
|
|
|
float aaw, // Anti-alias width
|
2023-01-08 23:33:39 -05:00
|
|
|
float angle_from_prev,
|
|
|
|
float angle_to_next,
|
|
|
|
out vec2 corners[5]
|
|
|
|
){
|
2021-01-08 22:28:34 -08:00
|
|
|
vec2 p0 = controls[0];
|
|
|
|
vec2 p1 = controls[1];
|
|
|
|
vec2 p2 = controls[2];
|
2020-06-02 16:18:44 -07:00
|
|
|
|
2020-06-04 11:29:36 -07:00
|
|
|
// Unit vectors for directions between control points
|
2023-01-10 12:59:10 -08:00
|
|
|
vec2 v01 = normalize(p1 - p0);
|
2021-01-08 22:28:34 -08:00
|
|
|
vec2 v12 = normalize(p2 - p1);
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2023-01-10 12:26:16 -08:00
|
|
|
float cross_prod = cross2d(v01, v12);
|
|
|
|
float sgn = (cross_prod >= 0.0 || bool(is_linear)) ? 1.0 : -1.0;
|
|
|
|
vec2 p0_perp = sgn * vec2(-v01.y, v01.x); // Pointing to the inside of the curve from p0
|
|
|
|
vec2 p2_perp = sgn * vec2(-v12.y, v12.x); // Pointing to the inside of the curve from p2
|
2020-06-02 16:18:44 -07:00
|
|
|
|
2023-01-10 15:17:08 -08:00
|
|
|
// This is to prevent weird bevel artifacts for sharp angles
|
|
|
|
if(abs(angle_from_prev) > 0.5 * PI){
|
|
|
|
stroke_widths[0] *= sin(angle_from_prev);
|
|
|
|
stroke_widths[1] = 0.5 * (stroke_widths[0] + stroke_widths[2]);
|
|
|
|
}
|
|
|
|
if(abs(angle_to_next) > 0.5 * PI){
|
|
|
|
stroke_widths[2] *= sin(angle_to_next);
|
|
|
|
stroke_widths[1] = 0.5 * (stroke_widths[0] + stroke_widths[2]);
|
|
|
|
}
|
|
|
|
|
2021-01-08 22:28:34 -08:00
|
|
|
float buff0 = 0.5 * stroke_widths[0] + aaw;
|
|
|
|
float buff2 = 0.5 * stroke_widths[2] + aaw;
|
2020-06-02 16:18:44 -07:00
|
|
|
|
2023-01-09 16:46:38 -08:00
|
|
|
vec2 c0 = p0 - buff0 * p0_perp;
|
|
|
|
vec2 c1 = p0 + buff0 * p0_perp;
|
|
|
|
vec2 c2 = p2 + buff2 * p2_perp;
|
|
|
|
vec2 c3 = p2 - buff2 * p2_perp;
|
2020-02-03 10:52:39 -08:00
|
|
|
|
|
|
|
// Account for previous and next control points
|
2023-01-09 16:46:38 -08:00
|
|
|
create_joint(angle_from_prev, v01, buff0, c0, c0, c1, c1);
|
2023-01-10 12:59:10 -08:00
|
|
|
create_joint(angle_to_next, -v12, buff2, c3, c3, c2, c2);
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2020-06-01 16:21:18 -07:00
|
|
|
// Linear case is the simplest
|
2023-01-10 08:54:02 -08:00
|
|
|
if(bool(is_linear)){
|
2020-06-06 09:26:18 -07:00
|
|
|
// The order of corners should be for a triangle_strip. Last entry is a dummy
|
2021-01-08 22:28:34 -08:00
|
|
|
corners = vec2[5](c0, c1, c3, c2, vec2(0.0));
|
2020-02-03 10:52:39 -08:00
|
|
|
return 4;
|
|
|
|
}
|
2020-06-04 11:29:36 -07:00
|
|
|
// Otherwise, form a pentagon around the curve
|
2023-01-10 12:26:16 -08:00
|
|
|
corners = vec2[5](c0, c1, p1, c2, c3);
|
|
|
|
corners[2] -= buff0 * p0_perp + buff2 * p2_perp;
|
2020-02-03 10:52:39 -08:00
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void main() {
|
2023-01-08 23:58:45 -05:00
|
|
|
if (distance(verts[0], verts[1]) == 0 && distance(verts[1], verts[2]) == 0) return;
|
|
|
|
|
2023-01-09 12:02:50 -08:00
|
|
|
vec3 unit_normal = camera_rotation * vec3(0.0, 0.0, 1.0); // TODO, track true unit normal globally
|
2021-01-08 22:28:34 -08:00
|
|
|
|
|
|
|
float scaled_strokes[3];
|
|
|
|
for(int i = 0; i < 3; i++){
|
2023-01-10 15:17:08 -08:00
|
|
|
scaled_strokes[i] = v_stroke_width[i];
|
2021-01-08 22:28:34 -08:00
|
|
|
if(bool(flat_stroke)){
|
2023-01-08 21:53:43 -05:00
|
|
|
vec3 to_cam = normalize(vec3(0.0, 0.0, focal_distance) - verts[i]);
|
2023-01-10 15:17:08 -08:00
|
|
|
scaled_strokes[i] *= abs(dot(unit_normal, to_cam));
|
2021-01-08 22:28:34 -08:00
|
|
|
}
|
|
|
|
}
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2023-01-08 23:33:39 -05:00
|
|
|
// Set joint information
|
|
|
|
float angle_from_prev = v_joint_angle[0];
|
|
|
|
float angle_to_next = v_joint_angle[2];
|
|
|
|
if(angle_from_prev == DISJOINT_CONST){
|
2023-01-10 12:26:16 -08:00
|
|
|
// TODO, add anti-aliasing patch to curve start
|
2023-01-08 23:33:39 -05:00
|
|
|
angle_from_prev = 0.0;
|
|
|
|
}
|
|
|
|
if(angle_to_next == DISJOINT_CONST){
|
2023-01-10 12:26:16 -08:00
|
|
|
// TODO, add anti-aliasing patch to curve end
|
2023-01-08 23:33:39 -05:00
|
|
|
angle_to_next = 0.0;
|
|
|
|
}
|
2023-01-10 15:17:08 -08:00
|
|
|
// Recompute angles based on perspective
|
|
|
|
if(angle_from_prev > 0.0 && unit_normal != vec3(0.0, 0.0, 1.0)){
|
|
|
|
vec3 v01 = verts[1] - verts[0];
|
|
|
|
vec3 from_prev = rotate(v01, angle_from_prev, unit_normal);
|
|
|
|
angle_from_prev = angle_between(from_prev.xy, v01.xy);
|
|
|
|
}
|
|
|
|
if(angle_to_next > 0.0 && unit_normal != vec3(0.0, 0.0, 1.0)){
|
|
|
|
vec3 v12 = verts[2] - verts[1];
|
|
|
|
vec3 to_next = rotate(v12, -angle_to_next, unit_normal);
|
|
|
|
angle_to_next = angle_between(v12.xy, to_next.xy);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Control points are projected to the xy plane before drawing, which in turn
|
|
|
|
// gets tranlated to a uv plane. The z-coordinate information will be remembered
|
|
|
|
// by what's sent out to gl_Position, and by how it affects the lighting and stroke width
|
|
|
|
vec2 flat_verts[3] = vec2[3](verts[0].xy, verts[1].xy, verts[2].xy);
|
|
|
|
|
|
|
|
// If the curve is flat, put the middle control in the midpoint
|
|
|
|
is_linear = float(abs(v_joint_angle[1]) < ANGLE_THRESHOLD);
|
|
|
|
if (bool(is_linear)){
|
|
|
|
flat_verts[1] = 0.5 * (flat_verts[0] + flat_verts[2]);
|
|
|
|
}
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2023-01-09 18:51:41 -08:00
|
|
|
// We want to change the coordinates to a space where the curve
|
|
|
|
// coincides with y = x^2, between some values x0 and x2. Or, in
|
|
|
|
// the case of a linear curve (bezier degree 1), just put it on
|
|
|
|
// the segment from (0, 0) to (1, 0)
|
2023-01-10 15:17:08 -08:00
|
|
|
mat3 xy_to_uv = get_xy_to_uv(flat_verts, is_linear, is_linear);
|
2023-01-09 18:51:41 -08:00
|
|
|
|
2023-01-10 12:26:16 -08:00
|
|
|
float uv_scale_factor = length(xy_to_uv[0].xy);
|
2023-01-10 15:17:08 -08:00
|
|
|
float scaled_aaw = anti_alias_width * (frame_shape.y / pixel_shape.y);
|
|
|
|
uv_anti_alias_width = uv_scale_factor * scaled_aaw;
|
2023-01-09 18:51:41 -08:00
|
|
|
|
2020-02-03 10:52:39 -08:00
|
|
|
// Corners of a bounding region around curve
|
2021-01-08 22:28:34 -08:00
|
|
|
vec2 corners[5];
|
2023-01-08 23:33:39 -05:00
|
|
|
int n_corners = get_corners(
|
2023-01-10 15:17:08 -08:00
|
|
|
flat_verts, scaled_strokes, scaled_aaw,
|
|
|
|
angle_from_prev, angle_to_next,
|
2023-01-08 23:33:39 -05:00
|
|
|
corners
|
|
|
|
);
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2020-06-02 16:18:44 -07:00
|
|
|
int index_map[5] = int[5](0, 0, 1, 2, 2);
|
|
|
|
if(n_corners == 4) index_map[2] = 2;
|
2020-02-03 10:52:39 -08:00
|
|
|
|
|
|
|
// Emit each corner
|
|
|
|
for(int i = 0; i < n_corners; i++){
|
2021-01-08 22:28:34 -08:00
|
|
|
uv_coords = (xy_to_uv * vec3(corners[i], 1.0)).xy;
|
2023-01-10 12:26:16 -08:00
|
|
|
uv_stroke_width = uv_scale_factor * scaled_strokes[index_map[i]];
|
2020-06-06 09:26:18 -07:00
|
|
|
// Apply some lighting to the color before sending out.
|
2023-01-08 21:53:43 -05:00
|
|
|
vec3 xyz_coords = vec3(corners[i], verts[index_map[i]].z);
|
2021-01-09 22:11:38 -08:00
|
|
|
color = finalize_color(
|
2020-06-06 09:26:18 -07:00
|
|
|
v_color[index_map[i]],
|
|
|
|
xyz_coords,
|
2022-12-23 10:08:23 -07:00
|
|
|
unit_normal,
|
2020-06-06 09:26:18 -07:00
|
|
|
light_source_position,
|
2021-11-08 21:43:57 -08:00
|
|
|
camera_position,
|
|
|
|
reflectiveness,
|
2020-06-28 12:13:25 -07:00
|
|
|
gloss,
|
|
|
|
shadow
|
2020-06-06 09:26:18 -07:00
|
|
|
);
|
2023-01-10 15:17:08 -08:00
|
|
|
gl_Position = get_gl_Position(vec3(corners[i], verts[index_map[i]].z));
|
2020-02-03 10:52:39 -08:00
|
|
|
EmitVertex();
|
|
|
|
}
|
|
|
|
EndPrimitive();
|
|
|
|
}
|