first pass at bvh construction (SAH), untested
[cyberay] / src / geom.c
1 #include <float.h>
2 #include "geom.h"
3
4 int ray_triangle(cgm_ray *ray, struct triangle *tri, float tmax, struct rayhit *hit)
5 {
6         float t, ndotdir;
7         cgm_vec3 vdir, bc, pos;
8
9         if(fabs(ndotdir = cgm_vdot(&ray->dir, &tri->norm)) <= 1e-6) {
10                 return 0;
11         }
12
13         vdir = tri->v[0].pos;
14         cgm_vsub(&vdir, &ray->origin);
15
16         if((t = cgm_vdot(&tri->norm, &vdir) / ndotdir) <= 1e-6 || t > tmax) {
17                 return 0;
18         }
19
20         cgm_raypos(&pos, ray, t);
21         cgm_bary(&bc, &tri->v[0].pos, &tri->v[1].pos, &tri->v[2].pos, &pos);
22
23         if(bc.x < 0.0f || bc.x > 1.0f) return 0;
24         if(bc.y < 0.0f || bc.y > 1.0f) return 0;
25         if(bc.z < 0.0f || bc.z > 1.0f) return 0;
26
27         if(hit) {
28                 hit->t = t;
29                 hit->ray = *ray;
30                 hit->mtl = tri->mtl;
31
32                 hit->v.pos = pos;
33
34                 hit->v.norm.x = tri->v[0].norm.x * bc.x + tri->v[1].norm.x * bc.y + tri->v[2].norm.x * bc.z;
35                 hit->v.norm.y = tri->v[0].norm.y * bc.x + tri->v[1].norm.y * bc.y + tri->v[2].norm.y * bc.z;
36                 hit->v.norm.z = tri->v[0].norm.z * bc.x + tri->v[1].norm.z * bc.y + tri->v[2].norm.z * bc.z;
37
38                 hit->v.tex.x = tri->v[0].tex.x * bc.x + tri->v[1].tex.x * bc.y + tri->v[2].tex.x * bc.z;
39                 hit->v.tex.y = tri->v[0].tex.y * bc.x + tri->v[1].tex.y * bc.y + tri->v[2].tex.y * bc.z;
40         }
41         return 1;
42 }
43
44 #define SLABCHECK(dim)  \
45         do { \
46                 invdir = 1.0f / ray->dir.dim;   \
47                 t0 = (box->vmin.dim - ray->origin.dim) * invdir;        \
48                 t1 = (box->vmax.dim - ray->origin.dim) * invdir;        \
49                 if(invdir < 0.0f) {     \
50                         tmp = t0;       \
51                         t0 = t1;        \
52                         t1 = tmp;       \
53                 }       \
54                 tmin = t0 > tmin ? t0 : tmin;   \
55                 tmax = t1 < tmax ? t1 : tmax;   \
56                 if(tmax <= tmin) return 0; \
57         } while(0)
58
59 int ray_aabox_any(cgm_ray *ray, struct aabox *box, float tmax)
60 {
61         float invdir, t0, t1, tmp;
62         float tmin = 0.0f;
63
64         SLABCHECK(x);
65         SLABCHECK(y);
66         SLABCHECK(z);
67
68         return 1;
69 }
70
71 void aabox_init(struct aabox *box)
72 {
73         box->vmin.x = box->vmin.y = box->vmin.z = FLT_MAX;
74         box->vmax.x = box->vmax.y = box->vmax.z = -FLT_MAX;
75 }
76
77 void aabox_addface(struct aabox *box, struct triangle *tri)
78 {
79         int i;
80         for(i=0; i<3; i++) {
81                 if(tri->v[i].pos.x < box->vmin.x) box->vmin.x = tri->v[i].pos.x;
82                 if(tri->v[i].pos.x > box->vmax.x) box->vmax.x = tri->v[i].pos.x;
83                 if(tri->v[i].pos.y < box->vmin.y) box->vmin.y = tri->v[i].pos.y;
84                 if(tri->v[i].pos.y > box->vmax.y) box->vmax.y = tri->v[i].pos.y;
85                 if(tri->v[i].pos.z < box->vmin.z) box->vmin.z = tri->v[i].pos.z;
86                 if(tri->v[i].pos.z > box->vmax.z) box->vmax.z = tri->v[i].pos.z;
87         }
88 }
89
90 void aabox_union(struct aabox *res, struct aabox *a, struct aabox *b)
91 {
92         res->vmin.x = a->vmin.x < b->vmin.x ? a->vmin.x : b->vmin.x;
93         res->vmax.x = a->vmax.x > b->vmax.x ? a->vmax.x : b->vmax.x;
94         res->vmin.y = a->vmin.y < b->vmin.y ? a->vmin.y : b->vmin.y;
95         res->vmax.y = a->vmax.y > b->vmax.y ? a->vmax.y : b->vmax.y;
96         res->vmin.z = a->vmin.z < b->vmin.z ? a->vmin.z : b->vmin.z;
97         res->vmax.z = a->vmax.z > b->vmax.z ? a->vmax.z : b->vmax.z;
98 }
99
100 float aabox_surf_area(struct aabox *box)
101 {
102         float dx, dy, dz;
103
104         dx = box->vmax.x - box->vmin.x;
105         dy = box->vmax.y - box->vmin.y;
106         dz = box->vmax.z - box->vmin.z;
107
108         return surf_area(dx, dy, dz);
109 }
110
111 float surf_area(float dx, float dy, float dz)
112 {
113         if(dx <= 0 || dy <= 0 || dz <= 0) {
114                 return 0.0f;
115         }
116         return (dx * dy + dx * dz + dy * dz) * 2.0f;
117 }