summaryrefslogtreecommitdiff
path: root/src/intersect.h
blob: 978bde8f945c694565426b9346f92da3b43b004e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//-*-c-*-

#ifndef __INTERSECT_H__
#define __INTERSECT_H__

#include "linalg.h"
#include "matrix.h"
#include "geometry.h"

#define EPSILON 0.0f

/* Tests the intersection between a ray and a triangle.
   If the ray intersects the triangle, set `distance` to the distance from
   `origin` to the intersection and return true, else return false.
   `direction` must be normalized to one. */
__device__ bool
intersect_triangle(const float3 &origin, const float3 &direction,
		   const Triangle &triangle, float &distance)
{
	float3 m1 = triangle.v1-triangle.v0;
	float3 m2 = triangle.v2-triangle.v0;
	float3 m3 = -direction;

	Matrix m = make_matrix(m1, m2, m3);
	
	float determinant = det(m);

	if (determinant == 0.0f)
		return false;

	float3 b = origin-triangle.v0;

	float u1 = ((m.a11*m.a22 - m.a12*m.a21)*b.x +
		    (m.a02*m.a21 - m.a01*m.a22)*b.y +
		    (m.a01*m.a12 - m.a02*m.a11)*b.z)/determinant;

	if (u1 < -EPSILON || u1 > 1.0f)
		return false;

	float u2 = ((m.a12*m.a20 - m.a10*m.a22)*b.x +
		    (m.a00*m.a22 - m.a02*m.a20)*b.y +
		    (m.a02*m.a10 - m.a00*m.a12)*b.z)/determinant;

	if (u2 < -EPSILON || u2 > 1.0f)
		return false;

	float u3 = ((m.a10*m.a21 - m.a11*m.a20)*b.x +
		    (m.a01*m.a20 - m.a00*m.a21)*b.y +
		    (m.a00*m.a11 - m.a01*m.a10)*b.z)/determinant;

	if (u3 <= 0.0f || (1.0f-u1-u2) < -EPSILON)
		return false;

	distance = u3;

	return true;
}

/* Tests the intersection between a ray and an axis-aligned box defined by
   an upper and lower bound. If the ray intersects the box, set
   `distance_to_box` to the distance from `origin` to the intersection and
   return true, else return false. `direction` must be normalized to one.

   Source: "An Efficient and Robust Ray-Box Intersection Algorithm."
   by Williams, et. al. */
__device__ bool
intersect_box(const float3 &origin, const float3 &direction,
	      const float3 &lower_bound, const float3 &upper_bound,
	      float& distance_to_box)
{
	float kmin, kmax, kymin, kymax, kzmin, kzmax;

	float divx = 1.0f/direction.x;
	if (divx >= 0.0f)
	{
		kmin = (lower_bound.x - origin.x)*divx;
		kmax = (upper_bound.x - origin.x)*divx;
	}
	else
	{
		kmin = (upper_bound.x - origin.x)*divx;
		kmax = (lower_bound.x - origin.x)*divx;
	}

	if (kmax < 0.0f)
		return false;

	float divy = 1.0f/direction.y;
	if (divy >= 0.0f)
	{
		kymin = (lower_bound.y - origin.y)*divy;
		kymax = (upper_bound.y - origin.y)*divy;
	}
	else
	{
		kymin = (upper_bound.y - origin.y)*divy;
		kymax = (lower_bound.y - origin.y)*divy;
	}

	if (kymax < 0.0f)
		return false;

	if (kymin > kmin)
		kmin = kymin;

	if (kymax < kmax)
		kmax = kymax;

	if (kmin > kmax)
		return false;

	float divz = 1.0f/direction.z;
	if (divz >= 0.0f)
	{
		kzmin = (lower_bound.z - origin.z)*divz;
		kzmax = (upper_bound.z - origin.z)*divz;
	}
	else
	{
		kzmin = (upper_bound.z - origin.z)*divz;
		kzmax = (lower_bound.z - origin.z)*divz;
	}

	if (kzmax < 0.0f)
		return false;

	if (kzmin > kmin)
		kmin = kzmin;

	if (kzmax < kmax)
		kmax = kzmax;

	if (kmin > kmax)
		return false;

	distance_to_box = kmin;

	return true;
}

#endif