-
Notifications
You must be signed in to change notification settings - Fork 1
/
robustwireframe.geom
131 lines (106 loc) · 4.31 KB
/
robustwireframe.geom
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
#version 330 core
// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in WorldSpaceVertex {
vec3 position;
vec3 normal;
} gs_in[];
out WireframeVertex {
vec3 position;
vec3 normal;
noperspective vec4 edgeA;
noperspective vec4 edgeB;
flat int configuration;
} gs_out;
uniform mat4 viewportMatrix;
const int infoA[] = int[](0, 0, 0, 0, 1, 1, 2);
const int infoB[] = int[](1, 1, 2, 0, 2, 1, 2);
const int infoAd[] = int[](2, 2, 1, 1, 0, 0, 0);
const int infoBd[] = int[](2, 2, 1, 2, 0, 2, 1);
vec2 transformToViewport(const in vec4 p)
{
return vec2(viewportMatrix * (p / p.w));
}
void main()
{
gs_out.configuration = int(gl_in[0].gl_Position.z < 0) * int(4)
+ int(gl_in[1].gl_Position.z < 0) * int(2)
+ int(gl_in[2].gl_Position.z < 0);
// If all vertices are behind us, cull the primitive
if (gs_out.configuration == 7)
return;
// Transform each vertex into viewport space
vec2 p[3];
p[0] = transformToViewport(gl_in[0].gl_Position);
p[1] = transformToViewport(gl_in[1].gl_Position);
p[2] = transformToViewport(gl_in[2].gl_Position);
if (gs_out.configuration == 0) {
// Common configuration where all vertices are within the viewport
gs_out.edgeA = vec4(0.0);
gs_out.edgeB = vec4(0.0);
// Calculate lengths of 3 edges of triangle
float a = length(p[1] - p[2]);
float b = length(p[2] - p[0]);
float c = length(p[1] - p[0]);
// Calculate internal angles using the cosine rule
float alpha = acos((b * b + c * c - a * a) / (2.0 * b * c));
float beta = acos((a * a + c * c - b * b) / (2.0 * a * c));
// Calculate the perpendicular distance of each vertex from the opposing edge
float ha = abs(c * sin(beta));
float hb = abs(c * sin(alpha));
float hc = abs(b * sin(alpha));
// Now add this perpendicular distance as a per-vertex property in addition to
// the position and normal calculated in the vertex shader.
// Vertex 0 (a)
gs_out.edgeA = vec4(ha, 0.0, 0.0, 0.0);
gs_out.normal = gs_in[0].normal;
gs_out.position = gs_in[0].position;
gl_Position = gl_in[0].gl_Position;
EmitVertex();
// Vertex 1 (b)
gs_out.edgeA = vec4(0.0, hb, 0.0, 0.0);
gs_out.normal = gs_in[1].normal;
gs_out.position = gs_in[1].position;
gl_Position = gl_in[1].gl_Position;
EmitVertex();
// Vertex 2 (c)
gs_out.edgeA = vec4(0.0, 0.0, hc, 0.0);
gs_out.normal = gs_in[2].normal;
gs_out.position = gs_in[2].position;
gl_Position = gl_in[2].gl_Position;
EmitVertex();
// Finish the primitive off
EndPrimitive();
} else {
// Viewport projection breaks down for one or two vertices.
// Caclulate what we can here and defer rest to fragment shader.
// Since this is coherent for the entire primitive the conditional
// in the fragment shader is still cheap as all concurrent
// fragment shader invocations will take the same code path.
// Copy across the viewport-space points for the (up to) two vertices
// in the viewport
gs_out.edgeA.xy = p[infoA[gs_out.configuration]];
gs_out.edgeB.xy = p[infoB[gs_out.configuration]];
// Copy across the viewport-space edge vectors for the (up to) two vertices
// in the viewport
gs_out.edgeA.zw = normalize(gs_out.edgeA.xy - p[ infoAd[gs_out.configuration] ]);
gs_out.edgeB.zw = normalize(gs_out.edgeB.xy - p[ infoBd[gs_out.configuration] ]);
// Pass through the other vertex attributes
gs_out.normal = gs_in[0].normal;
gs_out.position = gs_in[0].position;
gl_Position = gl_in[0].gl_Position;
EmitVertex();
gs_out.normal = gs_in[1].normal;
gs_out.position = gs_in[1].position;
gl_Position = gl_in[1].gl_Position;
EmitVertex();
gs_out.normal = gs_in[2].normal;
gs_out.position = gs_in[2].position;
gl_Position = gl_in[2].gl_Position;
EmitVertex();
// Finish the primitive off
EndPrimitive();
}
}