@@ -9,19 +9,36 @@ layout(location = 0) out vec4 outColor;
99
1010layout (location = 0 ) in flat uint axis;
1111layout (location = 1 ) in flat float scale;
12+ layout (location = 2 ) in vec3 baseColor;
13+
14+ const float TMax = 1e30f;
1215
1316layout (std140, push_constant) uniform Push {
1417 vec3 origin;
18+ uint axisBits;
1519 };
1620layout (binding = 0 , std140) uniform UboScene {
1721 SceneDesc scene;
1822 };
1923layout (binding = 1 ) uniform texture2D depth;
2024
25+ struct HitResult {
26+ vec3 norm;
27+ float hitT;
28+ int axis;
29+ };
30+
31+ void handleHit(inout HitResult hit, vec3 n, float t, int axis) {
32+ if (t >= hit.hitT)
33+ return ;
34+ hit.norm = n;
35+ hit.hitT = t;
36+ hit.axis = axis;
37+ }
2138
2239float dot2(vec3 v) { return dot (v,v); }
2340
24- vec4 cylIntersect(vec3 ro, vec3 rd, vec3 a, vec3 b, float ra ) {
41+ vec4 cylIntersect(inout HitResult hit, int axis, vec3 ro, vec3 rd, vec3 a, vec3 b, float ra) {
2542 vec3 ba = b - a;
2643 vec3 oc = ro - a;
2744
@@ -39,18 +56,51 @@ vec4 cylIntersect(vec3 ro, vec3 rd, vec3 a, vec3 b, float ra ) {
3956 float t = (- k1- h)/ k2;
4057 // body
4158 float y = baoc + t* bard;
42- if ( y> 0.0 && y< baba )
59+ if ( y> 0.0 && y< baba ) {
60+ handleHit(hit, (oc+ t* rd - ba* y/ baba)/ ra, t, axis);
4361 return vec4 ((oc+ t* rd - ba* y/ baba)/ ra, t);
62+ }
4463
4564 // caps
4665 t = ( ((y< 0.0 ) ? 0.0 : baba) - baoc)/ bard;
47- if (abs (k1+ k2* t) < h)
66+ if (abs (k1+ k2* t) < h) {
67+ handleHit(hit, ba* sign (y)/ sqrt (baba), t, axis);
4868 return vec4 (ba* sign (y)/ sqrt (baba), t);
69+ }
4970
5071 return vec4 (- 1.0 );// no intersection
5172 }
5273
53- vec4 coneIntersect(vec3 ro, vec3 rd, vec3 pa, vec3 pb, float ra, float rb) {
74+ vec4 sphereIntersect(inout HitResult hit, int axis, vec3 ro, vec3 rd, vec3 center, float radius) {
75+ vec3 oc = ro - center;
76+
77+ float b = dot (oc, rd);
78+ float c = dot (oc, oc) - radius * radius;
79+
80+ float h = b* b - c;
81+
82+ if (h < 0.0 )
83+ return vec4 (- 1.0 );
84+
85+ h = sqrt (h);
86+
87+ float t = - b - h;
88+
89+ // Camera is inside sphere: use far intersection.
90+ if (t < 0.0 )
91+ t = - b + h;
92+
93+ if (t < 0.0 )
94+ return vec4 (- 1.0 );
95+
96+ vec3 p = ro + rd * t;
97+ vec3 n = normalize (p - center);
98+
99+ handleHit(hit, n, t, axis);
100+ return vec4 (n, t);
101+ }
102+
103+ bool coneIntersect(inout HitResult hit, int axis, vec3 ro, vec3 rd, vec3 pa, vec3 pb, float ra, float rb) {
54104 vec3 ba = pb - pa;
55105 vec3 oa = ro - pa;
56106 vec3 ob = ro - pb;
@@ -63,13 +113,18 @@ vec4 coneIntersect(vec3 ro, vec3 rd, vec3 pa, vec3 pb, float ra, float rb) {
63113
64114 // caps
65115 if (m1 < 0.0 ) {
66- if (dot2(oa* m2- rd* m1) < (ra* ra* m2* m2)) // delayed division
67- return vec4 (- ba* inversesqrt (m0), - m1/ m2);
116+ if (dot2(oa* m2- rd* m1) < (ra* ra* m2* m2)) {
117+ // delayed division
118+ handleHit(hit, - ba* inversesqrt (m0), - m1/ m2, axis);
119+ return true;
120+ }
68121 }
69122 else if (m9 > 0.0 ) {
70123 float t = - m9/ m2; // NOTE delayed division
71- if (dot2(ob+ rd* t) < (rb* rb))
72- return vec4 (ba* inversesqrt (m0), t);
124+ if (dot2(ob+ rd* t) < (rb* rb)) {
125+ handleHit(hit, ba* inversesqrt (m0), t, axis);
126+ return true;
127+ }
73128 }
74129
75130 // body
@@ -80,25 +135,158 @@ vec4 coneIntersect(vec3 ro, vec3 rd, vec3 pa, vec3 pb, float ra, float rb) {
80135 float k0 = m0* m0* m5 - m1* m1* hy + m0* ra* (rr* m1* 2.0 - m0* ra);
81136 float h = k1* k1 - k2* k0;
82137 if (h < 0.0 )
83- return vec4 ( - 1.0 ) ; // no intersection
138+ return false ; // no intersection
84139 float t = (- k1- sqrt (h))/ k2;
85140 float y = m1 + t* m2;
86141 if (y < 0.0 || y > m0)
87- return vec4 (- 1.0 ); // no intersection
88- return vec4 (normalize (m0* (m0* (oa+ t* rd)+ rr* ba* ra)- ba* hy* y), t);
142+ return false; // no intersection
143+ handleHit(hit, normalize (m0* (m0* (oa+ t* rd)+ rr* ba* ra)- ba* hy* y), t, axis);
144+ return true;
89145 }
90146
91- vec4 arrowIntersect(vec3 ro, vec3 rd) {
147+ void arrowIntersect(inout HitResult hit, int axis, vec3 ro, vec3 rd) {
92148 vec3 off0 = vec3 (0 ), off1 = vec3 (0 ), off2 = vec3 (0 );
93149 off0[axis] = scale* 10 ;
94150 off1[axis] = scale* 160 ;
95151 off2[axis] = scale* 200 ;
96152
97- vec4 body = cylIntersect (ro, rd, origin, origin + off1, 4.0 * scale);
98- vec4 cap = coneIntersect(ro, rd, origin + off1, origin + off2, 10.0 * scale, 0 );
99- if (body.w>= 0 && (body.w< cap.w || cap.w<= 0 ))
100- return body;
101- return cap;
153+ cylIntersect (hit, axis, ro, rd, origin, origin + off1, 4.0 * scale);
154+ coneIntersect(hit, axis, ro, rd, origin + off1, origin + off2, 10.0 * scale, 0 );
155+ }
156+
157+ bool rotationRingIntersect(inout HitResult hit, int axis, vec3 ro, vec3 rd, float rIn, float rOut) {
158+ ro -= origin;
159+ if (axis == 0 ) {
160+ ro = ro.zyx;
161+ rd = rd.zyx;
162+ }
163+ else if (axis == 1 ) {
164+ ro = ro.xzy;
165+ rd = rd.xzy;
166+ }
167+ else {
168+ ro = ro.xyz;
169+ rd = rd.xyz;
170+ }
171+
172+ float po = 1.0 ;
173+ float Ra2 = 0.5 * (rIn + rOut); Ra2*= Ra2;
174+ float ra2 = 0.5 * (rIn - rOut); ra2*= ra2;
175+
176+ float m = dot (ro, ro);
177+ float n = dot (ro, rd);
178+ float k = (m + Ra2 - ra2)/ 2.0 ;
179+ float k3 = n;
180+ float k2 = n* n - Ra2* dot (rd.xy,rd.xy) + k;
181+ float k1 = n* k - Ra2* dot (rd.xy,ro.xy);
182+ float k0 = k* k - Ra2* dot (ro.xy,ro.xy);
183+
184+ if (abs (k3* (k3* k3- k2)+ k1) < 0.01 ) {
185+ po = - 1.0 ;
186+ float tmp= k1; k1= k3; k3= tmp;
187+ k0 = 1.0 / k0;
188+ k1 = k1* k0;
189+ k2 = k2* k0;
190+ k3 = k3* k0;
191+ }
192+
193+ float c2 = k2* 2.0 - 3.0 * k3* k3;
194+ float c1 = k3* (k3* k3- k2)+ k1;
195+ float c0 = k3* (k3* (c2+ 2.0 * k2)- 8.0 * k1)+ 4.0 * k0;
196+ c2 /= 3.0 ;
197+ c1 *= 2.0 ;
198+ c0 /= 3.0 ;
199+ float Q = c2* c2 + c0;
200+ float R = c2* c2* c2 - 3.0 * c2* c0 + c1* c1;
201+ float h = R* R - Q* Q* Q;
202+
203+ if ( h>= 0.0 ) {
204+ h = sqrt (h);
205+ float v = sign (R+ h)* pow (abs (R+ h),1.0 / 3.0 ); // cube root
206+ float u = sign (R- h)* pow (abs (R- h),1.0 / 3.0 ); // cube root
207+ vec2 s = vec2 ( (v+ u)+ 4.0 * c2, (v- u)* sqrt (3.0 ));
208+ float y = sqrt (0.5 * (length (s)+ s.x));
209+ float x = 0.5 * s.y/ y;
210+ float r = 2.0 * c1/ (x* x+ y* y);
211+ float t1 = x - r - k3; t1 = (po< 0.0 )? 2.0 / t1: t1;
212+ float t2 = - x - r - k3; t2 = (po< 0.0 )? 2.0 / t2: t2;
213+ float t = TMax;
214+ if ( t1> 0.0 ) t= t1;
215+ if ( t2> 0.0 ) t= min (t,t2);
216+
217+ vec3 pos = ro + t* rd;
218+ vec3 norm = normalize (pos* (dot (pos,pos)- ra2 - Ra2* vec3 (1.0 ,1.0 ,- 1.0 )));
219+ if (axis== 0 )
220+ norm = norm.zyx;
221+ else if (axis== 1 )
222+ norm = norm.xzy;
223+ handleHit(hit, norm, t, axis);
224+ return true;
225+ }
226+
227+ float sQ = sqrt (Q);
228+ float w = sQ* cos ( acos (- R/ (sQ* Q)) / 3.0 );
229+ float d2 = - (w+ c2);
230+ if ( d2< 0.0 )
231+ return false;
232+ float d1 = sqrt (d2);
233+ float h1 = sqrt (w - 2.0 * c2 + c1/ d1);
234+ float h2 = sqrt (w - 2.0 * c2 - c1/ d1);
235+ float t1 = - d1 - h1 - k3; t1 = (po< 0.0 )? 2.0 / t1: t1;
236+ float t2 = - d1 + h1 - k3; t2 = (po< 0.0 )? 2.0 / t2: t2;
237+ float t3 = d1 - h2 - k3; t3 = (po< 0.0 )? 2.0 / t3: t3;
238+ float t4 = d1 + h2 - k3; t4 = (po< 0.0 )? 2.0 / t4: t4;
239+ float t = TMax;
240+ if ( t1> 0.0 ) t= t1;
241+ if ( t2> 0.0 ) t= min (t,t2);
242+ if ( t3> 0.0 ) t= min (t,t3);
243+ if ( t4> 0.0 ) t= min (t,t4);
244+
245+ vec3 pos = ro + t* rd;
246+ vec3 norm = normalize (pos* (dot (pos,pos)- ra2 - Ra2* vec3 (1.0 ,1.0 ,- 1.0 )));
247+ if (axis== 0 )
248+ norm = norm.zyx;
249+ else if (axis== 1 )
250+ norm = norm.xzy;
251+ handleHit(hit, norm, t, axis);
252+ return true;
253+ }
254+
255+ vec4 gizmoIntersect(vec3 ro, vec3 rd, int axis) {
256+ HitResult hit;
257+ hit.hitT = TMax;
258+ if (axis < 4 ) {
259+ arrowIntersect (hit, 0 , ro, rd);
260+ arrowIntersect (hit, 1 , ro, rd);
261+ arrowIntersect (hit, 2 , ro, rd);
262+ sphereIntersect(hit, 3 , ro, rd, origin, 10.0 * scale);
263+ if (hit.axis!= axis)
264+ return vec4 (- 1 );
265+ return vec4 (hit.norm, hit.hitT);
266+ }
267+
268+ axis -= 4 ;
269+ if (axis < 3 ) {
270+ rotationRingIntersect(hit, 0 , ro, rd, 145.0 * scale, 155.0 * scale);
271+ rotationRingIntersect(hit, 1 , ro, rd, 145.0 * scale, 155.0 * scale);
272+ rotationRingIntersect(hit, 2 , ro, rd, 145.0 * scale, 155.0 * scale);
273+ sphereIntersect(hit, - 1 , ro, rd, origin, 145.0 * scale);
274+
275+ if (hit.axis!= axis)
276+ return vec4 (- 1 );
277+ return vec4 (hit.norm, hit.hitT);
278+ }
279+
280+ return vec4 (- 1 );
281+ }
282+
283+ bool depthTest(vec3 ro, vec3 rd, float t) {
284+ vec3 hitPos = ro + rd * t;
285+ vec4 hitClip = scene.viewProject * vec4 (hitPos, 1.0 );
286+ float hitNdcZ = hitClip.z / hitClip.w;
287+
288+ float d = texelFetch(depth, ivec2 (gl_FragCoord .xy), 0 ).x;
289+ return hitNdcZ > d;
102290 }
103291
104292void main() {
@@ -109,20 +297,17 @@ void main() {
109297 const vec3 camPos = scene.camPos;
110298 const vec3 view = normalize (start - camPos);
111299
112- const vec4 nort = arrowIntersect(camPos, view);
113- if (nort.w> 0 ) {
114- vec3 clr = vec3 (0 );
115- clr[axis] = 1 ;
300+ const vec4 nort = gizmoIntersect(camPos, view, int (axis));
301+ if (nort.w> 0 && nort.w!= TMax) {
302+ vec3 clr = baseColor;
116303 clr *= (max (0.0 , dot (scene.sunDir, nort.xyz))* 0.8 + 0.2 );
117- float d = texelFetch(depth, ivec2 (gl_FragCoord .xy), 0 ).x;
118- float dl = linearDepth(d, scene.clipInfo);
119- if (nort.w > dl) {
304+ if (depthTest(camPos, view, nort.w)) {
120305 ivec2 id = ivec2 (gl_FragCoord .xy)/ 4 ;
121306 clr *= (id.x+ id.y)% 2 == 0 ? 0.1 : 0.9 ;
122307 }
123308 outColor = vec4 (clr,1 );
124309 return ;
125310 }
126-
311+ outColor = vec4 ( 0 , 0 , 0 , 1 );
127312 discard ;
128313 }
0 commit comments