2020-02-03 10:52:39 -08:00
|
|
|
#version 330
|
|
|
|
|
|
|
|
layout (triangles) in;
|
2024-07-31 15:51:06 -04:00
|
|
|
layout (triangle_strip, max_vertices = 32) 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;
|
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;
|
|
|
|
out float uv_stroke_width;
|
|
|
|
out float uv_anti_alias_width;
|
2024-07-31 15:51:06 -04:00
|
|
|
out float 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-07-31 15:51:06 -04:00
|
|
|
const float COS_THRESHOLD = 0.999;
|
|
|
|
const int MAX_STEPS = 16;
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2023-01-18 10:58:25 -08:00
|
|
|
vec3 unit_normal = vec3(0.0, 0.0, 1.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-07-31 16:27:37 -04:00
|
|
|
vec3 point_on_curve(float t){
|
|
|
|
return verts[0] + 2 * (verts[1] - verts[0]) * t + (verts[0] - 2 * verts[1] + verts[2]) * t * t;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vec3 tangent_on_curve(float t){
|
|
|
|
return 2 * (verts[1] + -verts[0]) + 2 * (verts[0] - 2 * verts[1] + verts[2]) * t;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void map_to_basic(out float x0, out float x2, out float scale_factor){
|
|
|
|
/* Find the coordinates and scale factor such that the bezier curve
|
|
|
|
defined by verts[] is congruent to a section of the parabola y = x^2
|
|
|
|
between x0 and x2, with scale_factor
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void compute_subdivision(out int n_steps, out float subdivision[MAX_STEPS]){
|
|
|
|
/*
|
|
|
|
Based on https://raphlinus.github.io/graphics/curves/2019/12/23/flatten-quadbez.html
|
|
|
|
*/
|
|
|
|
float x0;
|
|
|
|
float x2;
|
|
|
|
float scale_factor;
|
|
|
|
map_to_basic(x0, x2, scale_factor);
|
|
|
|
|
|
|
|
if (normalized_joint_product(v_joint_product[1]).w > COS_THRESHOLD){
|
|
|
|
// Linear
|
|
|
|
n_steps = 2;
|
|
|
|
}else{
|
|
|
|
n_steps = MAX_STEPS; // TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int i = 0; i < MAX_STEPS; i++){
|
|
|
|
if (i >= n_steps) break;
|
|
|
|
subdivision[i] = float(i) / (n_steps - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-12 19:54:32 -08:00
|
|
|
void create_joint(
|
2023-01-18 10:04:05 -08:00
|
|
|
vec4 joint_product,
|
2023-01-12 19:54:32 -08:00
|
|
|
vec3 unit_tan,
|
|
|
|
float buff,
|
|
|
|
vec3 static_c0,
|
|
|
|
out vec3 changing_c0,
|
|
|
|
vec3 static_c1,
|
|
|
|
out vec3 changing_c1
|
|
|
|
){
|
2023-01-18 10:04:05 -08:00
|
|
|
float cos_angle = joint_product.w;
|
2023-01-18 12:52:05 -08:00
|
|
|
if(abs(cos_angle) > COS_THRESHOLD || int(joint_type) == NO_JOINT){
|
2020-02-03 10:52:39 -08:00
|
|
|
// No joint
|
2023-01-17 11:36:47 -08:00
|
|
|
changing_c0 = static_c0;
|
|
|
|
changing_c1 = static_c1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float shift;
|
2023-01-18 10:04:05 -08:00
|
|
|
float sin_angle = length(joint_product.xyz) * sign(joint_product.z);
|
2023-01-17 11:36:47 -08:00
|
|
|
if(int(joint_type) == MITER_JOINT){
|
|
|
|
shift = buff * (-1.0 - cos_angle) / sin_angle;
|
2020-02-03 10:52:39 -08:00
|
|
|
}else{
|
|
|
|
// For a Bevel joint
|
2023-01-17 11:36:47 -08:00
|
|
|
shift = buff * (1.0 - cos_angle) / sin_angle;
|
2020-02-03 10:52:39 -08:00
|
|
|
}
|
|
|
|
changing_c0 = static_c0 - shift * unit_tan;
|
|
|
|
changing_c1 = static_c1 + shift * unit_tan;
|
|
|
|
}
|
|
|
|
|
2024-07-31 16:27:37 -04:00
|
|
|
|
|
|
|
vec3 get_perp(vec3 point, vec3 tangent, vec4 joint_product){
|
2023-01-27 10:48:06 -08:00
|
|
|
/*
|
|
|
|
Perpendicular vectors to the left of the curve
|
|
|
|
*/
|
|
|
|
// Add correction for sharp angles to prevent weird bevel effects
|
2024-07-31 15:51:06 -04:00
|
|
|
float mult = 1.0;
|
|
|
|
if(joint_product.w < -0.75) mult *= 4 * (joint_product.w + 1.0);
|
2023-01-27 10:48:06 -08:00
|
|
|
vec3 normal = get_joint_unit_normal(joint_product);
|
|
|
|
// Set global unit normal
|
|
|
|
unit_normal = normal;
|
|
|
|
// Choose the "outward" normal direction
|
|
|
|
if(normal.z < 0) normal *= -1;
|
|
|
|
if(bool(flat_stroke)){
|
2024-07-31 15:51:06 -04:00
|
|
|
return mult * normalize(cross(normal, tangent));
|
2023-01-27 10:48:06 -08:00
|
|
|
}else{
|
2024-07-31 15:51:06 -04:00
|
|
|
return mult * normalize(cross(camera_position - point, tangent));
|
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,
|
|
|
|
vec4 joint_color,
|
|
|
|
float aaw
|
|
|
|
){
|
|
|
|
vec3 unit_tan = normalize(tangent);
|
|
|
|
vec4 njp = normalized_joint_product(joint_product);
|
|
|
|
float buff = 0.5 * width + aaw;
|
2024-07-31 16:27:37 -04:00
|
|
|
vec3 perp = buff * get_perp(point, unit_tan, njp);
|
2024-07-31 15:51:06 -04:00
|
|
|
|
|
|
|
vec3 corners[2] = vec3[2](point + perp, point - perp);
|
|
|
|
create_joint(
|
|
|
|
njp, unit_tan, length(perp),
|
|
|
|
corners[0], corners[0],
|
|
|
|
corners[1], corners[1]
|
|
|
|
);
|
|
|
|
|
|
|
|
color = finalize_color(joint_color, point, unit_normal);
|
|
|
|
uv_anti_alias_width = aaw;
|
|
|
|
uv_stroke_width = width;
|
|
|
|
|
|
|
|
// Emit two corners
|
|
|
|
for(int i = 0; i < 2; i++){
|
|
|
|
float sign = i % 2 == 0 ? -1 : 1;
|
|
|
|
signed_dist_to_curve = sign * buff;
|
|
|
|
emit_gl_Position(corners[i]);
|
|
|
|
EmitVertex();
|
2023-01-17 13:18:32 -08: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-07-31 15:51:06 -04:00
|
|
|
// Compute subdivision
|
|
|
|
int n_steps;
|
|
|
|
float subdivision[MAX_STEPS];
|
2024-07-31 16:27:37 -04:00
|
|
|
compute_subdivision(n_steps, subdivision);
|
|
|
|
|
|
|
|
// Compute joint products
|
2024-07-31 15:51:06 -04:00
|
|
|
vec3 points[MAX_STEPS];
|
2024-07-31 16:27:37 -04:00
|
|
|
vec4 joint_products[MAX_STEPS];
|
|
|
|
for (int i = 0; i < MAX_STEPS; i++){
|
2024-07-31 15:51:06 -04:00
|
|
|
if (i >= n_steps) break;
|
|
|
|
points[i] = point_on_curve(subdivision[i]);
|
|
|
|
}
|
|
|
|
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];
|
|
|
|
joint_products[i].xyz = cross(v1, v2);
|
|
|
|
joint_products[i].w = dot(v1, v2);
|
|
|
|
}
|
|
|
|
|
2024-07-31 16:27:37 -04:00
|
|
|
// Emit vertex pairs aroudn subdivided points
|
2023-01-18 13:50:09 -08:00
|
|
|
float scaled_aaw = anti_alias_width * pixel_size;
|
2024-07-31 15:51:06 -04:00
|
|
|
for (int i = 0; i < MAX_STEPS; i++){
|
|
|
|
if (i >= n_steps) break;
|
|
|
|
float t = subdivision[i];
|
|
|
|
emit_point_with_width(
|
|
|
|
points[i],
|
|
|
|
tangent_on_curve(t),
|
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),
|
|
|
|
mix(v_color[0], v_color[2], t),
|
|
|
|
scaled_aaw
|
|
|
|
);
|
2020-02-03 10:52:39 -08:00
|
|
|
}
|
|
|
|
EndPrimitive();
|
|
|
|
}
|