yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Yong HeFix type checking on generic extensions. (#5316)c97166aed

master
18.0 KiB708 linesraw
1implementing fcpw;
2__include ray;
3__include math_constants;
4__include interaction;
5__include bounding_volumes;
6
7public interface IPrimitive
8{
9    // returns the bounding box of the primitive
10    BoundingBox getBoundingBox();
11
12    // returns the centroid of the primitive
13    float3 getCentroid();
14
15    // returns the normal of the primitive
16    float3 getNormal();
17
18    // returns the surface area of the primitive
19    float getSurfaceArea();
20
21    // intersects primitive with ray
22    bool intersect(Ray r, bool checkForOcclusion, inout Interaction i);
23
24    // intersects primitive with sphere
25    bool intersect(BoundingSphere s, inout Interaction i);
26
27    // finds closest point on primitive from sphere center
28    bool findClosestPoint(BoundingSphere s, inout Interaction i);
29
30    // samples point on primitive and returns sampling pdf
31    float samplePoint(float2 randNums, out float2 uv, out float3 p, out float3 n);
32
33    // returns the index of the primitive
34    uint getIndex();
35};
36
37public bool intersectLineSegment(float3 pa, float3 pb,
38                                 float3 ro, float3 rd, float rtMax, bool checkForOcclusion,
39                                 inout float3 p, inout float3 n, inout float2 uv, inout float d)
40{
41    float3 u = pa - ro;
42    float3 v = pb - pa;
43
44    // return if line segment and ray are parallel
45    float dv = cross(rd, v)[2];
46    if (abs(dv) <= FLT_EPSILON)
47    {
48        return false;
49    }
50
51    // solve ro + t*rd = pa + s*(pb - pa) for t >= 0 && 0 <= s <= 1
52    // s = (u x rd)/(rd x v)
53    float ud = cross(u, rd)[2];
54    float s = ud / dv;
55
56    if (s >= 0.0 && s <= 1.0)
57    {
58        // t = (u x v)/(rd x v)
59        float t = cross(u, v)[2] / dv;
60
61        if (t >= 0.0 && t <= rtMax)
62        {
63            if (checkForOcclusion)
64            {
65                return true;
66            }
67
68            p = pa + s * v;
69            n = normalize(float3(v[1], -v[0], 0.0));
70            uv = float2(s, 0.0);
71            d = t;
72            return true;
73        }
74    }
75
76    return false;
77}
78
79public float findClosestPointLineSegment(float3 pa, float3 pb, float3 x, out float3 p, out float t)
80{
81    float3 u = pb - pa;
82    float3 v = x - pa;
83
84    float c1 = dot(u, v);
85    if (c1 <= 0.0)
86    {
87        t = 0.0;
88        p = pa;
89        return length(x - p);
90    }
91
92    float c2 = dot(u, u);
93    if (c2 <= c1)
94    {
95        t = 1.0;
96        p = pb;
97        return length(x - p);
98    }
99
100    t = c1 / c2;
101    p = pa + u * t;
102    return length(x - p);
103}
104
105public struct LineSegment : IPrimitive
106{
107    public float3 pa;
108    public float3 pb;
109    public uint index;
110
111    // returns the bounding box of the primitive
112    public BoundingBox getBoundingBox()
113    {
114        float3 epsilon = float3(FLT_EPSILON, FLT_EPSILON, 0.0);
115        return BoundingBox(min(pa, pb) - epsilon, max(pa, pb) + epsilon);
116    }
117
118    // returns the centroid of the primitive
119    public float3 getCentroid()
120    {
121        return 0.5 * (pa + pb);
122    }
123
124    // returns the normal of the primitive
125    public float3 getNormal()
126    {
127        float3 s = pb - pa;
128        float3 n = float3(s.y, -s.x, 0.0);
129
130        return normalize(n);
131    }
132
133    // returns the surface area of the primitive
134    public float getSurfaceArea()
135    {
136        return length(pb - pa);
137    }
138
139    // intersects primitive with ray
140    // NOTE: specialized to 2D (z coordinate == 0)
141    public bool intersect(Ray r, bool checkForOcclusion, inout Interaction i)
142    {
143        bool didIntersect = intersectLineSegment(pa, pb, r.o, r.d, r.tMax, checkForOcclusion, i.p, i.n, i.uv, i.d);
144        if (didIntersect)
145        {
146            i.index = index;
147            return true;
148        }
149
150        return false;
151    }
152
153    // intersects primitive with sphere
154    public bool intersect(BoundingSphere s, inout Interaction i)
155    {
156        float d = findClosestPointLineSegment(pa, pb, s.c, i.p, i.uv[0]);
157        if (d * d <= s.r2)
158        {
159            i.d = getSurfaceArea();
160            i.index = index;
161            return true;
162        }
163
164        return false;
165    }
166
167    // finds closest point on primitive from sphere center
168    public bool findClosestPoint(BoundingSphere s, inout Interaction i)
169    {
170        float d = findClosestPointLineSegment(pa, pb, s.c, i.p, i.uv[0]);
171        if (d * d <= s.r2)
172        {
173            i.uv[1] = 0.0;
174            i.d = d;
175            i.index = index;
176            return true;
177        }
178
179        return false;
180    }
181
182    // samples point on primitive and returns sampling pdf
183    public float samplePoint(float2 randNums, out float2 uv, out float3 p, out float3 n)
184    {
185        float3 s = pb - pa;
186        float area = length(s);
187        float u = randNums[0];
188        uv = float2(u, 0.0);
189        p = pa + u * s;
190        n = float3(s[1], -s[0], 0.0) / area;
191
192        return 1.0 / area;
193    }
194
195    // returns the index of the primitive
196    public uint getIndex()
197    {
198        return index;
199    }
200};
201
202public bool intersectTriangle(float3 pa, float3 pb, float3 pc,
203                              float3 ro, float3 rd, float rtMax, bool checkForOcclusion,
204                              inout float3 p, inout float3 n, inout float2 uv, inout float d)
205{
206    // Möller–Trumbore intersection algorithm
207    float3 v1 = pb - pa;
208    float3 v2 = pc - pa;
209    float3 q = cross(rd, v2);
210    float det = dot(v1, q);
211
212    // ray and triangle are parallel if det is close to 0
213    if (abs(det) <= FLT_EPSILON)
214    {
215        return false;
216    }
217    float invDet = 1.0 / det;
218
219    float3 r = ro - pa;
220    float v = dot(r, q) * invDet;
221    if (v < 0.0 || v > 1.0)
222    {
223        return false;
224    }
225
226    float3 s = cross(r, v1);
227    float w = dot(rd, s) * invDet;
228    if (w < 0.0 || v + w > 1.0)
229    {
230        return false;
231    }
232
233    float t = dot(v2, s) * invDet;
234    if (t >= 0.0 && t <= rtMax)
235    {
236        if (checkForOcclusion)
237        {
238            return true;
239        }
240
241        p = pa + v1 * v + v2 * w;
242        n = normalize(cross(v1, v2));
243        uv = float2(1.0 - v - w, v);
244        d = t;
245        return true;
246    }
247
248    return false;
249}
250
251public float findClosestPointTriangle(float3 pa, float3 pb, float3 pc, float3 x, out float3 p, out float2 t)
252{
253    // source: real time collision detection
254    // check if x in vertex region outside pa
255    float3 ab = pb - pa;
256    float3 ac = pc - pa;
257    float3 ax = x - pa;
258    float d1 = dot(ab, ax);
259    float d2 = dot(ac, ax);
260    if (d1 <= 0.0 && d2 <= 0.0)
261    {
262        // barycentric coordinates (1, 0, 0)
263        t = float2(1.0, 0.0);
264        p = pa;
265        return length(x - p);
266    }
267
268    // check if x in vertex region outside pb
269    float3 bx = x - pb;
270    float d3 = dot(ab, bx);
271    float d4 = dot(ac, bx);
272    if (d3 >= 0.0 && d4 <= d3)
273    {
274        // barycentric coordinates (0, 1, 0)
275        t = float2(0.0, 1.0);
276        p = pb;
277        return length(x - p);
278    }
279
280    // check if x in vertex region outside pc
281    float3 cx = x - pc;
282    float d5 = dot(ab, cx);
283    float d6 = dot(ac, cx);
284    if (d6 >= 0.0 && d5 <= d6)
285    {
286        // barycentric coordinates (0, 0, 1)
287        t = float2(0.0, 0.0);
288        p = pc;
289        return length(x - p);
290    }
291
292    // check if x in edge region of ab, if so return projection of x onto ab
293    float vc = d1 * d4 - d3 * d2;
294    if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0)
295    {
296        // barycentric coordinates (1 - v, v, 0)
297        float v = d1 / (d1 - d3);
298        t = float2(1.0 - v, v);
299        p = pa + ab * v;
300        return length(x - p);
301    }
302
303    // check if x in edge region of ac, if so return projection of x onto ac
304    float vb = d5 * d2 - d1 * d6;
305    if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0)
306    {
307        // barycentric coordinates (1 - w, 0, w)
308        float w = d2 / (d2 - d6);
309        t = float2(1.0 - w, 0.0);
310        p = pa + ac * w;
311        return length(x - p);
312    }
313
314    // check if x in edge region of bc, if so return projection of x onto bc
315    float va = d3 * d6 - d5 * d4;
316    if (va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0)
317    {
318        // barycentric coordinates (0, 1 - w, w)
319        float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
320        t = float2(0.0, 1.0 - w);
321        p = pb + (pc - pb) * w;
322        return length(x - p);
323    }
324
325    // x inside face region. Compute p through its barycentric coordinates (u, v, w)
326    float denom = 1.0 / (va + vb + vc);
327    float v = vb * denom;
328    float w = vc * denom;
329    t = float2(1.0 - v - w, v);
330    p = pa + ab * v + ac * w; //= u*a + v*b + w*c, u = va*denom = 1.0f - v - w
331    return length(x - p);
332}
333
334public struct Triangle : IPrimitive
335{
336    public float3 pa;
337    public float3 pb;
338    public float3 pc;
339    public uint index;
340
341    // returns the bounding box of the primitive
342    public BoundingBox getBoundingBox()
343    {
344        float3 epsilon = float3(FLT_EPSILON, FLT_EPSILON, FLT_EPSILON);
345        return BoundingBox(min(min(pa, pb), pc) - epsilon, max(max(pa, pb), pc) + epsilon);
346    }
347
348    // returns the centroid of the primitive
349    public float3 getCentroid()
350    {
351        return (pa + pb + pc) / 3.0;
352    }
353
354    // returns the surface area of the primitive
355    public float getSurfaceArea()
356    {
357        return 0.5 * length(cross(pb - pa, pc - pa));
358    }
359
360    // returns the normal of the primitive
361    public float3 getNormal()
362    {
363        float3 n = cross(pb - pa, pc - pa);
364
365        return normalize(n);
366    }
367
368    // intersects primitive with ray
369    public bool intersect(Ray r, bool checkForOcclusion, inout Interaction i)
370    {
371        bool didIntersect = intersectTriangle(pa, pb, pc, r.o, r.d, r.tMax, checkForOcclusion, i.p, i.n, i.uv, i.d);
372        if (didIntersect)
373        {
374            i.index = index;
375            return true;
376        }
377
378        return false;
379    }
380
381    // intersects primitive with sphere
382    public bool intersect(BoundingSphere s, inout Interaction i)
383    {
384        float d = findClosestPointTriangle(pa, pb, pc, s.c, i.p, i.uv);
385        if (d * d <= s.r2)
386        {
387            i.d = getSurfaceArea();
388            i.index = index;
389            return true;
390        }
391
392        return false;
393    }
394
395    // finds closest point on primitive from sphere center
396    public bool findClosestPoint(BoundingSphere s, inout Interaction i)
397    {
398        float d = findClosestPointTriangle(pa, pb, pc, s.c, i.p, i.uv);
399        if (d * d <= s.r2)
400        {
401            i.d = d;
402            i.index = index;
403            return true;
404        }
405
406        return false;
407    }
408
409    // samples point on primitive and returns sampling pdf
410    public float samplePoint(float2 randNums, out float2 uv, out float3 p, out float3 n)
411    {
412        n = cross(pb - pa, pc - pa);
413        float area = length(n);
414        float u1 = sqrt(randNums[0]);
415        float u2 = randNums[1];
416        float u = 1.0 - u1;
417        float v = u2 * u1;
418        float w = 1.0 - u - v;
419        uv = float2(u, v);
420        p = pa * u + pb * v + pc * w;
421        n /= area;
422
423        return 2.0 / area;
424    }
425
426    // returns the index of the primitive
427    public uint getIndex()
428    {
429        return index;
430    }
431};
432
433public interface ISilhouette
434{
435    // returns the centroid of the silhouette
436    float3 getCentroid();
437
438    // returns whether silhouette has two adjacent faces
439    bool hasTwoAdjacentFaces();
440
441    // returns normal of adjacent face
442    float3 getNormal(uint fIndex);
443
444    // finds closest silhouette point on primitive from sphere center
445    bool findClosestSilhouettePoint(BoundingSphere s, bool flipNormalOrientation,
446                                    float squaredMinRadius, float precision,
447                                    inout Interaction i);
448
449    // returns the index of the silhouette
450    uint getIndex();
451};
452
453public struct NoSilhouette : ISilhouette
454{
455    public uint index;
456
457    // returns the centroid of the silhouette
458    public float3 getCentroid()
459    {
460        return float3(0.0, 0.0, 0.0);
461    }
462
463    // returns whether silhouette has two adjacent faces
464    public bool hasTwoAdjacentFaces()
465    {
466        return false;
467    }
468
469    // returns normal of adjacent face
470    public float3 getNormal(uint fIndex)
471    {
472        return float3(0.0, 0.0, 0.0);
473    }
474
475    // finds closest silhouette point on primitive from sphere center
476    public bool findClosestSilhouettePoint(BoundingSphere s, bool flipNormalOrientation,
477                                           float squaredMinRadius, float precision,
478                                           inout Interaction i)
479    {
480        return false;
481    }
482
483    // returns the index of the silhouette
484    public uint getIndex()
485    {
486        return UINT_MAX;
487    }
488};
489
490public bool isSilhouetteVertex(float3 n0, float3 n1, float3 viewDir, float d, bool flipNormalOrientation, float precision)
491{
492    float sign = flipNormalOrientation ? 1.0 : -1.0;
493
494    // vertex is a silhouette point if it is concave and the query point lies on the vertex
495    if (d <= precision)
496    {
497        float det = n0.x * n1.y - n1.x * n0.y;
498        return sign * det > precision;
499    }
500
501    // vertex is a silhouette point if the query point lies on the halfplane
502    // defined by an adjacent line segment and the other segment is backfacing
503    float3 viewDirUnit = viewDir / d;
504    float dot0 = dot(viewDirUnit, n0);
505    float dot1 = dot(viewDirUnit, n1);
506
507    bool isZeroDot0 = abs(dot0) <= precision;
508    if (isZeroDot0)
509    {
510        return sign * dot1 > precision;
511    }
512
513    bool isZeroDot1 = abs(dot1) <= precision;
514    if (isZeroDot1)
515    {
516        return sign * dot0 > precision;
517    }
518
519    // vertex is a silhouette point if an adjacent line segment is frontfacing
520    // w.r.t. the query point and the other segment is backfacing
521    return dot0 * dot1 < 0.0;
522}
523
524public struct Vertex : ISilhouette
525{
526    public float3 p;
527    public float3 n0;
528    public float3 n1;
529    public uint index;
530    public uint hasOneAdjacentFace;
531
532    // returns the centroid of the silhouette
533    public float3 getCentroid()
534    {
535        return p;
536    }
537
538    // returns whether silhouette has two adjacent faces
539    public bool hasTwoAdjacentFaces()
540    {
541        return hasOneAdjacentFace == 0;
542    }
543
544    // returns normal of adjacent face
545    public float3 getNormal(uint fIndex)
546    {
547        if (fIndex == 0)
548        {
549            return n0;
550        }
551
552        return n1;
553    }
554
555    // finds closest silhouette point on primitive from sphere center
556    public bool findClosestSilhouettePoint(BoundingSphere s, bool flipNormalOrientation,
557                                           float squaredMinRadius, float precision,
558                                           inout Interaction i)
559    {
560        if (squaredMinRadius >= s.r2)
561        {
562            return false;
563        }
564
565        // compute view direction
566        float3 viewDir = s.c - p;
567        float d = length(viewDir);
568        if (d * d > s.r2)
569        {
570            return false;
571        }
572
573        // check if vertex is a silhouette point from view direction
574        bool process = hasOneAdjacentFace == 1 ? true : false;
575        if (!process)
576        {
577            process = isSilhouetteVertex(n0, n1, viewDir, d, flipNormalOrientation, precision);
578        }
579
580        if (process && d * d <= s.r2)
581        {
582            i.p = p;
583            i.uv = float2(0.0, 0.0);
584            i.d = d;
585            i.index = index;
586            return true;
587        }
588
589        return false;
590    }
591
592    // returns the index of the silhouette
593    public uint getIndex()
594    {
595        return index;
596    }
597};
598
599public bool isSilhouetteEdge(float3 pa, float3 pb, float3 n0, float3 n1, float3 viewDir,
600                             float d, bool flipNormalOrientation, float precision)
601{
602    float sign = flipNormalOrientation ? 1.0 : -1.0;
603
604    // edge is a silhouette if it is concave and the query point lies on the edge
605    if (d <= precision)
606    {
607        float3 edgeDir = normalize(pb - pa);
608        float signedDihedralAngle = atan2(dot(edgeDir, cross(n0, n1)), dot(n0, n1));
609        return sign * signedDihedralAngle > precision;
610    }
611
612    // edge is a silhouette if the query point lies on the halfplane defined
613    // by an adjacent triangle and the other triangle is backfacing
614    float3 viewDirUnit = viewDir / d;
615    float dot0 = dot(viewDirUnit, n0);
616    float dot1 = dot(viewDirUnit, n1);
617
618    bool isZeroDot0 = abs(dot0) <= precision;
619    if (isZeroDot0)
620    {
621        return sign * dot1 > precision;
622    }
623
624    bool isZeroDot1 = abs(dot1) <= precision;
625    if (isZeroDot1)
626    {
627        return sign * dot0 > precision;
628    }
629
630    // edge is a silhouette if an adjacent triangle is frontfacing w.r.t. the
631    // query point and the other triangle is backfacing
632    return dot0 * dot1 < 0.0;
633}
634
635public struct Edge : ISilhouette
636{
637    public float3 pa;
638    public float3 pb;
639    public float3 n0;
640    public float3 n1;
641    public uint index;
642    public uint hasOneAdjacentFace;
643
644    // returns the centroid of the silhouette
645    public float3 getCentroid()
646    {
647        return 0.5 * (pa + pb);
648    }
649
650    // returns whether silhouette has two adjacent faces
651    public bool hasTwoAdjacentFaces()
652    {
653        return hasOneAdjacentFace == 0;
654    }
655
656    // returns normal of adjacent face
657    public float3 getNormal(uint fIndex)
658    {
659        if (fIndex == 0)
660        {
661            return n0;
662        }
663
664        return n1;
665    }
666
667    // finds closest silhouette point on primitive from sphere center
668    public bool findClosestSilhouettePoint(BoundingSphere s, bool flipNormalOrientation,
669                                           float squaredMinRadius, float precision,
670                                           inout Interaction i)
671    {
672        if (squaredMinRadius >= s.r2)
673        {
674            return false;
675        }
676
677        // compute view direction
678        float d = findClosestPointLineSegment(pa, pb, s.c, i.p, i.uv[0]);
679        if (d * d > s.r2)
680        {
681            return false;
682        }
683
684        // check if edge is a silhouette from view direction
685        bool process = hasOneAdjacentFace == 1 ? true : false;
686        if (!process)
687        {
688            float3 viewDir = s.c - i.p;
689            process = isSilhouetteEdge(pa, pb, n0, n1, viewDir, d, flipNormalOrientation, precision);
690        }
691
692        if (process && d * d <= s.r2)
693        {
694            i.uv[1] = 0.0;
695            i.d = d;
696            i.index = index;
697            return true;
698        }
699
700        return false;
701    }
702
703    // returns the index of the silhouette
704    public uint getIndex()
705    {
706        return index;
707    }
708};