foo
[erebus2020] / liberebus / src / surf.c
index 7d8d38a..8f2d4db 100644 (file)
@@ -9,14 +9,17 @@ struct box_data {
 };
 
 static int null_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
+static void null_hitgeom(struct erb_surf *surf, struct erb_hit *hit);
 static void null_sample(struct erb_surf *surf, cgm_vec3 *pos);
 static void null_bbox(struct erb_surf *surf, struct erb_aabb *bb);
 
 static int sph_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
+static void sph_hitgeom(struct erb_surf *surf, struct erb_hit *hit);
 static void sph_sample(struct erb_surf *surf, cgm_vec3 *pos);
 static void sph_bbox(struct erb_surf *surf, struct erb_aabb *bb);
 
 static int box_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
+static void box_hitgeom(struct erb_surf *surf, struct erb_hit *hit);
 static void box_sample(struct erb_surf *surf, cgm_vec3 *pos);
 static void box_bbox(struct erb_surf *surf, struct erb_aabb *bb);
 
@@ -30,6 +33,7 @@ struct erb_surf *erb_surface(int datasz)
                return 0;
        }
        surf->isect = null_isect;
+       surf->hitgeom = null_hitgeom;
        surf->sample = null_sample;
        surf->calc_bbox = null_bbox;
        return surf;
@@ -52,6 +56,7 @@ struct erb_surf *erb_surf_sphere(float rad)
                return 0;
        }
        surf->isect = sph_isect;
+       surf->hitgeom = sph_hitgeom;
        surf->sample = sph_sample;
        surf->calc_bbox = sph_bbox;
        sdata = (struct sph_data*)surf->data;
@@ -68,6 +73,7 @@ struct erb_surf *erb_surf_box(float xsz, float ysz, float zsz)
                return 0;
        }
        surf->isect = box_isect;
+       surf->hitgeom = box_hitgeom;
        surf->sample = box_sample;
        surf->calc_bbox = box_bbox;
        bdata = (struct box_data*)surf->data;
@@ -81,6 +87,11 @@ static int null_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit
        return 0;
 }
 
+static void null_hitgeom(struct erb_surf *surf, struct erb_hit *hit)
+{
+       fprintf(stderr, "BUG: null_hitgeom called\n");
+}
+
 static void null_sample(struct erb_surf *surf, cgm_vec3 *pos)
 {
        pos->x = pos->y = pos->z = 0;
@@ -94,22 +105,102 @@ static void null_bbox(struct erb_surf *surf, struct erb_aabb *bb)
 
 static int sph_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit)
 {
-       return 0;
+       float a, b, c, d, sqrt_d, q, t, t0, t1;
+       cgm_vec3 org, dir;
+       struct sph_data *sdata = (struct sph_data*)surf->data;
+
+       if(surf->node) {
+               erb_xform_ray(ray, surf->node->inv_xform, &org, &dir);
+       } else {
+               org = ray->o;
+               dir = ray->d;
+       }
+
+       a = cgm_vdot(&dir, &dir);
+       b = 2.0f * cgm_vdot(&org, &dir);
+       c = cgm_vdot(&org, &org) - sdata->rad * sdata->rad;
+
+       d = b * b - 4.0f * a * c;
+       if(d <= 0.0f) return 0;
+
+       sqrt_d = sqrt(d);
+       q = b < 0.0f ? -0.5f * (b - sqrt_d) : -0.5f * (b + sqrt_d);
+
+       t0 = q / a;
+       t1 = c / q;
+       if(t1 < t0) {
+               float ttmp = t0;
+               t0 = t1;
+               t1 = ttmp;
+       }
+
+       if(t0 > ray->tmax || t1 < ray->tmin) {
+               return 0;
+       }
+       t = t0 < ray->tmin ? t1 : t0;
+       if(t > ray->tmax) {
+               return 0;
+       }
+
+       if(hit) {
+               hit->t = t;
+               hit->err = 5e-4f * t;   /* PBR 3.2.6 */
+               hit->surf = surf;
+               hit->pos = ray->o;
+               cgm_vadd_scaled(&hit->pos, &ray->d, t);
+               hit->lpos = org;
+               cgm_vadd_scaled(&hit->lpos, &dir, t);
+               hit->total_dist = ray->total_dist + t;
+       }
+
+       return 1;
+}
+
+static void sph_hitgeom(struct erb_surf *surf, struct erb_hit *hit)
+{
+       float theta, phi;
+
+       hit->norm = hit->lpos;
+       cgm_vnormalize(&hit->norm);
+
+       cgm_uvec_to_sph(&theta, &phi, &hit->norm);
+
+       hit->u = (theta + M_PI) / (2.0 * M_PI);
+       hit->v = phi / M_PI;
+
+       hit->tang.x = hit->norm.z;
+       hit->tang.y = hit->norm.y;
+       hit->tang.z = -hit->norm.x;
+
+       if(surf->node) {
+               cgm_vmul_m3v3(&hit->norm, surf->node->xform);
+               cgm_vmul_m3v3(&hit->tang, surf->node->xform);
+       }
 }
 
 static void sph_sample(struct erb_surf *surf, cgm_vec3 *pos)
 {
+       /* TODO */
 }
 
 static void sph_bbox(struct erb_surf *surf, struct erb_aabb *bb)
 {
+       struct sph_data *sdata = (struct sph_data*)surf->data;
+
+       cgm_vcons(&bb->pos, 0, 0, 0);
+       bb->sz.x = bb->sz.y = bb->sz.z = sdata->rad;
 }
 
+/* TODO boxen */
 static int box_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit)
 {
        return 0;
 }
 
+static void box_hitgeom(struct erb_surf *surf, struct erb_hit *hit)
+{
+}
+
 static void box_sample(struct erb_surf *surf, cgm_vec3 *pos)
 {
 }