2020-02-03 10:52:39 -08:00
|
|
|
#version 330
|
|
|
|
|
|
|
|
layout (triangles) in;
|
2024-08-01 06:32:04 -05:00
|
|
|
layout (triangle_strip, max_vertices = 64) out; // Related to MAX_STEPS below
|
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-18 13:50:09 -08:00
|
|
|
uniform float pixel_size;
|
2020-06-08 16:03:08 -07:00
|
|
|
uniform float joint_type;
|
2024-08-01 06:32:04 -05:00
|
|
|
uniform float frame_scale;
|
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-17 11:36:47 -08:00
|
|
|
in vec4 v_joint_product[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;
|
2024-08-01 07:17:26 -05:00
|
|
|
out float scaled_anti_alias_width;
|
|
|
|
out float scaled_signed_dist_to_curve;
|
2020-02-03 10:52:39 -08:00
|
|
|
|
|
|
|
// 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
|
|
|
|
2023-01-17 13:16:58 -08:00
|
|
|
// When the cosine of the angle between
|
|
|
|
// two vectors is larger than this, we
|
|
|
|
// consider them aligned
|
2024-08-01 06:32:04 -05:00
|
|
|
const float COS_THRESHOLD = 0.99;
|
|
|
|
// Used to determine how many lines to break the curve into
|
2024-08-01 07:41:32 -05:00
|
|
|
const float POLYLINE_FACTOR = 30;
|
2024-08-01 06:32:04 -05:00
|
|
|
const int MAX_STEPS = 32;
|
2024-08-05 09:15:06 -05:00
|
|
|
const float MITER_LIMIT = 3.0;
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2023-01-30 18:43:28 -08:00
|
|
|
#INSERT emit_gl_Position.glsl
|
2021-01-09 22:11:38 -08:00
|
|
|
#INSERT finalize_color.glsl
|
2023-01-10 15:17:08 -08:00
|
|
|
|
|
|
|
|
2023-01-18 10:04:05 -08:00
|
|
|
vec3 get_joint_unit_normal(vec4 joint_product){
|
2023-01-23 15:05:10 -08:00
|
|
|
vec3 result = (joint_product.w < COS_THRESHOLD) ?
|
|
|
|
joint_product.xyz : v_joint_product[1].xyz;
|
2023-01-18 10:04:05 -08:00
|
|
|
float norm = length(result);
|
2023-01-19 20:24:32 -08:00
|
|
|
return (norm > 1e-5) ? result / norm : vec3(0.0, 0.0, 1.0);
|
2023-01-17 11:36:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-27 10:48:06 -08:00
|
|
|
vec4 normalized_joint_product(vec4 joint_product){
|
|
|
|
float norm = length(joint_product);
|
|
|
|
return (norm > 1e-10) ? joint_product / norm : vec4(0.0, 0.0, 0.0, 1.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-08-03 08:12:00 -05:00
|
|
|
vec3 point_on_quadratic(float t, vec3 c0, vec3 c1, vec3 c2){
|
|
|
|
return c0 + c1 * t + c2 * t * t;
|
2024-07-31 16:27:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-08-03 08:12:00 -05:00
|
|
|
vec3 tangent_on_quadratic(float t, vec3 c1, vec3 c2){
|
|
|
|
return c1 + 2 * c2 * t;
|
2024-07-31 16:27:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-08-05 09:15:06 -05:00
|
|
|
vec4 get_joint_product(vec3 v1, vec3 v2){
|
|
|
|
return vec4(cross(v1, v2), dot(v1, v2));
|
|
|
|
}
|
2023-01-17 11:36:47 -08:00
|
|
|
|
2024-08-05 09:15:06 -05:00
|
|
|
|
2024-08-05 13:37:17 -05:00
|
|
|
vec3 project(vec3 vect, vec3 unit_normal){
|
2024-08-05 09:15:06 -05:00
|
|
|
/* Project the vector onto the plane perpendicular to a given unit normal */
|
2024-08-05 13:37:17 -05:00
|
|
|
return vect - dot(vect, unit_normal) * unit_normal;
|
2024-08-05 09:15:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
vec3 inverse_joint_product(vec3 vect, vec4 joint_product){
|
|
|
|
/*
|
|
|
|
If joint_product represents vec4(cross(v1, v2), dot(v1, v2)),
|
|
|
|
then given v1, this function recovers v2
|
|
|
|
*/
|
|
|
|
float dp = joint_product.w;
|
|
|
|
if (abs(dp) > COS_THRESHOLD) return vect;
|
|
|
|
vec3 cp = joint_product.xyz;
|
|
|
|
vec3 perp = cross(cp, vect);
|
|
|
|
float a = dp / dot(vect, vect);
|
|
|
|
float b = length(cp) / length(cross(vect, perp));
|
|
|
|
return a * vect + b * perp;
|
2020-02-03 10:52:39 -08:00
|
|
|
}
|
|
|
|
|
2024-07-31 16:27:37 -04:00
|
|
|
|
2024-08-05 13:37:17 -05:00
|
|
|
vec3 step_to_corner(vec3 point, vec3 unit_tan, vec3 unit_normal, vec4 joint_product, bool inner_joint){
|
2023-01-27 10:48:06 -08:00
|
|
|
/*
|
2024-08-05 09:15:06 -05:00
|
|
|
Step the the left of a curve.
|
|
|
|
First a perpendicular direction is calculated, then it is adjusted
|
|
|
|
so as to make a joint.
|
2023-01-27 10:48:06 -08:00
|
|
|
*/
|
2024-08-05 09:15:06 -05:00
|
|
|
vec3 step = normalize(cross(unit_normal, unit_tan));
|
|
|
|
|
2024-08-05 13:37:17 -05:00
|
|
|
// Check if an adjustment is needed,
|
2024-08-05 09:15:06 -05:00
|
|
|
float cos_angle = joint_product.w;
|
2024-08-05 13:37:17 -05:00
|
|
|
if(inner_joint || int(joint_type) == NO_JOINT || cos_angle > 1 - 1e-5){
|
2024-08-05 09:15:06 -05:00
|
|
|
return step;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust based on the joint
|
|
|
|
float sin_angle = length(joint_product.xyz) * sign(joint_product.z);
|
|
|
|
float shift = (int(joint_type) == MITER_JOINT) ?
|
|
|
|
(cos_angle + 1.0) / sin_angle :
|
|
|
|
(cos_angle - 1.0) / sin_angle;
|
|
|
|
|
|
|
|
vec3 result = step + shift * unit_tan;
|
|
|
|
if (length(result) > MITER_LIMIT){
|
|
|
|
result = MITER_LIMIT * normalize(result);
|
2023-01-27 10:48:06 -08:00
|
|
|
}
|
2024-08-05 13:37:17 -05:00
|
|
|
|
2024-08-05 09:15:06 -05:00
|
|
|
return result;
|
2023-01-27 10:48:06 -08:00
|
|
|
}
|
|
|
|
|
2023-01-12 10:14:14 -08:00
|
|
|
|
2024-07-31 15:51:06 -04:00
|
|
|
void emit_point_with_width(
|
|
|
|
vec3 point,
|
|
|
|
vec3 tangent,
|
|
|
|
vec4 joint_product,
|
|
|
|
float width,
|
2024-08-05 13:37:17 -05:00
|
|
|
vec4 joint_color,
|
|
|
|
bool inner_joint
|
2024-07-31 15:51:06 -04:00
|
|
|
){
|
2024-08-05 09:15:06 -05:00
|
|
|
// Normalize relevant vectors
|
|
|
|
vec3 unit_tan;
|
|
|
|
vec4 unit_jp;
|
|
|
|
vec3 unit_normal;
|
2024-08-05 13:37:17 -05:00
|
|
|
vec3 to_camera = camera_position - point;
|
|
|
|
if(flat_stroke == 1.0){
|
2024-08-05 09:15:06 -05:00
|
|
|
unit_tan = normalize(tangent);
|
|
|
|
unit_jp = normalized_joint_product(joint_product);
|
|
|
|
unit_normal = get_joint_unit_normal(joint_product);
|
|
|
|
}else{
|
2024-08-05 13:37:17 -05:00
|
|
|
unit_normal = normalize(to_camera);
|
2024-08-05 09:15:06 -05:00
|
|
|
unit_tan = normalize(project(tangent, unit_normal));
|
|
|
|
vec3 adj_tan = inverse_joint_product(tangent, joint_product);
|
|
|
|
adj_tan = project(adj_tan, unit_normal);
|
|
|
|
unit_jp = normalized_joint_product(get_joint_product(unit_tan, adj_tan));
|
|
|
|
}
|
2024-08-05 13:37:17 -05:00
|
|
|
// Choose the "outward" normal direction
|
|
|
|
if(to_camera.z * dot(unit_normal, to_camera) < 0) unit_normal *= -1;
|
2024-07-31 15:51:06 -04:00
|
|
|
|
2024-08-05 09:15:06 -05:00
|
|
|
// Figure out the step from the point to the corners of the
|
|
|
|
// triangle strip around the polyline
|
2024-08-05 13:37:17 -05:00
|
|
|
vec3 step = step_to_corner(point, unit_tan, unit_normal, unit_jp, inner_joint);
|
2024-07-31 15:51:06 -04:00
|
|
|
|
2024-08-05 09:15:06 -05:00
|
|
|
// Set styling
|
2024-07-31 15:51:06 -04:00
|
|
|
color = finalize_color(joint_color, point, unit_normal);
|
2024-08-01 07:41:32 -05:00
|
|
|
if (width == 0) scaled_anti_alias_width = -1.0; // Signal to discard in frag
|
|
|
|
else scaled_anti_alias_width = 2.0 * anti_alias_width * pixel_size / width;
|
2024-07-31 15:51:06 -04:00
|
|
|
|
|
|
|
// Emit two corners
|
2024-08-01 07:41:32 -05:00
|
|
|
// The frag shader will receive a value from -1 to 1,
|
|
|
|
// reflecting where in the stroke that point is
|
2024-08-05 09:15:06 -05:00
|
|
|
for (int sign = -1; sign <= 1; sign += 2){
|
|
|
|
scaled_signed_dist_to_curve = sign;
|
|
|
|
emit_gl_Position(point + 0.5 * width * sign * step);
|
|
|
|
EmitVertex();
|
|
|
|
}
|
2020-02-03 10:52:39 -08:00
|
|
|
}
|
|
|
|
|
2024-08-03 08:12:00 -05:00
|
|
|
|
2020-02-03 10:52:39 -08:00
|
|
|
void main() {
|
2023-01-24 13:49:43 -08:00
|
|
|
// Curves are marked as ended when the handle after
|
2023-01-12 19:24:42 -08:00
|
|
|
// the first anchor is set equal to that anchor
|
|
|
|
if (verts[0] == verts[1]) return;
|
2021-01-08 22:28:34 -08:00
|
|
|
|
2024-08-03 08:12:00 -05:00
|
|
|
// Coefficients such that the quadratic bezier is c0 + c1 * t + c2 * t^2
|
|
|
|
vec3 c0 = verts[0];
|
|
|
|
vec3 c1 = 2 * (verts[1] - verts[0]);
|
|
|
|
vec3 c2 = verts[0] - 2 * verts[1] + verts[2];
|
|
|
|
|
|
|
|
// Estimate how many line segment the curve should be divided into
|
|
|
|
// based on the area of the triangle defined by these control points
|
|
|
|
float area = 0.5 * length(v_joint_product[1].xzy);
|
|
|
|
int count = int(round(POLYLINE_FACTOR * sqrt(area) / frame_scale));
|
|
|
|
int n_steps = min(2 + count, MAX_STEPS);
|
|
|
|
|
|
|
|
// Compute points along the curve
|
2024-07-31 15:51:06 -04:00
|
|
|
vec3 points[MAX_STEPS];
|
2024-07-31 16:27:37 -04:00
|
|
|
for (int i = 0; i < MAX_STEPS; i++){
|
2024-07-31 15:51:06 -04:00
|
|
|
if (i >= n_steps) break;
|
2024-08-03 08:12:00 -05:00
|
|
|
float t = float(i) / (n_steps - 1);
|
|
|
|
points[i] = point_on_quadratic(t, c0, c1, c2);
|
2024-07-31 15:51:06 -04:00
|
|
|
}
|
2024-08-01 07:41:32 -05:00
|
|
|
|
|
|
|
// Compute joint products
|
|
|
|
vec4 joint_products[MAX_STEPS];
|
2024-07-31 15:51:06 -04:00
|
|
|
joint_products[0] = v_joint_product[0];
|
|
|
|
joint_products[0].xyz *= -1;
|
|
|
|
joint_products[n_steps - 1] = v_joint_product[2];
|
|
|
|
for (int i = 1; i < MAX_STEPS; i++){
|
|
|
|
if (i >= n_steps - 1) break;
|
|
|
|
vec3 v1 = points[i] - points[i - 1];
|
|
|
|
vec3 v2 = points[i + 1] - points[i];
|
2024-08-05 09:15:06 -05:00
|
|
|
joint_products[i] = get_joint_product(v1, v2);
|
2024-07-31 15:51:06 -04:00
|
|
|
}
|
|
|
|
|
2024-07-31 16:27:37 -04:00
|
|
|
// Emit vertex pairs aroudn subdivided points
|
2024-07-31 15:51:06 -04:00
|
|
|
for (int i = 0; i < MAX_STEPS; i++){
|
|
|
|
if (i >= n_steps) break;
|
2024-08-03 08:12:00 -05:00
|
|
|
float t = float(i) / (n_steps - 1);
|
2024-07-31 15:51:06 -04:00
|
|
|
emit_point_with_width(
|
|
|
|
points[i],
|
2024-08-03 08:12:00 -05:00
|
|
|
tangent_on_quadratic(t, c1, c2),
|
2024-07-31 16:27:37 -04:00
|
|
|
joint_products[i],
|
2024-07-31 15:51:06 -04:00
|
|
|
mix(v_stroke_width[0], v_stroke_width[2], t),
|
2024-08-05 13:37:17 -05:00
|
|
|
mix(v_color[0], v_color[2], t),
|
|
|
|
(i > 0 && i < n_steps - 1) // Is this an inner joint
|
2024-07-31 15:51:06 -04:00
|
|
|
);
|
2020-02-03 10:52:39 -08:00
|
|
|
}
|
|
|
|
EndPrimitive();
|
|
|
|
}
|