Tachyon (current)  Current Main Branch
sphere.c
Go to the documentation of this file.
1 /*
2  * sphere.c - This file contains the functions for dealing with spheres.
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: sphere.c,v 1.36 2022/02/18 17:55:28 johns Exp $
8  *
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 
16 #define TACHYON_INTERNAL 1
17 #include "tachyon.h"
18 #include "macros.h"
19 #include "vector.h"
20 #include "intersect.h"
21 #include "util.h"
22 
23 #define SPHERE_PRIVATE
24 #include "sphere.h"
25 
26 static object_methods sphere_methods = {
27  (void (*)(const void *, void *))(sphere_intersect),
28  (void (*)(const void *, const void *, const void *, void *))(sphere_normal),
29  sphere_bbox,
30  free
31 };
32 
33 object * newsphere(void * tex, vector ctr, flt rad) {
34  sphere * s;
35 
36  s=(sphere *) malloc(sizeof(sphere));
37  memset(s, 0, sizeof(sphere));
38  s->methods = &sphere_methods;
39 
40  s->tex=tex;
41  s->ctr=ctr;
42  s->rad=rad;
43 
44  return (object *) s;
45 }
46 
47 static int sphere_bbox(void * obj, vector * min, vector * max) {
48  sphere * s = (sphere *) obj;
49 
50  min->x = s->ctr.x - s->rad;
51  min->y = s->ctr.y - s->rad;
52  min->z = s->ctr.z - s->rad;
53  max->x = s->ctr.x + s->rad;
54  max->y = s->ctr.y + s->rad;
55  max->z = s->ctr.z + s->rad;
56 
57  return 1;
58 }
59 
60 static void sphere_intersect(const sphere * spr, ray * ry) {
61 #if 1
62  // classic ray-sphere intersection method
63  flt b, disc, t1, t2, temp;
64  vector V;
65 
66  VSUB(spr->ctr, ry->o, V);
67  VDOT(b, V, ry->d);
68  VDOT(temp, V, V);
69 
70  disc=b*b + spr->rad*spr->rad - temp;
71 
72  if (disc<=0.0) return;
73  disc=SQRT(disc);
74 
75  t2=b+disc;
76  if (t2 <= SPEPSILON)
77  return;
78  ry->add_intersection(t2, (object *) spr, ry);
79 
80  t1=b-disc;
81  if (t1 > SPEPSILON)
82  ry->add_intersection(t1, (object *) spr, ry);
83 #else
84  // Ray-sphere intersection method with improved floating point precision
85  // for cases where the sphere size is small relative to the distance
86  // from the camera to the sphere. This implementation is based on
87  // Eq. 10-72, p.603 of "Computer Graphics with OpenGL", 3rd Ed.,
88  // by Donald Hearn and Pauline Baker, 2004. Shown in Eq. 10, p.639
89  // in the 4th edition of the book (Hearn, Baker, Carithers).
90  vector deltap, remedyTerm;
91  flt ddp, disc;
92 
93  VSUB(spr->ctr, ry->o, deltap);
94  VDOT(ddp, ry->d, deltap);
95  remedyTerm.x = deltap.x - ddp * ry->d.x;
96  remedyTerm.y = deltap.y - ddp * ry->d.y;
97  remedyTerm.z = deltap.z - ddp * ry->d.z;
98  disc = spr->rad*spr->rad - (remedyTerm.x * remedyTerm.x + remedyTerm.y * remedyTerm.y + remedyTerm.z * remedyTerm.z);
99  if (disc >= 0.0f) {
100  flt disc_root = SQRT(disc);
101  float t2 = ddp + disc_root;
102  float t1 = ddp - disc_root;
103  if (t2 <= SPEPSILON)
104  return;
105  ry->add_intersection(t2, (object *) spr, ry);
106 
107  if (t1 > SPEPSILON)
108  ry->add_intersection(t1, (object *) spr, ry);
109  }
110 #endif
111 }
112 
113 static void sphere_normal(const sphere * spr, const vector * pnt, const ray * incident, vector * N) {
114  flt invlen;
115 
116  N->x = pnt->x - spr->ctr.x;
117  N->y = pnt->y - spr->ctr.y;
118  N->z = pnt->z - spr->ctr.z;
119 
120  invlen = 1.0 / SQRT(N->x*N->x + N->y*N->y + N->z*N->z);
121  N->x *= invlen;
122  N->y *= invlen;
123  N->z *= invlen;
124 
125  /* Flip surface normal to point toward the viewer if necessary */
126  if (VDot(N, &(incident->d)) > 0.0) {
127  N->x=-N->x;
128  N->y=-N->y;
129  N->z=-N->z;
130  }
131 }
132 
133 
static int sphere_bbox(void *obj, vector *min, vector *max)
Definition: sphere.c:47
static void sphere_normal(const sphere *spr, const vector *pnt, const ray *incident, vector *N)
Definition: sphere.c:113
#define VSUB(a, b, c)
Definition: macros.h:24
flt VDot(apivector *a, apivector *b)
double flt
generic floating point number, using double
Definition: tachyon.h:47
#define VDOT(return, a, b)
Definition: macros.h:15
Tachyon cross-platform timers, special math function wrappers, and RNGs.
#define SQRT(x)
Definition: util.h:31
static void sphere_intersect(const sphere *spr, ray *ry)
Definition: sphere.c:60
object * newsphere(void *tex, vector ctr, flt rad)
Definition: sphere.c:33
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
static object_methods sphere_methods
Definition: sphere.c:26