quakeforge/libs/video/renderer/glsl/trail.vert
Bill Currie 1a06712405 Handle the singularities on the trail vectors.
They're actually guaranteed for the first and last segments due to the
first and last points being duplicated in the buffer (simplifies design).
This also handles the rare case where a vector appears to go directly into
or out of the screen.

Everything works nicely if only one of n1 or n2 is 0, and for the very rare
case of both n1 and n2 being 0, then a final normal of 0 is reasonable.
2014-01-29 16:37:48 +09:00

79 lines
1.8 KiB
GLSL

attribute vec4 last, current, next;
attribute vec3 barycentric;
attribute float texoff;
uniform mat4 proj, view;
uniform vec2 viewport;
uniform float width;
varying vec2 texcoord;
varying vec3 vBC;
vec4
transform (vec3 coord)
{
return proj * view * vec4 (coord, 1.0);
}
vec2
project (vec4 coord)
{
vec3 device = coord.xyz / coord.w;
vec2 clip = (device * 0.5 + 0.5).xy;
return clip * viewport;
}
vec4
unproject (vec2 screen, float z, float w)
{
vec2 clip = screen / viewport;
vec2 device = clip * 2.0 - 1.0;
return vec4 (device * w, z, w);
}
float
estimateScale (vec3 position, vec2 sPosition)
{
vec4 view_pos = view * vec4 (position, 1.0);
vec4 scale_pos = view_pos - vec4 (normalize (view_pos.xy) * width,
0.0, 0.0);
vec2 screen_scale_pos = project (proj * scale_pos);
return distance (sPosition, screen_scale_pos);
}
void
main (void)
{
vec2 t, n1, n2, n;
vec2 sLast = project (transform (last.xyz));
vec2 sNext = project (transform (next.xyz));
vec4 dCurrent = transform (current.xyz);
vec2 sCurrent = project (dCurrent);
float off = current.w;
texcoord = vec2 (texoff * 0.7, off * 0.5 + 0.5);
vBC = barycentric;
t = sLast - sCurrent;
n1 = vec2 (0.0);
if (dot (t, t) > 0.001)
n1 = normalize (t);
t = sCurrent - sNext;
n2 = vec2 (0.0);
if (dot (t, t) > 0.001)
n2 = normalize (t);
n = vec2 (0.0);
if (n1 != -n2)
n = normalize (n1 + n2);
else if (dot (n1, n1) > 0.001)
n = n1;
else if (dot (n2, n2) > 0.001)
n = n2;
// rotate the normal by 90 degrees and scale by the desired width
vec2 dir = vec2 (n.y, -n.x) * off;
float scale = estimateScale (current.xyz, sCurrent);
vec2 pos = sCurrent + dir * scale;
gl_Position = unproject (pos, dCurrent.z, dCurrent.w);
}