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