- shadows are now stable (in stable mode) when an IBL rotation is
used.
- fix the shadow transform option which didn't work when an IBL rotation
was used
- also use the x-axis as a reference for the "up" direction when
computing the light space matrix so that we don't fall into the
degenerate case when the light points straight down, which is a
common case
FIXES=[299310624]
I noticed that our slerp function sometimes produces a jolt in
animation, but only when the time delta is very small, and only when the
two operands have completely opposing signs.
For example, let's say you are slerping from <0.76, 0.39, 0.51, 0.19>
to <-0.72, -0.45, -0.49, -0.17>.
These quats are actually quite near to each other because the total
negation of the second quat is similar to the first quat.
We were already doing the short path check in the proper slerp path, but
not when falling back to lerp due to a small angle.
This was tested by replacing the node 0 scale in BusterDrone with
[-1, 1, 1].
For future reference, commit f728776 shows when we switched from
transpose(inverse()) to cof(). This was a good change, but before that
particular change, we had a "two wrongs made a right" situation for
mirrored normals.
Fixes#3001.
libmath itself doesn't expose any stream operators anymore. However,
libutils is able to automatically print libmath types into its
io::ostream -- however matrices are not formatted nicely.
Added a new optional library, libmathio, that provides std::ostream
operators for all libmath types. libmathio does a better job at
formating matrices.
Also removed apply() and map() from libmath because there were not used
anywhere and they forced us to depend on <functional> in public headers.
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;
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)));
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.