1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
// ----------------------------------------------------------------------------
// Copyright (c) 2014, Nicolas P. Rougier. All Rights Reserved.
// Distributed under the (new) BSD License.
// ----------------------------------------------------------------------------
// Hooks:
// <transform> : vec4 function(position, ...)
//
// ----------------------------------------------------------------------------
#include "misc/viewport-NDC.glsl"
#include "math/point-to-line-distance.glsl"
#include "math/point-to-line-projection.glsl"
// Externs
// ------------------------------------
// extern vec3 p0;
// extern vec3 p1;
// extern vec3 p2;
// extern vec3 p3;
// extern vec2 uv;
// extern vec2 caps;
// extern vec4 color;
// extern float antialias;
// extern float linewidth;
// extern float miter_limit;
// extern vec4 viewport;
// vec4 transform(vec3 position);
// Varyings
// ------------------------------------
varying vec2 v_caps;
varying vec4 v_color;
varying float v_antialias;
varying float v_linewidth;
varying float v_length;
varying vec2 v_texcoord;
varying float v_miter_limit;
varying vec2 v_bevel_distance;
// Main
// ------------------------------------
void main (void)
{
// This function is externally generated
fetch_uniforms();
v_color = color;
v_caps = caps;
v_linewidth = linewidth;
v_antialias = antialias;
v_miter_limit = miter_limit;
// transform prev/curr/next
vec4 p0_ = $transform(vec4(p0, 1));
vec4 p1_ = $transform(vec4(p1, 1));
vec4 p2_ = $transform(vec4(p2, 1));
vec4 p3_ = $transform(vec4(p3, 1));
// prev/curr/next in viewport coordinates
vec2 _p0 = NDC_to_viewport(p0_, viewport.zw);
vec2 _p1 = NDC_to_viewport(p1_, viewport.zw);
vec2 _p2 = NDC_to_viewport(p2_, viewport.zw);
vec2 _p3 = NDC_to_viewport(p3_, viewport.zw);
v_antialias = antialias;
v_linewidth = linewidth;
v_miter_limit = miter_limit;
// Determine the direction of each of the 3 segments (previous, current, next)
vec2 v0 = normalize(_p1 - _p0);
vec2 v1 = normalize(_p2 - _p1);
vec2 v2 = normalize(_p3 - _p2);
// Determine the normal of each of the 3 segments (previous, current, next)
vec2 n0 = vec2(-v0.y, v0.x);
vec2 n1 = vec2(-v1.y, v1.x);
vec2 n2 = vec2(-v2.y, v2.x);
// Determine miter lines by averaging the normals of the 2 segments
vec2 miter_a;
vec2 miter_b;
const float epsilon = 0.1;
// WARN: Here we test if v0 = -v1 relatively to epsilon
if( length(v0+v1) < epsilon ) {
miter_a = n1;
} else {
miter_a = normalize(n0 + n1); // miter at start of current segment
}
// WARN: Here we test if v1 = -v2 relatively to epsilon
if( length(v1+v2) < epsilon ) {
miter_b = n1;
} else {
miter_b = normalize(n1 + n2); // miter at end of current segment
}
// Determine the length of the miter by projecting it onto normal
vec2 p,v;
float d, z;
float w = linewidth/2.0 + 1.5*antialias;
v_length = length(_p2-_p1);
float m = miter_limit*linewidth/2.0;
float length_a = w / dot(miter_a, n1);
float length_b = w / dot(miter_b, n1);
// Angle between prev and current segment (sign only)
float d0 = +1.0;
if( (v0.x*v1.y - v0.y*v1.x) > 0. ) { d0 = -1.0;}
// Angle between current and next segment (sign only)
float d1 = +1.0;
if( (v1.x*v2.y - v1.y*v2.x) > 0. ) { d1 = -1.0; }
// Adjust vertex position
if (uv.x == -1.) {
z = p1_.z / p1_.w;
// Cap at start
if( p0 == p1 ) {
p = _p1 - w*v1 + uv.y* w*n1;
v_texcoord = vec2(-w, uv.y*w);
v_caps.x = v_texcoord.x;
// Regular join
} else {
p = _p1 + uv.y * length_a * miter_a;
v_texcoord = vec2(point_to_line_projection(_p1,_p2,p), uv.y*w);
v_caps.x = 1.0;
}
if( p2 == p3 ) {
v_caps.y = v_texcoord.x;
} else {
v_caps.y = 1.0;
}
v_bevel_distance.x = uv.y*d0*point_to_line_distance(_p1+d0*n0*w, _p1+d0*n1*w, p);
v_bevel_distance.y = -point_to_line_distance(_p2+d1*n1*w, _p2+d1*n2*w, p);
} else {
z = p2_.z / p2_.w;
// Cap at end
if( p2 == p3 ) {
p = _p2 + w*v1 + uv.y*w*n1;
v_texcoord = vec2(v_length+w, uv.y*w);
v_caps.y = v_texcoord.x;
// Regular join
} else {
p = _p2 + uv.y*length_b * miter_b;
v_texcoord = vec2(point_to_line_projection(_p1,_p2,p), uv.y*w);
v_caps.y = 1.0;
}
if( p0 == p1 ) {
v_caps.x = v_texcoord.x;
} else {
v_caps.x = 1.0;
}
v_bevel_distance.x = -point_to_line_distance(_p1+d0*n0*w, _p1+d0*n1*w, p);
v_bevel_distance.y = uv.y*d1*point_to_line_distance(_p2+d1*n1*w, _p2+d1*n2*w, p);
}
gl_Position = viewport_to_NDC(vec3(p,z), viewport.zw);
}
|