1use crate::matrix::*;
53use crate::quaternion::*;
54use crate::scalar::*;
55use crate::vector::*;
56use num_traits::{Zero, One};
57
58pub fn translate<T: Scalar>(trans: Vector3<T>) -> Matrix4<T> {
71 Matrix4::new(
72 <T as One>::one(),
73 <T as Zero>::zero(),
74 <T as Zero>::zero(),
75 <T as Zero>::zero(),
76 <T as Zero>::zero(),
77 <T as One>::one(),
78 <T as Zero>::zero(),
79 <T as Zero>::zero(),
80 <T as Zero>::zero(),
81 <T as Zero>::zero(),
82 <T as One>::one(),
83 <T as Zero>::zero(),
84 trans.x,
85 trans.y,
86 trans.z,
87 <T as One>::one(),
88 )
89}
90
91pub fn scale<T: Scalar>(scale: Vector3<T>) -> Matrix4<T> {
104 Matrix4::new(
105 scale.x,
106 <T as Zero>::zero(),
107 <T as Zero>::zero(),
108 <T as Zero>::zero(),
109 <T as Zero>::zero(),
110 scale.y,
111 <T as Zero>::zero(),
112 <T as Zero>::zero(),
113 <T as Zero>::zero(),
114 <T as Zero>::zero(),
115 scale.z,
116 <T as Zero>::zero(),
117 <T as Zero>::zero(),
118 <T as Zero>::zero(),
119 <T as Zero>::zero(),
120 <T as One>::one(),
121 )
122}
123
124pub fn rotation_from_quat<T: FloatScalar>(q: &Quat<T>) -> Matrix4<T> {
128 Quat::mat4(q)
129}
130
131pub fn rotation_from_axis_angle<T: FloatScalar>(axis: &Vector3<T>, angle: T) -> Matrix4<T> {
137 Quat::mat4(&Quat::of_axis_angle(axis, angle))
138}
139
140pub fn transform_vec3<T: Scalar>(m: &Matrix4<T>, v: &Vector3<T>) -> Vector3<T> {
144 let v4 = Vector4::new(v.x, v.y, v.z, <T as One>::one());
145 let vout = *m * v4;
146 Vector3::new(vout.x / vout.w, vout.y / vout.w, vout.z / vout.w)
147}
148
149pub fn project3<T: Scalar>(
161 world: &Matrix4<T>,
162 persp: &Matrix4<T>,
163 lb: &Vector2<T>,
164 rt: &Vector2<T>,
165 pt: &Vector3<T>,
166) -> Vector3<T> {
167 let inp = Vector4::new(pt.x, pt.y, pt.z, <T as One>::one());
168 let pw = *persp * *world;
169 let mut out = pw * inp;
170
171 out.x /= out.w;
172 out.y /= out.w;
173 out.z /= out.w;
174
175 let out_x = lb.x + ((rt.x - lb.x) * (out.x + <T as One>::one()) * T::half());
176 let out_y = lb.y + ((rt.y - lb.y) * (out.y + <T as One>::one()) * T::half());
177 let out_z = (out.z + <T as One>::one()) * T::half();
178 Vector3::new(out_x, out_y, out_z)
179}
180
181pub fn unproject3<T: Scalar>(
193 world: &Matrix4<T>,
194 persp: &Matrix4<T>,
195 lb: &Vector2<T>,
196 rt: &Vector2<T>,
197 pt: &Vector3<T>,
198) -> Vector3<T> {
199 let pw = *persp * *world;
200 let inv = pw.inverse();
201 let in_x = (T::two() * (pt.x - lb.x) / (rt.x - lb.x)) - <T as One>::one();
202 let in_y = (T::two() * (pt.y - lb.y) / (rt.y - lb.y)) - <T as One>::one();
203 let in_z = (T::two() * pt.z) - <T as One>::one();
204 let in_w = <T as One>::one();
205 let inp = Vector4::new(in_x, in_y, in_z, in_w);
206 let out = inv * inp;
207 let out4 = out / out.w;
208 Vector3::new(out4.x, out4.y, out4.z)
209}
210
211pub fn frustum<T: Scalar>(lbn: &Vector3<T>, rtf: &Vector3<T>) -> Matrix4<T> {
219 let width = rtf.x - lbn.x;
220 let height = rtf.y - lbn.y;
221 let depth = rtf.z - lbn.z;
222 let a = (rtf.x + lbn.x) / width;
223 let b = (rtf.y + lbn.y) / height;
224 let c = -(rtf.z + lbn.z) / depth;
225 let d = -(T::two() * rtf.z * lbn.z) / depth;
226
227 Matrix4::new(
228 T::two() * lbn.z / width,
229 <T as Zero>::zero(),
230 <T as Zero>::zero(),
231 <T as Zero>::zero(),
232 <T as Zero>::zero(),
233 T::two() * lbn.z / height,
234 <T as Zero>::zero(),
235 <T as Zero>::zero(),
236 a,
237 b,
238 c,
239 -<T as One>::one(),
240 <T as Zero>::zero(),
241 <T as Zero>::zero(),
242 d,
243 <T as Zero>::zero(),
244 )
245}
246
247pub fn ortho4<T: Scalar>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Matrix4<T> {
256 let width = right - left;
257 let height = top - bottom;
258 let depth = far - near;
259 let r00 = T::two() / width;
260 let r11 = T::two() / height;
261 let r22 = -T::two() / depth;
262 let r03 = -(right + left) / width;
263 let r13 = -(top + bottom) / height;
264 let r23 = -(far + near) / depth;
265 Matrix4::new(
266 r00,
267 <T as Zero>::zero(),
268 <T as Zero>::zero(),
269 <T as Zero>::zero(),
270 <T as Zero>::zero(),
271 r11,
272 <T as Zero>::zero(),
273 <T as Zero>::zero(),
274 <T as Zero>::zero(),
275 <T as Zero>::zero(),
276 r22,
277 <T as Zero>::zero(),
278 r03,
279 r13,
280 r23,
281 <T as One>::one(),
282 )
283}
284
285pub fn perspective<T: FloatScalar>(fovy: T, aspect: T, near: T, far: T) -> Matrix4<T> {
295 let f = <T as One>::one() / T::ttan(fovy * T::half());
296 let denom = near - far;
297 let a = (far + near) / denom;
298 let b = (T::two() * far * near) / denom;
299
300 Matrix4::new(
301 f / aspect,
302 <T as Zero>::zero(),
303 <T as Zero>::zero(),
304 <T as Zero>::zero(),
305 <T as Zero>::zero(),
306 f,
307 <T as Zero>::zero(),
308 <T as Zero>::zero(),
309 <T as Zero>::zero(),
310 <T as Zero>::zero(),
311 a,
312 -<T as One>::one(),
313 <T as Zero>::zero(),
314 <T as Zero>::zero(),
315 b,
316 <T as Zero>::zero(),
317 )
318}
319
320pub fn lookat<T: FloatScalar>(eye: &Vector3<T>, dest: &Vector3<T>, up: &Vector3<T>) -> Matrix4<T> {
329 let f = Vector3::normalize(&(*dest - *eye));
330 let s = Vector3::normalize(&Vector3::cross(&f, up));
331 let u = Vector3::normalize(&Vector3::cross(&s, &f));
332
333 let trans = translate(-*eye);
334
335 let m = Matrix4::new(
336 s.x,
337 u.x,
338 -f.x,
339 <T as Zero>::zero(),
340 s.y,
341 u.y,
342 -f.y,
343 <T as Zero>::zero(),
344 s.z,
345 u.z,
346 -f.z,
347 <T as Zero>::zero(),
348 <T as Zero>::zero(),
349 <T as Zero>::zero(),
350 <T as Zero>::zero(),
351 <T as One>::one(),
352 );
353 m * trans
354}
355
356pub fn decompose<T: FloatScalar>(m: &Matrix4<T>) -> Option<(Vector3<T>, Quat<T>, Vector3<T>)> {
365 let mut col0 = Vector3::new(m.col[0].x, m.col[0].y, m.col[0].z);
366 let mut col1 = Vector3::new(m.col[1].x, m.col[1].y, m.col[1].z);
367 let mut col2 = Vector3::new(m.col[2].x, m.col[2].y, m.col[2].z);
368 let det = m.determinant();
369
370 let mut scale = Vector3::new(
372 Vector3::length(&col0),
373 Vector3::length(&col1),
374 Vector3::length(&col2),
375 );
376 let trans = Vector3::new(m.col[3].x, m.col[3].y, m.col[3].z);
377
378 if det < <T as Zero>::zero() {
379 scale = -scale;
380 }
381
382 if scale.x != <T as Zero>::zero() {
383 col0 = col0 / scale.x;
384 } else {
385 return Option::None;
386 }
387
388 if scale.y != <T as Zero>::zero() {
389 col1 = col1 / scale.y;
390 } else {
391 return Option::None;
392 }
393
394 if scale.z != <T as Zero>::zero() {
395 col2 = col2 / scale.z;
396 } else {
397 return Option::None;
398 }
399
400 let rot_matrix = Matrix3::new(
401 col0.x, col0.y, col0.z, col1.x, col1.y, col1.z, col2.x, col2.y, col2.z,
402 );
403
404 let rot = Quat::of_matrix3(&rot_matrix);
405
406 Some((scale, rot, trans))
407}
408
409#[cfg(test)]
410mod tests {
411 use super::*;
412 #[test]
413 pub fn test_decompose() {
414 let ms = scale(Vector3::<f32>::new(4.0, 5.0, 6.0));
415 let mt = translate(Vector3::<f32>::new(1.0, 2.0, 3.0));
416 let q = Quat::<f32>::of_axis_angle(&Vector3::new(1.0, 1.0, 1.0), 1.0);
417 let mr = rotation_from_quat(&q);
418
419 let m = mt * mr * ms;
420
421 let v = decompose(&m);
422 match v {
423 None => assert_eq!(1, 2),
424 Some((s, r, t)) => {
425 assert_eq!((s.x - 4.0) < f32::epsilon(), true);
426 assert_eq!((s.y - 5.0) < f32::epsilon(), true);
427 assert_eq!((s.z - 6.0) < f32::epsilon(), true);
428
429 assert_eq!((q.x - r.x) < f32::epsilon(), true);
430 assert_eq!((q.y - r.y) < f32::epsilon(), true);
431 assert_eq!((q.z - r.z) < f32::epsilon(), true);
432 assert_eq!((q.w - r.w) < f32::epsilon(), true);
433
434 assert_eq!((t.x - 1.0) < f32::epsilon(), true);
435 assert_eq!((t.y - 2.0) < f32::epsilon(), true);
436 assert_eq!((t.z - 3.0) < f32::epsilon(), true);
437 }
438 }
439 }
440}