2020-02-03 10:52:39 -08:00
|
|
|
#version 330
|
|
|
|
|
|
|
|
layout (triangles) in;
|
2023-01-11 21:30:12 -08:00
|
|
|
layout (triangle_strip, max_vertices = 6) out;
|
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-13 22:11:13 -08:00
|
|
|
uniform vec2 pixel_shape;
|
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];
|
2023-01-12 15:56:12 -08:00
|
|
|
in float v_vert_index[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
|
|
|
|
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
|
|
|
|
const float COS_THRESHOLD = 0.999;
|
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
|
|
|
|
2020-06-01 16:21:18 -07:00
|
|
|
#INSERT get_gl_Position.glsl
|
2023-01-18 10:58:25 -08:00
|
|
|
#INSERT get_xyz_to_uv.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){
|
|
|
|
vec3 result;
|
|
|
|
if(joint_product.w < COS_THRESHOLD){
|
|
|
|
result = joint_product.xyz;
|
|
|
|
}else{
|
2023-01-17 11:36:47 -08:00
|
|
|
result = v_joint_product[1].xyz;
|
|
|
|
}
|
2023-01-18 10:04:05 -08:00
|
|
|
float norm = length(result);
|
|
|
|
return (norm > 1e-10) ? result / norm : vec3(0.0, 0.0, 1.0);
|
2023-01-17 11:36:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is responsible for finding the corners of
|
|
|
|
// a bounding region around the bezier curve, which can be
|
2023-01-11 21:30:12 -08:00
|
|
|
// emitted as a triangle fan, with vertices vaguely close
|
|
|
|
// to control points so that the passage of vert data to
|
|
|
|
// frag shaders is most natural.
|
|
|
|
void get_corners(
|
2023-01-12 19:24:42 -08:00
|
|
|
// Control points for a bezier curve
|
|
|
|
vec3 p0,
|
|
|
|
vec3 p1,
|
|
|
|
vec3 p2,
|
|
|
|
// Unit tangent vectors at p0 and p2
|
|
|
|
vec3 v01,
|
|
|
|
vec3 v12,
|
|
|
|
// Anti-alias width
|
|
|
|
float aaw,
|
|
|
|
out vec3 corners[6]
|
2023-01-08 23:33:39 -05:00
|
|
|
){
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2023-01-17 11:36:47 -08:00
|
|
|
float buff0 = 0.5 * v_stroke_width[0] + aaw;
|
|
|
|
float buff2 = 0.5 * v_stroke_width[2] + aaw;
|
2020-06-02 16:18:44 -07:00
|
|
|
|
2023-01-17 11:36:47 -08:00
|
|
|
// Add correction for sharp angles to prevent weird bevel effects
|
2023-01-18 13:07:37 -08:00
|
|
|
if(v_joint_product[0].w < -0.75) buff0 *= 4 * (v_joint_product[0].w + 1.0);
|
|
|
|
if(v_joint_product[2].w < -0.75) buff2 *= 4 * (v_joint_product[2].w + 1.0);
|
2023-01-17 11:36:47 -08:00
|
|
|
|
|
|
|
// Unit normal and joint angles
|
2023-01-18 10:04:05 -08:00
|
|
|
vec3 normal0 = get_joint_unit_normal(v_joint_product[0]);
|
|
|
|
vec3 normal2 = get_joint_unit_normal(v_joint_product[2]);
|
2023-01-18 10:58:25 -08:00
|
|
|
// Set global unit normal
|
|
|
|
unit_normal = normal0;
|
2023-01-17 15:46:09 -08:00
|
|
|
|
2023-01-18 12:52:05 -08:00
|
|
|
// Choose the "outward" normal direction
|
|
|
|
normal0 *= sign(normal0.z);
|
|
|
|
normal2 *= sign(normal2.z);
|
2023-01-12 10:14:14 -08:00
|
|
|
|
2023-01-17 11:36:47 -08:00
|
|
|
vec3 p0_perp;
|
|
|
|
vec3 p2_perp;
|
|
|
|
if(bool(flat_stroke)){
|
2023-01-18 10:04:05 -08:00
|
|
|
// Perpendicular vectors to the left of the curve
|
2023-01-17 11:36:47 -08:00
|
|
|
p0_perp = buff0 * normalize(cross(normal0, v01));
|
|
|
|
p2_perp = buff2 * normalize(cross(normal2, v12));
|
|
|
|
}else{
|
2023-01-18 10:58:25 -08:00
|
|
|
// p0_perp = buff0 * normal0;
|
|
|
|
// p2_perp = buff2 * normal2;
|
|
|
|
p0_perp = buff0 * normalize(cross(camera_position - p0, v01));
|
|
|
|
p2_perp = buff2 * normalize(cross(camera_position - p2, v12));
|
2023-01-17 11:36:47 -08:00
|
|
|
}
|
2023-01-12 19:24:42 -08:00
|
|
|
vec3 p1_perp = 0.5 * (p0_perp + p2_perp);
|
2023-01-12 10:14:14 -08:00
|
|
|
|
2023-01-11 21:30:12 -08:00
|
|
|
// The order of corners should be for a triangle_strip.
|
2023-01-12 19:24:42 -08:00
|
|
|
vec3 c0 = p0 + p0_perp;
|
|
|
|
vec3 c1 = p0 - p0_perp;
|
|
|
|
vec3 c2 = p1 + p1_perp;
|
|
|
|
vec3 c3 = p1 - p1_perp;
|
|
|
|
vec3 c4 = p2 + p2_perp;
|
|
|
|
vec3 c5 = p2 - p2_perp;
|
|
|
|
// Move the inner middle control point to make
|
|
|
|
// room for the curve
|
2023-01-17 13:18:32 -08:00
|
|
|
float orientation = dot(normal0, v_joint_product[1].xyz);
|
|
|
|
if(orientation >= 0.0) c2 = 0.5 * (c0 + c4);
|
2023-01-12 19:24:42 -08:00
|
|
|
else if(orientation < 0.0) c3 = 0.5 * (c1 + c5);
|
2020-02-03 10:52:39 -08:00
|
|
|
|
|
|
|
// Account for previous and next control points
|
2023-01-17 13:18:32 -08:00
|
|
|
if(bool(flat_stroke)){
|
2023-01-18 10:04:05 -08:00
|
|
|
create_joint(v_joint_product[0], v01, buff0, c1, c1, c0, c0);
|
|
|
|
create_joint(v_joint_product[2], -v12, buff2, c5, c5, c4, c4);
|
2023-01-17 13:18:32 -08:00
|
|
|
}
|
2020-02-03 10:52:39 -08:00
|
|
|
|
2023-01-12 19:24:42 -08:00
|
|
|
corners = vec3[6](c0, c1, c2, c3, c4, c5);
|
2020-02-03 10:52:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void main() {
|
2023-01-12 19:24:42 -08:00
|
|
|
// We use the triangle strip primative, but
|
|
|
|
// actually only need every other strip element
|
2023-01-12 15:56:12 -08:00
|
|
|
if (int(v_vert_index[0]) % 2 == 1) return;
|
2023-01-08 23:58:45 -05:00
|
|
|
|
2023-01-12 19:24:42 -08:00
|
|
|
// Curves are marked as eneded when the handle after
|
|
|
|
// the first anchor is set equal to that anchor
|
|
|
|
if (verts[0] == verts[1]) return;
|
2021-01-08 22:28:34 -08:00
|
|
|
|
2023-01-12 19:24:42 -08:00
|
|
|
vec3 p0 = verts[0];
|
|
|
|
vec3 p1 = verts[1];
|
|
|
|
vec3 p2 = verts[2];
|
|
|
|
vec3 v01 = normalize(p1 - p0);
|
|
|
|
vec3 v12 = normalize(p2 - p1);
|
2023-01-10 15:17:08 -08:00
|
|
|
|
2023-01-17 13:16:58 -08:00
|
|
|
float cos_angle = v_joint_product[1].w;
|
|
|
|
is_linear = float(cos_angle > COS_THRESHOLD);
|
2023-01-17 11:36:47 -08:00
|
|
|
|
2023-01-10 15:17:08 -08:00
|
|
|
// If the curve is flat, put the middle control in the midpoint
|
2023-01-12 19:24:42 -08:00
|
|
|
if (bool(is_linear)) p1 = 0.5 * (p0 + p2);
|
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
|
2023-01-18 10:58:25 -08:00
|
|
|
// the x-axis
|
2023-01-17 17:27:20 -08:00
|
|
|
mat4 xyz_to_uv = get_xyz_to_uv(p0, p1, p2, is_linear, is_linear);
|
2023-01-09 18:51:41 -08:00
|
|
|
|
2023-01-17 15:46:09 -08:00
|
|
|
float uv_scale_factor = length(xyz_to_uv[0].xyz);
|
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
|
|
|
|
2023-01-12 19:24:42 -08:00
|
|
|
vec3 corners[6];
|
2023-01-17 11:36:47 -08:00
|
|
|
get_corners(p0, p1, p2, v01, v12, scaled_aaw, corners);
|
2020-02-03 10:52:39 -08:00
|
|
|
|
|
|
|
// Emit each corner
|
2023-01-11 21:30:12 -08:00
|
|
|
for(int i = 0; i < 6; i++){
|
|
|
|
int vert_index = i / 2;
|
2023-01-17 17:27:20 -08:00
|
|
|
uv_coords = (xyz_to_uv * vec4(corners[i], 1)).xy;
|
2023-01-12 19:24:42 -08:00
|
|
|
uv_stroke_width = uv_scale_factor * v_stroke_width[vert_index];
|
2023-01-18 10:58:25 -08:00
|
|
|
color = finalize_color(v_color[vert_index], corners[i], unit_normal);
|
2023-01-18 13:44:41 -08:00
|
|
|
gl_Position = get_gl_Position(corners[i]);
|
2020-02-03 10:52:39 -08:00
|
|
|
EmitVertex();
|
|
|
|
}
|
|
|
|
EndPrimitive();
|
|
|
|
}
|