A game about forced loneliness, made by TACStudios
1#ifndef UNITY_GEOMETRICTOOLS_INCLUDED
2#define UNITY_GEOMETRICTOOLS_INCLUDED
3
4//-----------------------------------------------------------------------------
5// Intersection functions
6//-----------------------------------------------------------------------------
7
8// return furthest near intersection in x and closest far intersection in y
9// if (intersections.y > intersections.x) the ray hit the box, else it miss it
10// Assume dir is normalize
11float2 BoxRayIntersect(float3 start, float3 dir, float3 boxMin, float3 boxMax)
12{
13 float3 invDir = 1.0 / dir;
14
15 // Find the ray intersection with box plane
16 float3 firstPlaneIntersect = (boxMin - start) * invDir;
17 float3 secondPlaneIntersect = (boxMax - start) * invDir;
18
19 // Get the closest/furthest of these intersections along the ray (Ok because x/0 give +inf and -x/0 give -inf )
20 float3 closestPlane = min(firstPlaneIntersect, secondPlaneIntersect);
21 float3 furthestPlane = max(firstPlaneIntersect, secondPlaneIntersect);
22
23 float2 intersections;
24 // Find the furthest near intersection
25 intersections.x = max(closestPlane.x, max(closestPlane.y, closestPlane.z));
26 // Find the closest far intersection
27 intersections.y = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z);
28
29 return intersections;
30}
31
32// This simplified version assume that we care about the result only when we are inside the box
33// Assume dir is normalize
34float BoxRayIntersectSimple(float3 start, float3 dir, float3 boxMin, float3 boxMax)
35{
36 float3 invDir = 1.0 / dir;
37
38 // Find the ray intersection with box plane
39 float3 rbmin = (boxMin - start) * invDir;
40 float3 rbmax = (boxMax - start) * invDir;
41
42 float3 rbminmax = (dir > 0.0) ? rbmax : rbmin;
43
44 return min(min(rbminmax.x, rbminmax.y), rbminmax.z);
45}
46
47// Assume Sphere is at the origin (i.e start = position - spherePosition)
48float2 SphereRayIntersect(float3 start, float3 dir, float radius, out bool intersect)
49{
50 float a = dot(dir, dir);
51 float b = dot(dir, start) * 2.0;
52 float c = dot(start, start) - radius * radius;
53 float discriminant = b * b - 4.0 * a * c;
54
55 float2 intersections = float2(0.0, 0.0);
56 intersect = false;
57 if (discriminant < 0.0 || a == 0.0)
58 {
59 intersections.x = 0.0;
60 intersections.y = 0.0;
61 }
62 else
63 {
64 float sqrtDiscriminant = sqrt(discriminant);
65 intersections.x = (-b - sqrtDiscriminant) / (2.0 * a);
66 intersections.y = (-b + sqrtDiscriminant) / (2.0 * a);
67 intersect = true;
68 }
69
70 return intersections;
71}
72
73// This simplified version assume that we care about the result only when we are inside the sphere
74// Assume Sphere is at the origin (i.e start = position - spherePosition) and dir is normalized
75// Ref: http://http.developer.nvidia.com/GPUGems/gpugems_ch19.html
76float SphereRayIntersectSimple(float3 start, float3 dir, float radius)
77{
78 float b = dot(dir, start) * 2.0;
79 float c = dot(start, start) - radius * radius;
80 float discriminant = b * b - 4.0 * c;
81
82 return abs(sqrt(discriminant) - b) * 0.5;
83}
84
85float3 RayPlaneIntersect(in float3 rayOrigin, in float3 rayDirection, in float3 planeOrigin, in float3 planeNormal)
86{
87 float dist = dot(planeNormal, planeOrigin - rayOrigin) / dot(planeNormal, rayDirection);
88 return rayOrigin + rayDirection * dist;
89}
90
91//-----------------------------------------------------------------------------
92// Miscellaneous functions
93//-----------------------------------------------------------------------------
94
95// Box is AABB
96float DistancePointBox(float3 position, float3 boxMin, float3 boxMax)
97{
98 return length(max(max(position - boxMax, boxMin - position), float3(0.0, 0.0, 0.0)));
99}
100
101float3 ProjectPointOnPlane(float3 position, float3 planePosition, float3 planeNormal)
102{
103 return position - (dot(position - planePosition, planeNormal) * planeNormal);
104}
105
106// Plane equation: {(a, b, c) = N, d = -dot(N, P)}.
107// Returns the distance from the plane to the point 'p' along the normal.
108// Positive -> in front (above), negative -> behind (below).
109float DistanceFromPlane(float3 p, float4 plane)
110{
111 return dot(float4(p, 1.0), plane);
112}
113
114// Returns 'true' if the triangle is outside of the frustum.
115// 'epsilon' is the (negative) distance to (outside of) the frustum below which we cull the triangle.
116bool CullTriangleFrustum(float3 p0, float3 p1, float3 p2, float epsilon, float4 frustumPlanes[6], int numPlanes)
117{
118 bool outside = false;
119
120 for (int i = 0; i < numPlanes; i++)
121 {
122 // If all 3 points are behind any of the planes, we cull.
123 outside = outside || Max3(DistanceFromPlane(p0, frustumPlanes[i]),
124 DistanceFromPlane(p1, frustumPlanes[i]),
125 DistanceFromPlane(p2, frustumPlanes[i])) < epsilon;
126 }
127
128 return outside;
129}
130
131// Returns 'true' if the edge of the triangle is outside of the frustum.
132// The edges are defined s.t. they are on the opposite side of the point with the given index.
133// 'epsilon' is the (negative) distance to (outside of) the frustum below which we cull the triangle.
134bool3 CullTriangleEdgesFrustum(float3 p0, float3 p1, float3 p2, float epsilon, float4 frustumPlanes[6], int numPlanes)
135{
136 bool3 edgesOutside = false;
137
138 for (int i = 0; i < numPlanes; i++)
139 {
140 bool3 pointsOutside = bool3(DistanceFromPlane(p0, frustumPlanes[i]) < epsilon,
141 DistanceFromPlane(p1, frustumPlanes[i]) < epsilon,
142 DistanceFromPlane(p2, frustumPlanes[i]) < epsilon);
143
144 // If both points of the edge are behind any of the planes, we cull.
145 edgesOutside.x = edgesOutside.x || (pointsOutside.y && pointsOutside.z);
146 edgesOutside.y = edgesOutside.y || (pointsOutside.x && pointsOutside.z);
147 edgesOutside.z = edgesOutside.z || (pointsOutside.x && pointsOutside.y);
148 }
149
150 return edgesOutside;
151}
152
153// Returns 'true' if a triangle defined by 3 vertices is back-facing.
154// 'epsilon' is the (negative) value of dot(N, V) below which we cull the triangle.
155// 'winding' can be used to change the order: pass 1 for (p0 -> p1 -> p2), or -1 for (p0 -> p2 -> p1).
156bool CullTriangleBackFace(float3 p0, float3 p1, float3 p2, float epsilon, float3 viewPos, float winding)
157{
158 float3 edge1 = p1 - p0;
159 float3 edge2 = p2 - p0;
160
161 float3 N = cross(edge1, edge2);
162 float3 V = viewPos - p0;
163 float NdotV = dot(N, V) * winding;
164
165 // Optimize:
166 // NdotV / (length(N) * length(V)) < Epsilon
167 // NdotV < Epsilon * length(N) * length(V)
168 // NdotV < Epsilon * sqrt(dot(N, N)) * sqrt(dot(V, V))
169 // NdotV < Epsilon * sqrt(dot(N, N) * dot(V, V))
170 return NdotV < epsilon * sqrt(dot(N, N) * dot(V, V));
171}
172
173#endif // UNITY_GEOMETRICTOOLS_INCLUDED