-
Notifications
You must be signed in to change notification settings - Fork 32
Effective vek
This page lacks some more content. There are quite a bunch of interesting tricks vek
allows for.
If you need that Vec3<i32>
cast to a Vec3<f32>
(or any other type), you may do so via map()
:
let v = Vec3::<i32>::zero(); // or any value, really
let v = v.map(|x| x as f32);
(Note that since 0.10.3, you should consider let v: Vec4<f32> = v.as_();
, which uses AsPrimitive
, for trivial safe conversions).
This is also the way to go for LERP-ing integer vectors or getting the average of a Rgba<u8>
: Convert to float, perform the operation, then convert back to integers (optionally using round()
, ceil()
, etc).
All matrix types have map()
too, which works the same way. In addition, row-major matrices have map_rows()
and column-major ones have map_cols()
(for, respectively, performing some operation on rows or columns).
Some geometric constructs (such as Rect
and Aabr
) also have map()
. If you would like other types to have a map()
API, feel free to suggest that in an issue!
You'll often encounter function signatures such as this one (from Mat4
) :
pub fn scaling_3d<V: Into<Vec3<T>>>(v: V) -> Self where T: Zero + One { ... }
The Into<Vec3<T>>
bound allows you to call this function in all sorts of convenient ways!
// A vector can be obtained from a single value by setting all elements to it
// as long as T is Copy.
// Concise uniform scale!
let _ = Mat4::scaling_3d(5_f32);
// A vector can be obtained from a tuple with identical number of elements;
let _ = Mat4::scaling_3d((5_f32, 4_f32, 3_f32));
// A vector can be obtained from an array with identical number of elements;
let _ = Mat4::scaling_3d([5_f32, 4., 3.]);
// Any T implements Into<T> by returning itself, so this works!
let v = Vec3::new(5_f32, 4., 3.);
let _ = Mat4::scaling_3d(v);
// A Vec4 is converted to a Vec3 by dropping the `w` element (not dividing by it!)
let v = Vec4::new(5_f32, 4., 3., 1.);
let _ = Mat4::scaling_3d(v);
let v = Vec4::new(5_f32, 4., 3., 0.);
let _ = Mat4::scaling_3d(v);
It's also worth noting that repr_simd
vectors can be converted to repr_c
ones via From
, and the other way around as well.
Another example is ShuffleMask4
for Vec4
:
pub fn shuffled<M: Into<ShuffleMask4>>(self, mask: M) -> Self where T: Copy { ... }
The Into<ShuffleMask4>
bound allows you to call shuffled
in any of the following ways :
let a = Vec4::<u32>::new(0,1,2,3);
assert_eq!(a.shuffled((0,1,2,3)), Vec4::new(0,1,2,3));
assert_eq!(a.shuffled([0,1,2,3]), Vec4::new(0,1,2,3));
assert_eq!(a.shuffled(1), Vec4::broadcast(1));
For instance, indexing a matrix with a Vec2
is not allowed; If it was, what would the meaning be ?
Would x
mean "row index" because it is the first element, or "column index" because it represents a horizontal offset ?
Therefore, you can only index matrices with explicit (i, j)
tuples, i
being the row index and j
the column index.
(Another way is to index the public member, like m.cols[j][i]
or m.rows[i][j]
).
Also notice how Mat4<T>
doesn't accept V: Into<Vec4<T>>
as a right-hand-side operand:
This means we can't do mat4 * vec3
, and it's on purpose ! It's because the w
element of Vec4
matters here, and we have no idea
which would make more sense: set it to 1, or 0 ?
When w
is 0, all translational effects of the transform are cancelled. When w
is 1, they are applied normally.
However, transforming 3D vectors is a very common use case, so mul_point
and mul_direction
methods are provided for Mat4
.
These take V: Into<Vec3<T>>
, dropping any w
element and replacing it by, respectively, 1 and 0.
The matrix API was designed such that users could fearlessly decide, at any point in the development cycle,
to move from column-major to row-major, and the other way around as well.
Correctness is enforced by encoding the current layout in the names of appropriate functions (and the matrix's public member, either rows
or cols
).
Because these names carry information about the current layout, and are therefore made layout-specific, they will turn into hard compile-time errors when you decide to use another layout - which is what you want, instead of exhibiting funny behaviour at run-time in places you haven't been careful enough to refactor accordingly.
Examples include as_col_ptr
vs as_row_ptr
, as_col_slice
vs as_row_slice
, and map_cols
vs map_rows
.