1 /* 2 Copyright © 2020, Luna Nielsen 3 Distributed under the 2-Clause BSD License, see LICENSE file. 4 5 Authors: Luna Nielsen 6 */ 7 module engine.math; 8 public import engine.math.camera; 9 public import engine.math.transform; 10 public import engine.math.obb; 11 public import std.math; 12 public import gl3n.math; 13 public import gl3n.linalg; 14 public import gl3n.aabb; 15 public import gl3n.interpolate; 16 import engine.core.log; 17 18 /** 19 Smoothly dampens from a position to a target 20 */ 21 vec3 dampen(vec3 pos, vec3 target, float delta, float speed = 1) { 22 return (pos - target) * pow(1e-4f, delta*speed) + target; 23 } 24 25 /** 26 A basic ray 27 */ 28 struct Ray { 29 /** 30 Origin of the ray 31 */ 32 vec3 origin; 33 34 /** 35 Direction of the ray (unit vector) 36 */ 37 vec3 direction; 38 39 string toString() { 40 import std.format : format; 41 return "origin=<%s, %s, %s> dir=<%s, %s, %s>".format(origin.x, origin.y, origin.z, direction.x, direction.y, direction.z); 42 } 43 } 44 /** 45 Casts a screen space ray from the mouse position 46 */ 47 Ray castScreenSpaceRay(vec2 mouse, vec2 viewSize, mat4 vp) { 48 49 // mouse to homogenus coordinates 50 double x = mouse.x / (viewSize.x * 0.5) - 1.0; 51 double y = mouse.y / (viewSize.y * 0.5) - 1.0; 52 53 x = clamp(x, -1, 1); 54 y = clamp(y, -1, 1); 55 56 vec4 rayStart = vec4( 57 x, 58 -y, 59 0, 60 1 61 ); 62 63 vec4 rayEnd = vec4( 64 x, 65 -y, 66 1, 67 1 68 ); 69 70 // Get inverse vp matrix 71 immutable(mat4) vpInverse = vp.inverse; 72 vec4 rayStartWorld = vpInverse * rayStart; rayStartWorld /= rayStartWorld.w; 73 vec4 rayEndWorld = vpInverse * rayEnd; rayEndWorld /= rayEndWorld.w; 74 75 // Get the ray direction 76 vec3 rayDir = vec3(rayEndWorld-rayStartWorld).normalized; 77 return Ray(rayStartWorld.xyz, rayDir); 78 } 79 80 /** 81 Gets whether a ray is intersecting a bounding box 82 */ 83 bool isRayIntersecting(OBB boundingBox, Ray ray, mat4 modelmatrix, ref float iDist) { 84 float min = 0f; 85 float max = 100_000f; 86 87 vec3 oobWorldspace = vec3(modelmatrix[3][0], modelmatrix[3][1], modelmatrix[3][2]); 88 vec3 delta = oobWorldspace-ray.origin; 89 90 { 91 vec3 xaxis = vec3(modelmatrix[0][0], modelmatrix[0][1], modelmatrix[0][2]); 92 float e = dot(xaxis, delta); 93 float f = dot(ray.direction, xaxis); 94 95 if (fabs(f) > 0.0001f) { 96 float t1 = (e+boundingBox.min.x)/f; 97 float t2 = (e+boundingBox.max.x)/f; 98 99 // Swap if t1 is larger than t2 100 if (t1 > t2) { 101 float w = t1; 102 t1 = t2; 103 t2 = w; 104 } 105 106 if (t2 < max) max = t2; 107 if (t1 > min) min = t1; 108 109 if (max < min) return false; 110 } 111 } 112 113 { 114 vec3 yaxis = vec3(modelmatrix[1][0], modelmatrix[1][1], modelmatrix[1][2]); 115 float e = dot(yaxis, delta); 116 float f = dot(ray.direction, yaxis); 117 118 if (fabs(f) > 0.0001f) { 119 float t1 = (e+boundingBox.min.y)/f; 120 float t2 = (e+boundingBox.max.y)/f; 121 122 // Swap if t1 is larger than t2 123 if (t1 > t2) { 124 float w = t1; 125 t1 = t2; 126 t2 = w; 127 } 128 129 if (t2 < max) max = t2; 130 if (t1 > min) min = t1; 131 132 if (max < min) return false; 133 } 134 } 135 136 { 137 vec3 zaxis = vec3(modelmatrix[2][0], modelmatrix[2][1], modelmatrix[2][2]); 138 float e = dot(zaxis, delta); 139 float f = dot(ray.direction, zaxis); 140 141 if (fabs(f) > 0.0001f) { 142 float t1 = (e+boundingBox.min.z)/f; 143 float t2 = (e+boundingBox.max.z)/f; 144 145 // Swap if t1 is larger than t2 146 if (t1 > t2) { 147 float w = t1; 148 t1 = t2; 149 t2 = w; 150 } 151 152 if (t2 < max) max = t2; 153 if (t1 > min) min = t1; 154 155 if (max < min) return false; 156 } 157 } 158 159 iDist = min; 160 return true; 161 }