Add sphere intersection function
This commit is contained in:
		
							parent
							
								
									0c050734c7
								
							
						
					
					
						commit
						974ebd6ccd
					
				
					 2 changed files with 110 additions and 2 deletions
				
			
		
							
								
								
									
										110
									
								
								src/object.c
									
										
									
									
									
								
							
							
						
						
									
										110
									
								
								src/object.c
									
										
									
									
									
								
							| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include "basics.h"
 | 
					#include "basics.h"
 | 
				
			||||||
#include "object.h"
 | 
					#include "object.h"
 | 
				
			||||||
| 
						 | 
					@ -16,12 +17,17 @@ struct _Object {
 | 
				
			||||||
    ObjectType type;
 | 
					    ObjectType type;
 | 
				
			||||||
    Vector3 location;
 | 
					    Vector3 location;
 | 
				
			||||||
    void *shape;
 | 
					    void *shape;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int (*does_intersect)(Object *obj, Ray ray, float **t);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct _Sphere {
 | 
					typedef struct _Sphere {
 | 
				
			||||||
    float radius;
 | 
					    float radius;
 | 
				
			||||||
} Sphere;
 | 
					} Sphere;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sphere_does_intersect(Object *obj, Ray ray, float **t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * object_init ---
 | 
					 * object_init ---
 | 
				
			||||||
| 
						 | 
					@ -37,9 +43,16 @@ object_init(ObjectType type)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (type) {
 | 
					    switch (type) {
 | 
				
			||||||
        case ObjectTypeSphere:
 | 
					        case ObjectTypeSphere: {
 | 
				
			||||||
            obj->shape = malloc(sizeof(Sphere));
 | 
					            Sphere *s = malloc(sizeof(Sphere));
 | 
				
			||||||
 | 
					            if (s == NULL) {
 | 
				
			||||||
 | 
					                // TODO: DANGER! WILL ROBINSON!
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            obj->shape = s;
 | 
				
			||||||
 | 
					            s->radius = 0.0;
 | 
				
			||||||
 | 
					            obj->does_intersect = sphere_does_intersect;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            assert(0);
 | 
					            assert(0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -84,6 +97,19 @@ object_set_location(Object *obj, Vector3 location)
 | 
				
			||||||
    obj->location = location;
 | 
					    obj->location = location;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * object_does_intersect --
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Determine if a ray intersects with the object.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					object_does_intersect(Object *obj, Ray ray, float **t)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(obj != NULL && obj->does_intersect != NULL);
 | 
				
			||||||
 | 
					    return obj->does_intersect(obj, ray, t);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Sphere functions
 | 
					 * Sphere functions
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -107,3 +133,83 @@ object_sphere_set_radius(Object *obj, float r)
 | 
				
			||||||
    assert(obj != NULL && obj->type == ObjectTypeSphere);
 | 
					    assert(obj != NULL && obj->type == ObjectTypeSphere);
 | 
				
			||||||
    ((Sphere *)obj->shape)->radius = r;
 | 
					    ((Sphere *)obj->shape)->radius = r;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * sphere_does_intersect --
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Compute the intersection of a ray with the given object. The object must be a Sphere. All intersection t values are
 | 
				
			||||||
 | 
					 * returned in the **t argument. The number of values returned therein is indicated by the return value. Memory is
 | 
				
			||||||
 | 
					 * allocated at *t. It is the caller's responsibility to free it when it is no longer needed. If 0 is returned, no
 | 
				
			||||||
 | 
					 * memory needs to be freed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					sphere_does_intersect(Object *obj, Ray ray, float **t)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Distance from vector point to center of sphere.
 | 
				
			||||||
 | 
					    Vector3 dist = vector_sub_vector(ray.location, object_get_location(obj));
 | 
				
			||||||
 | 
					    float r = object_sphere_get_radius(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Coefficients for quadratic equation.
 | 
				
			||||||
 | 
					    float a = vector_dot(ray.direction, ray.direction);
 | 
				
			||||||
 | 
					    float b = vector_dot(vector_mult_scalar(dist, 2), ray.direction);
 | 
				
			||||||
 | 
					    float c = vector_dot(dist, dist) - (r * r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Discriminant for quadratic equation.
 | 
				
			||||||
 | 
					    float discrim = b * b - 4.0 * a * c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If the discriminant is less than zero, there are no real (as in not imaginary) solutions to this intersection.
 | 
				
			||||||
 | 
					    if (discrim < 0) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Compute most of the quadratic equation as q. Doing this first helps avoid precision errors when
 | 
				
			||||||
 | 
					     * b =~ * sqrt(b^2 - 4ac).
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * See: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    float q;
 | 
				
			||||||
 | 
					    float sqrt_discrim = sqrtf(discrim);
 | 
				
			||||||
 | 
					    if (b < 0) {
 | 
				
			||||||
 | 
					        q = (-b - sqrt_discrim) / 2.0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        q = (-b + sqrt_discrim) / 2.0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Compute the intersections. Spheres have at most two intersections.
 | 
				
			||||||
 | 
					    float t0 = q / a;
 | 
				
			||||||
 | 
					    float t1 = c / q;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If t[1] is less than t[0], swap them (t[0] will always be the first intersection).
 | 
				
			||||||
 | 
					    if (t1 < t0) {
 | 
				
			||||||
 | 
					        float tmp = t0;
 | 
				
			||||||
 | 
					        t0 = t1;
 | 
				
			||||||
 | 
					        t1 = tmp;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * If the farther intersection of the two is in the negative direction, the sphere is in the ray's negative
 | 
				
			||||||
 | 
					     * direction.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (t1 < 0) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Allocate the memory and store the values. It's possible the two values are equal. Only allocate enough memory to
 | 
				
			||||||
 | 
					     * store the required number of values.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    int nints = (t0 != t1) ? 2 : 1;
 | 
				
			||||||
 | 
					    *t = malloc(sizeof(float) * nints);
 | 
				
			||||||
 | 
					    if (*t == NULL) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    (*t)[0] = t0;
 | 
				
			||||||
 | 
					    if (nints > 1) {
 | 
				
			||||||
 | 
					        (*t)[1] = t1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return nints;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,8 @@ void object_destroy(Object *obj);
 | 
				
			||||||
Vector3 object_get_location(Object *obj);
 | 
					Vector3 object_get_location(Object *obj);
 | 
				
			||||||
void object_set_location(Object *obj, Vector3 location);
 | 
					void object_set_location(Object *obj, Vector3 location);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int object_does_intersect(Object *obj, Ray ray, float **t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Sphere methods
 | 
					// Sphere methods
 | 
				
			||||||
float object_sphere_get_radius(Object *obj);
 | 
					float object_sphere_get_radius(Object *obj);
 | 
				
			||||||
void object_sphere_set_radius(Object *obj, float r);
 | 
					void object_sphere_set_radius(Object *obj, float r);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue