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