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 }