|
1 | 1 | /*
|
2 | 2 | Part of the Processing project - http://processing.org
|
3 | 3 |
|
4 |
| - Copyright (c) 2012-16 The Processing Foundation |
| 4 | + Copyright (c) 2012-17 The Processing Foundation |
5 | 5 | Copyright (c) 2004-12 Ben Fry and Casey Reas
|
6 | 6 | Copyright (c) 2001-04 Massachusetts Institute of Technology
|
7 | 7 |
|
@@ -35,53 +35,63 @@ attribute vec4 direction;
|
35 | 35 |
|
36 | 36 | varying vec4 vertColor;
|
37 | 37 |
|
38 |
| -vec3 clipToWindow(vec4 clip, vec4 viewport) { |
39 |
| - vec3 post_div = clip.xyz / clip.w; |
40 |
| - vec2 xypos = (post_div.xy + vec2(1.0, 1.0)) * 0.5 * viewport.zw; |
41 |
| - return vec3(xypos, post_div.z * 0.5 + 0.5); |
42 |
| -} |
43 |
| - |
44 |
| -vec4 windowToClipVector(vec2 window, vec4 viewport, float clip_w) { |
45 |
| - vec2 xypos = (window / viewport.zw) * 2.0; |
46 |
| - return vec4(xypos, 0.0, 0.0) * clip_w; |
47 |
| -} |
48 |
| - |
49 | 38 | void main() {
|
50 | 39 | vec4 posp = modelviewMatrix * position;
|
51 |
| - |
| 40 | + vec4 posq = modelviewMatrix * (position + vec4(direction.xyz, 0)); |
| 41 | + |
52 | 42 | // Moving vertices slightly toward the camera
|
53 | 43 | // to avoid depth-fighting with the fill triangles.
|
54 | 44 | // Discussed here:
|
55 | 45 | // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=252848
|
56 | 46 | posp.xyz = posp.xyz * scale;
|
57 |
| - vec4 clipp = projectionMatrix * posp; |
| 47 | + posq.xyz = posq.xyz * scale; |
| 48 | + |
| 49 | + vec4 p = projectionMatrix * posp; |
| 50 | + vec4 q = projectionMatrix * posq; |
| 51 | + |
| 52 | + // formula to convert from clip space (range -1..1) to screen space (range 0..[width or height]) |
| 53 | + // screen_p = (p.xy/p.w + <1,1>) * 0.5 * viewport.zw |
| 54 | + |
| 55 | + // prevent division by W by transforming the tangent formula (div by 0 causes |
| 56 | + // the line to disappear, see https://github.com/processing/processing/issues/5183) |
| 57 | + // t = screen_q - screen_p |
| 58 | + // |
| 59 | + // tangent is normalized and we don't care which direction it points to (+-) |
| 60 | + // t = +- normalize( screen_q - screen_p ) |
| 61 | + // t = +- normalize( (q.xy/q.w+<1,1>)*0.5*viewport.zw - (p.xy/p.w+<1,1>)*0.5*viewport.zw ) |
| 62 | + // |
| 63 | + // extract common factor, <1,1> - <1,1> cancels out |
| 64 | + // t = +- normalize( (q.xy/q.w - p.xy/p.w) * 0.5 * viewport.zw ) |
| 65 | + // |
| 66 | + // convert to common divisor |
| 67 | + // t = +- normalize( ((q.xy*p.w - p.xy*q.w) / (p.w*q.w)) * 0.5 * viewport.zw ) |
| 68 | + // |
| 69 | + // remove the common scalar divisor/factor, not needed due to normalize and +- |
| 70 | + // (keep viewport - can't remove because it has different components for x and y |
| 71 | + // and corrects for aspect ratio, see https://github.com/processing/processing/issues/5181) |
| 72 | + // t = +- normalize( (q.xy*p.w - p.xy*q.w) * viewport.zw ) |
| 73 | + |
| 74 | + vec2 tangent = normalize((q.xy*p.w - p.xy*q.w) * viewport.zw); |
| 75 | + |
| 76 | + // flip tangent to normal (it's already normalized) |
| 77 | + vec2 normal = vec2(-tangent.y, tangent.x); |
| 78 | + |
58 | 79 | float thickness = direction.w;
|
59 |
| - |
60 |
| - if (thickness != 0.0) { |
61 |
| - vec4 posq = posp + modelviewMatrix * vec4(direction.xyz, 0); |
62 |
| - posq.xyz = posq.xyz * scale; |
63 |
| - vec4 clipq = projectionMatrix * posq; |
64 |
| - |
65 |
| - vec3 window_p = clipToWindow(clipp, viewport); |
66 |
| - vec3 window_q = clipToWindow(clipq, viewport); |
67 |
| - vec3 tangent = window_q - window_p; |
68 |
| - |
69 |
| - vec2 perp = normalize(vec2(-tangent.y, tangent.x)); |
70 |
| - vec2 offset = perp * thickness; |
71 |
| - |
72 |
| - if (0 < perspective) { |
73 |
| - // Perspective correction (lines will look thiner as they move away |
74 |
| - // from the view position). |
75 |
| - gl_Position.xy = clipp.xy + offset.xy; |
76 |
| - gl_Position.zw = clipp.zw; |
77 |
| - } else { |
78 |
| - // No perspective correction. |
79 |
| - vec4 offsetp = windowToClipVector(offset, viewport, clipp.w); |
80 |
| - gl_Position = clipp + offsetp; |
81 |
| - } |
82 |
| - } else { |
83 |
| - gl_Position = clipp; |
84 |
| - } |
85 |
| - |
| 80 | + vec2 offset = normal * thickness; |
| 81 | + |
| 82 | + // Perspective --- |
| 83 | + // convert from world to clip by multiplying with projection scaling factor |
| 84 | + // to get the right thickness (see https://github.com/processing/processing/issues/5182) |
| 85 | + // invert Y, projections in Processing invert Y |
| 86 | + vec2 perspScale = (projectionMatrix * vec4(1, -1, 0, 0)).xy; |
| 87 | + |
| 88 | + // No Perspective --- |
| 89 | + // multiply by W (to cancel out division by W later in the pipeline) and |
| 90 | + // convert from screen to clip (derived from clip to screen above) |
| 91 | + vec2 noPerspScale = p.w / (0.5 * viewport.zw); |
| 92 | + |
| 93 | + gl_Position.xy = p.xy + offset.xy * mix(noPerspScale, perspScale, float(perspective > 0)); |
| 94 | + gl_Position.zw = p.zw; |
| 95 | + |
86 | 96 | vertColor = color;
|
87 | 97 | }
|
0 commit comments