static bool sfc_hit_planar(bool is_triangle, point3_t* A, point3_t* B, point3_t* C, ray3_t* ray, float t0, float t1, hit_record_t* hit) { // Use the notation of Shirley & Marschner, Section 4.4.2. float a = A->x - B->x ; float b = A->y - B->y ; float c = A->z - B->z ; float d = A->x - C->x ; float e = A->y - C->y ; float f = A->z - C->z ; float g = ray->dir.x ; float h = ray->dir.y ; float i = ray->dir.z ; float j = A->x - ray->base.x ; float k = A->y - ray->base.y ; float l = A->z - ray->base.z ; float ei = e*i, hf = h*f, gf = g*f, di = d*i, dh = d*h, eg = e*g ; float ak = a*k, jb = j*b, jc = j*c, al = a*l, bl = b*l, kc = k*c ; float ei_hf = ei-hf, gf_di = gf-di, dh_eg = dh-eg ; float ak_jb = ak-jb, jc_al = jc-al, bl_kc = bl-kc ; float M = a*ei_hf + b*gf_di + c*dh_eg ; float t = -(f*ak_jb + e*jc_al + d*bl_kc)/M ; if (t <= t0 || t > t1) return false ; float beta = (j*ei_hf + k*gf_di + l*dh_eg)/M ; if (is_triangle && (beta < 0 || beta > 1)) return false ; float gamma = (i*ak_jb + h*jc_al + g*bl_kc)/M ; if (!is_triangle || (0 <= gamma && beta+gamma <= 1)) { hit->t = t ; vector3_t b_minus_a, c_minus_a ; pv_subtract(B, A, &b_minus_a) ; pv_subtract(C, A, &c_minus_a) ; cross(&b_minus_a, &c_minus_a, &(hit->normal)) ; normalize(&(hit->normal)) ; multiply(&b_minus_a, beta, &b_minus_a) ; multiply(&c_minus_a, gamma, &c_minus_a) ; pv_add(A, &b_minus_a, &(hit->hit_pt)) ; pv_add(&(hit->hit_pt), &c_minus_a, &(hit->hit_pt)) ; return true ; } else return false ; }
pv_t pv_add_constant (pv_t v, CORE_ADDR k) { /* Rather than thinking of all the cases we can and can't handle, we'll just let pv_add take care of that for us. */ return pv_add (v, pv_constant (k)); }
static bool sfc_hit_sphere(void* data, ray3_t* ray, float t0, float t1, hit_record_t* hit) { sphere_data_t* sdata = (sphere_data_t*)data ; point3_t ctr = sdata->center ; float radius = sdata->radius ; point3_t* e = &ray->base ; vector3_t* d = &ray->dir ; // First see if there is any chance we hit the sphere. We do this // by checking whether any part of the sphere is inside the sphere // of radius t1 from the base of the ray. With even just one sphere // in the scene, I found that this check actually slowed down rendering, // probably because of all the square-root computations that turn // out to give no helpful information (i.e., this test says to // continue checking, but then the sphere isn't hit anyway). // if (t1 < (dist(e, &ctr) - radius)) return false ; vector3_t e_minus_ctr ; pv_subtract(e, &ctr, &e_minus_ctr) ; float e_minus_ctr2 = dot(&e_minus_ctr, &e_minus_ctr) ; float d2 = dot(d, d) ; // Compute the discriminant first. float b = dot(d, &e_minus_ctr) ; float discr = b*b - d2*(e_minus_ctr2 - radius*radius) ; // Compute hit position if discr. is >= 0, and also compute // the surface normal. if (discr < 0) return false ; else { // Hit position. float num = min(-b - sqrt(discr), -b + sqrt(discr)) ; float t = num/d2 ; if (t < t0 || t > t1) return false ; hit->t = t ; vector3_t ray_vec = *d ; multiply(&ray_vec, hit->t, &ray_vec) ; pv_add(e, &ray_vec, &(hit->hit_pt)) ; // Surface normal. pv_subtract(&(hit->hit_pt), &ctr, &(hit->normal)) ; normalize(&(hit->normal)) ; return true ; } }