skip to content
==> include/pathtrace/t_intersect.h <==
1/* Template (included once per instantiation after pathtrace/t_math.h; see pathtrace/real.h): the
2 * nearest hit of a ray in (EPS, tmax) against the scene's quads, spheres and triangles (the triangles
3 * behind their bounding sphere). Returns t, and the hit id in *id (0 none, 1 + i quad i, PT_ID_SPH + i
4 * sphere i, PT_ID_TRI + i triangle i). */
5#include "pathtrace/real.h"
6#include "pathtrace/scene.h"
7
8PT_API float PT_FN(intersect)(const uint32_t *sc, const pt_layout *l, pt_v o, pt_v d, float tmax, uint32_t *id_out) {
9    float tmin = PT_K(PT_C_EPS), one = PT_K(PT_C_ONE), zero = PT_K(PT_C_ZERO);
10    float best = tmax;
11    uint32_t id = 0;
12    for (uint32_t i = 0; i < l->nquad; i++) {
13        size_t b = l->quad + PT_QUAD_WORDS * (size_t)i;
14        pt_v n = PT_FN(ldv)(sc, b + 9);
15        float den = PT_FN(dot)(n, d);
16        if (PT_GT(den, PT_NEG(PT_K(PT_C_PAR_EPS))) && PT_LT(den, PT_K(PT_C_PAR_EPS))) continue;
17        pt_v p = PT_FN(ldv)(sc, b);
18        float t = PT_DIV(PT_FN(dot)(n, PT_FN(vsub)(p, o)), den);
19        if (!(PT_GT(t, tmin) && PT_LT(t, best))) continue;
20        pt_v w = PT_FN(vsub)(PT_FN(vadd)(o, PT_FN(vscale)(d, t)), p);
21        float a = PT_MUL(PT_FN(dot)(w, PT_FN(ldv)(sc, b + 3)), PT_FN(ldr)(sc, b + 12));
22        if (PT_LT(a, zero) || PT_GT(a, one)) continue;
23        float c = PT_MUL(PT_FN(dot)(w, PT_FN(ldv)(sc, b + 6)), PT_FN(ldr)(sc, b + 13));
24        if (PT_LT(c, zero) || PT_GT(c, one)) continue;
25        best = t;
26        id = 1 + i;
27    }
28    for (uint32_t i = 0; i < l->nsph; i++) {
29        size_t b = l->sph + PT_SPH_WORDS * (size_t)i;
30        float r = PT_FN(ldr)(sc, b + 3);
31        pt_v oc = PT_FN(vsub)(o, PT_FN(ldv)(sc, b));
32        float bq = PT_FN(dot)(oc, d);
33        float cq = PT_SUB(PT_FN(dot)(oc, oc), PT_MUL(r, r));
34        float disc = PT_SUB(PT_MUL(bq, bq), cq);
35        if (PT_LT(disc, zero)) continue;
36        float s = PT_FN(sqrt)(disc);
37        float t = PT_SUB(PT_NEG(bq), s);
38        if (!PT_GT(t, tmin)) t = PT_SUB(s, bq);
39        if (PT_GT(t, tmin) && PT_LT(t, best)) {
40            best = t;
41            id = PT_ID_SPH + i;
42        }
43    }
44    if (l->ntri > 0) {
45        /* The mesh's bounding sphere first. */
46        float mr = PT_FN(ldr)(sc, PT_H_MESH + 3);
47        pt_v oc = PT_FN(vsub)(o, PT_FN(ldv)(sc, PT_H_MESH));
48        float bq = PT_FN(dot)(oc, d);
49        float cq = PT_SUB(PT_FN(dot)(oc, oc), PT_MUL(mr, mr));
50        float disc = PT_SUB(PT_MUL(bq, bq), cq);
51        int near = !PT_LT(disc, zero);
52        if (near) {
53            float s = PT_FN(sqrt)(disc);
54            near = PT_GT(PT_SUB(s, bq), tmin) && PT_LT(PT_SUB(PT_NEG(bq), s), best);
55        }
56        if (near) {
57            for (uint32_t i = 0; i < l->ntri; i++) {
58                size_t b = l->tri + PT_TRI_WORDS * (size_t)i;
59                pt_v e1 = PT_FN(ldv)(sc, b + 3);
60                pt_v e2 = PT_FN(ldv)(sc, b + 6);
61                pt_v pv = PT_FN(cross)(d, e2);
62                float det = PT_FN(dot)(e1, pv);
63                if (PT_GT(det, PT_NEG(PT_K(PT_C_DET_EPS))) && PT_LT(det, PT_K(PT_C_DET_EPS))) continue;
64                float inv = PT_DIV(one, det);
65                pt_v tv = PT_FN(vsub)(o, PT_FN(ldv)(sc, b));
66                float u = PT_MUL(PT_FN(dot)(tv, pv), inv);
67                if (PT_LT(u, zero) || PT_GT(u, one)) continue;
68                pt_v qv = PT_FN(cross)(tv, e1);
69                float v = PT_MUL(PT_FN(dot)(d, qv), inv);
70                if (PT_LT(v, zero) || PT_GT(PT_ADD(u, v), one)) continue;
71                float t = PT_MUL(PT_FN(dot)(e2, qv), inv);
72                if (PT_GT(t, tmin) && PT_LT(t, best)) {
73                    best = t;
74                    id = PT_ID_TRI + i;
75                }
76            }
77        }
78    }
79    *id_out = id;
80    return best;
81}