Inode *cylin_intersect(Prim *p, Ray ro) { double a, b, c, disc, t0, t1, t2, t3; Inode *i0, *i1; int flag[4] = {FALSE, FALSE, FALSE, FALSE}; Ray r = ray_transform(ro, p->ti); Vector3 Sol0, Sol1, Sol2, Sol3; a = SQR(r.d.x) + SQR(r.d.y); b = 2 * (r.o.x * r.d.x + r.o.y * r.d.y); c = SQR(r.o.x) + SQR(r.o.y) - 1; // Case 0: no solution / infinite solutions if ((disc = SQR(b) - 4 * a * c) <= 0) return (Inode *)0; if ( fabs(a) < RAY_EPS ) { return (Inode *)0; } else { t0 = (-b - sqrt(disc)) / (2 * a); t1 = (-b + sqrt(disc)) / (2 * a); Sol0 = ray_point(r, t0); Sol1 = ray_point(r, t1); if (t1 > RAY_EPS && Sol1.z >= 0 && Sol1.z <= 1){ flag[1] = TRUE; } if (t0 > RAY_EPS && Sol0.z >= 0 && Sol0.z <= 1){ flag[0] = TRUE; } } // Ray NOT parallel to base caps --> Cap intersections if ( fabs(r.d.z) > RAY_EPS ){ t2 = - (r.o.z) / (r.d.z); t3 = (1 - (r.o.z)) / (r.d.z); Sol2 = ray_point(r,t2); Sol3 = ray_point(r,t3); if (t2 > RAY_EPS && (SQR(Sol2.x) + SQR(Sol2.y)) <= 1) flag[2] = TRUE; if (t3 > RAY_EPS && (SQR(Sol3.x) + SQR(Sol3.y)) <= 1) flag[3] = TRUE; } int k = 0, nsols = 0; double t[4] = {t0, t1, t2, t3}; while (k < 4 && nsols < 2){ if (flag[k]){ Vector3 n = v3_unit(cylin_gradient(p, ray_point(ro, t[k]))); if ( nsols == 0 ){ i0 = inode_alloc(t[k], n, TRUE); } else { i1 = inode_alloc(t[k], n, FALSE); i0->next = i1; } nsols++; } k++; } return i0; }
Inode *torus_intersect(Prim *p, Ray ro) { double a, b, c, disc, t0, t1; Inode *i0, *i1; Ray r = ray_transform(ro, p->ti); a = v3_sqrnorm(r.d); b = 2 * v3_dot(r.d, r.o); c = v3_sqrnorm(r.o) - 1; if ((disc = SQR(b) - 4 * a * c) <= 0) return (Inode *)0; t0 = (-b - sqrt(disc)) / (2 * a); t1 = (-b + sqrt(disc)) / (2 * a); if (t1 < RAY_EPS) return (Inode *)0; if (t0 < RAY_EPS) { Vector3 n1 = v3_unit(torus_gradient(p, ray_point(r, t1))); return inode_alloc(t1, n1, FALSE); } else { Vector3 n0 = v3_unit(torus_gradient(p, ray_point(ro, t0))); Vector3 n1 = v3_unit(torus_gradient(p, ray_point(ro, t1))); i0 = inode_alloc(t0, n0, TRUE); i1 = inode_alloc(t1, n1, FALSE); i0->next = i1; return i0; } }
static inline v4su sign_test(v4sf n, struct ray ray, float a) { m34sf p = ray_point(n, ray); v4sf v = curve(p, a); m34sf p0 = ray_point(n + v4sf_set1(-0.0001), ray); m34sf p1 = ray_point(n + v4sf_set1(0.0001), ray); v4sf v0 = curve(p0, a); v4sf v1 = curve(p1, a); return sign_change(v, v0) | sign_change(v, v1); }
static inline v4sf bisect(i4sf l, struct ray ray, float a) { i4sf k = l; m34sf p0 = ray_point(k.min, ray); v4sf v0 = curve(p0, a); for (int i = 0; i < 20; i++) { v4sf x = v4sf_set1(0.5) * (k.min + k.max); m34sf p1 = ray_point(x, ray); v4su test = sign_change(v0, curve(p1, a)); k.min = v4sf_select(test, k.min, x); k.max = v4sf_select(test, x, k.max); } return v4sf_set1(0.5) * (k.min + k.max); }
CollisionResult collision_ray_scene_union(const Ray* ray, const Scene* scene) { const Scene* scene1 = ((ScenePair*)scene->data)->scene1; const Scene* scene2 = ((ScenePair*)scene->data)->scene2; const int max_iterations = 10; CollisionResult r1; { Ray ray2 = *ray; Vec3 p; for (int i = 0; i < max_iterations; ++i) { r1 = collision_ray_scene(&ray2, scene1); if (r1.type == None) { break; } p = ray_point(&ray2, r1.time); if (!scene_is_point_in_solid(scene2, &p)) { break; } Vec3 ro = ray_point(&ray2, r1.time+0.1); ray2 = ray_init(&ro, &ray2.direction); } if (r1.type != None) { Vec3 v = vec3_sub(&p, &ray->origin); r1.time = vec3_dot(&ray->direction, &v); } } CollisionResult r2; { Ray ray2 = *ray; Vec3 p; for (int i = 0; i < max_iterations; ++i) { r2 = collision_ray_scene(&ray2, scene2); if (r2.type == None) { break; } p = ray_point(&ray2, r2.time); if (!scene_is_point_in_solid(scene1, &p)) { break; } Vec3 ro = ray_point(&ray2, r2.time+0.1); ray2 = ray_init(&ro, &ray2.direction); } if (r2.type != None) { Vec3 v = vec3_sub(&p, &ray->origin); r2.time = vec3_dot(&ray->direction, &v); } } if (r1.type == None) { if (r2.type == None) { return (CollisionResult){.type=None}; } else { return r2; } } else {
main(int argc, char **argv) { Prim *o; Color c; int u, v; Ray r; Inode *l; o = sphere_instance(&sphere_funcs); init_sdl(); s = scene_read(); init_render(); for (v = s->view->sc.ll.y; v < s->view->sc.ur.y; v += 1) { for (u = s->view->sc.ll.x; u < s->view->sc.ur.x; u += 1) { r = ray_unit(ray_transform(ray_view(u, v), mclip)); if ((l = ray_intersect(s->objs, r)) != NULL) c = point_tshade(ray_point(r, l->t), l->n, s->view->center, rc, l->m, o); else c = bgcolor; inode_free(l); img_putc(s->img, u, v, col_dpymap(c)); } } img_write(s->img,"stdout",0); exit(0); }
static inline v4su epsilon_test(v4sf n, struct ray ray, float a) { float epsilon = 0.0000000001; m34sf p = ray_point(n, ray); v4sf v = curve(p, a); return v4sf_lt(v4sf_abs(v), v4sf_set1(epsilon)); }
Color ray_shade(int level, Real w, Ray v, RContext *rc, Object *ol) { Inode *i = ray_intersect(ol, v); if (i != NULL) { Light *l; Real wf; Material *m = i->m; Vector3 p = ray_point(v, i->t); Cone recv = cone_make(p, i->n, PIOVER2); Color c = c_mult(m->c, c_scale(m->ka, ambient(rc))); rc->p = p; for (l = rc->l; l != NULL; l = l->next) if ((*l->transport)(l, recv, rc) && (wf = shadow(l, p, ol)) > RAY_WF_MIN) c = c_add(c, c_mult(m->c, c_scale(wf * m->kd * v3_dot(l->outdir,i->n), l->outcol))); if (level++ < MAX_RAY_LEVEL) { if ((wf = w * m->ks) > RAY_WF_MIN) { Ray r = ray_make(p, reflect_dir(v.d, i->n)); c = c_add(c, c_mult(m->s, c_scale(m->ks, ray_shade(level, wf, r, rc, ol)))); } if ((wf = w * m->kt) > RAY_WF_MIN) { Ray t = ray_make(p, refract_dir(v.d, i->n, (i->enter)? 1/m->ir: m->ir)); if (v3_sqrnorm(t.d) > 0) { c = c_add(c, c_mult(m->s, c_scale(m->kt, ray_shade(level, wf, t, rc, ol)))); } } } inode_free(i); return c; } else { return BG_COLOR; } }
static inline v4sf newton(v4sf n, struct ray ray, float a) { for (int i = 0; i < 20; i++) { m34sf p = ray_point(n, ray); n -= curve(p, a) / m34sf_dot(ray.d, gradient(p, a)); } return n; }
static inline v4sf newton_bisect(i4sf l, struct ray ray, float a) { i4sf k = l; m34sf p0 = ray_point(k.min, ray); v4sf v0 = curve(p0, a); for (int i = 0; i < 20; i++) { v4sf x = v4sf_set1(0.5) * (k.min + k.max); m34sf p1 = ray_point(x, ray); v4sf n = x - curve(p1, a) / m34sf_dot(ray.d, gradient(p1, a)); v4su inside = v4sf_lt(k.min, n) & v4sf_lt(n, k.max); v4sf nx = v4sf_select(inside, n, x); m34sf p2 = ray_point(nx, ray); v4su test = sign_change(v0, curve(p2, a)); k.min = v4sf_select(test, k.min, nx); k.max = v4sf_select(test, nx, k.max); } return v4sf_set1(0.5) * (k.min + k.max); }
static inline v4sf newton_forward(v4sf n, struct ray ray, float a) { for (int i = 0; i < 20; i++) { m34sf p = ray_point(n, ray); v4sf x = - curve(p, a) / m34sf_dot(ray.d, gradient(p, a)); n += v4sf_max(x, v4sf_set1(0)); } return n; }
static inline m34sf color(v4sf n, v4su test, struct ray ray, float a) { m34sf p = ray_point(n, ray); v4sf diff = m34sf_dot(ray.d, m34sf_normal(gradient(p, a))); v4su face = v4sf_gt(diff, v4sf_set1(0)); v4sf r = v4sf_and(test & face, diff); v4sf g = v4sf_and(test & ~face, -diff); v4sf b = v4sf_set1(0); return (m34sf) { r, g, b }; }
static inline v4su localize(i4sf *l, struct ray ray, float a) { float coarse = 0.05; float fine = 0.001; i4sf k = *l; m34sf p0 = ray_point(k.min, ray); v4sf v0 = curve(p0, a); v4su test = v4su_set1(0); while (!v4su_all_ones(test | v4sf_ge(k.min, l->max))) { v4sf x = v0 / m34sf_dot(ray.d, gradient(p0, a)); v4sf step = v4sf_clamp(v4sf_abs(x), v4sf_set1(fine), v4sf_set1(coarse)); k.max = v4sf_select(test, k.max, k.min + step); m34sf p1 = ray_point(k.max, ray); v4sf v1 = curve(p1, a); test |= v4sf_lt(k.max, l->max) & sign_change(v0, v1); k.min = v4sf_select(test, k.min, k.max); v0 = v1; p0 = p1; } l->min = v4sf_select(test, k.min, l->min); l->max = v4sf_select(test, k.max, l->max); return test; }
static inline v4su zero_test(v4sf n, struct ray ray, float a) { m34sf p = ray_point(n, ray); v4sf v = curve(p, a); return v4sf_eq(v4sf_set1(0), v); }