math/mathwfd.h forward declares all {mat|vec}{2|3|4}<> classes,
which allows us to remove their respective #include in a lot of
our public headers.
Our math headers are full of templates, so this should help build times
a bit.
Also we want to keep the public headers as minimalist as possible.
- we use by-value parameters in some places, which helps the compiler
(not sure why, but assuming references can be aliased and the
compiler is cautious about that).
This helps matrix multiplies (which is almost never inlined) and
transpose (but that's almost always inlined and merged with
something else, so the gain here is not completely real)
- remove support for matrices-of-matrices because this wasn't complete
anyways.
- improve matrix * scalar by inlining the loop manually instead of
going through *=, this saves some extra writes.
These constants are not part of the standard. We instead use our own
constexpr definitions in the filament::math namespace, as part of
the scalar.h include.
the C++ standard says:
if T is a class type with a default constructor that is neither
user-provided nor deleted (that is, it may be a class with an
implicitly-defined or defaulted default constructor), the object
is zero-initialized and then it is default-initialized if it has a
non-trivial default constructor
Unfortunately, MSVC always calls the default constructor, even if it
is trivial, which breaks constexpr-ness.
To workaround this, we're always zero-initializing TVecN<>
Also removed constexpr from default constructors, since they never can
be constexpr as they're not initializing the vector.
This is a similar fix to the previous vector fix. Commutative
operations now always return the same type and the operations are
carried out in the precision resulting from following traditional
C++ rules.
It used to be that operations e.g. like:
float3{} + double{} would be computed as
float3{} + float3{double{}} instead of
float3{} + double3{double{}}
I other words, when an implicit conversion was involved on the right
it would be converted to the left side’s type, possibly losing
precision.
Another problem was that swiping the operands could produce different
Results, e.g.:
float3{1} * 5.0 -> float3{5.0f}
5.0 * float3{1} -> double3{5.0}
This is no longer the case, now both expressions would return a double3.
Note:
float3 r{};
r *= 5;
Is now equivalent to:
r[0] *= 5;
r[1] *= 5;
r[2] *= 5;
Instead of before:
r[0] *= 5.0f;
r[1] *= 5.0f;
r[2] *= 5.0f;
We now follow the same rules than for basic types, when performing
mixed-precision operations, e.g.:
float3 + double3 -> double3
double3 + float3 -> double3
dot(float3, double3) -> double
In particular, e.g. swapping the arguments to arithmetic operations
now always yields to the same result type (before, float3 + double3
would not return the same type than double3 + float3).
We now inverse the face winding order based on the determinant of
each render primitive world's transform. This prevents front/back faces
to be reversed when using a left-handed basis, after transform.
Fix#1520
This is nicer because this way the methods that don't match don't
even exist. Also make it better when editing code with a C++ aware
ide.
Also use the less verbose std::enable_if_t<>
It turns out that most of libmath couldn't be used in constexpr
expression due to our use of union{}. The C++ standard requires that
all accesses to a union{} in a constexpr expression be the same
element.
Also because libm and cmath are not constexpr some functions such
as length() or normalize() can't be constexpr. The same is true for
anything needing things like sqrt, cos, sin, ceil, floor.
This change mainly does the following:
- replace all accesses to vector elements by operator[]
(this ensure all of libmath uses the same union element)
- avoid use of std::min / std::max / std::abs
- avoid uninitialized variables, which can't be constexpr
- remove 'constexpr' keyword on functions that can never be
It is now possible to write things like:
constexpr mat4f I = inverse(
transpose(mat4f::translation(float3{ 1, 2, 3 })
* mat4f::scaling(4)));
We can now use for e.g. vec4<float> instead of float4, this is
useful for templated code. The existing solution was to reach
out to the math::detail::TVec<> class.
- switched the frustum/box intersection code to double. With large
scenes, we were getting very wrong intersection points (up to 1m off).
This doesn't seem to happen with doubles.
- reject points that end-up outside the frustum
- made LiSPSM code more robust against the problem above. When points
were falsely placed behind the near plane (due to bad intersections),
we could end-up with NaN (sqrt of negative numbers).
This is our first ImGui extension, it draws a draggable 3D arrow for
manipulating a unit vector. This is especially useful for tweaking the
light direction.
In my previous NaN-related commit, I added a conditional similar to the
one seen in glMatrix, but this was insufficient for the interpolation
seen in a glTF skinning test because a divide-by-zero was occuring later
in the function. This commit simply adds back the previous protection.
These two functions expect a vector of the same size as the
matrix's storage vectors (float4 for a mat4f for instance) which
has two major issues:
- The vector must end with 1 for homogeneous coordinates to work
- Passing a single scalar (mat4f::scale(0.5)) creates a matrix
whose diagonal is set to that scalar, thus breaking homogeneous
coordinates
With this change scale and translate expect a vector who dimensionality
is 1 less that of the matrix's underlying storage vectors. i.e. a float3
for mat4f.