Skip to content

Commit

Permalink
[Math/Vector] Normalizing a 0 vector keeps it as such
Browse files Browse the repository at this point in the history
- This avoids NaNs where they shouldn't exist
  • Loading branch information
Razakhel committed Jan 13, 2024
1 parent 39fc084 commit f689f2c
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 12 deletions.
4 changes: 2 additions & 2 deletions include/RaZ/Math/Vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ class Vector {
/// \tparam SqLengthT Type of the squared length value. For vectors of an integral type, it is defined to a large unsigned integer type to avoid overflows.
/// \return Vector's squared length.
template <typename SqLengthT = std::conditional_t<std::is_integral_v<T>, uint64_t, T>>
constexpr SqLengthT computeSquaredLength() const noexcept { return dot(*this); }
constexpr SqLengthT computeSquaredLength() const noexcept { return static_cast<SqLengthT>(dot(*this)); }
/// Computes the length of the vector.
/// Calculating the actual length requires a square root operation to be involved, which is expensive.
/// As such, this function should be used if actual length is needed; otherwise, prefer computeSquaredLength().
/// As such, this function should be used only if the actual length is needed; otherwise, prefer computeSquaredLength().
/// \tparam LengthT Type of the length value. For vectors of an integral type, it is defined to float; otherwise, it is the same as the original vector's.
/// \return Vector's length.
template <typename LengthT = std::conditional_t<std::is_integral_v<T>, float, T>>
Expand Down
6 changes: 5 additions & 1 deletion include/RaZ/Math/Vector.inl
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,12 @@ template <typename NormedT>
constexpr Vector<NormedT, Size> Vector<T, Size>::normalize() const noexcept {
static_assert(std::is_floating_point_v<NormedT>, "Error: The normalized vector's type must be floating-point.");

const NormedT sqLength = computeSquaredLength<NormedT>();
Vector<NormedT, Size> res(*this);
res /= computeLength();

if (sqLength != static_cast<NormedT>(0))
res /= std::sqrt(sqLength);

return res;
}

Expand Down
6 changes: 6 additions & 0 deletions tests/src/RaZ/Math/Vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ TEST_CASE("Vector normalization") {

CHECK(std::is_same_v<decltype(std::declval<Raz::Vec3d>().normalize()), Raz::Vec3d>);
CHECK_THAT(vec3d1.normalize(), IsNearlyEqualToVector(Raz::Vec3d(-0.0037504754254997, 0.9846554128425506, -0.174469630291203)));

// Normalizing a 0 vector returns it as is
CHECK(Raz::Vec3b(0).normalize() == Raz::Vec3f(0.f));
CHECK(Raz::Vec3i(0).normalize() == Raz::Vec3f(0.f));
CHECK(Raz::Vec3f(0.f).normalize() == Raz::Vec3f(0.f));
CHECK(Raz::Vec3d(0.0).normalize() == Raz::Vec3d(0.f));
}

TEST_CASE("Vector interpolation") {
Expand Down
14 changes: 5 additions & 9 deletions tests/src/RaZ/Render/Camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,11 @@ TEST_CASE("Camera look-at") {

const Raz::Mat4f& viewMat = camera.computeLookAt(Raz::Vec3f(0.f));

// If target == position, creates a look-at matrix filled with NaNs:
// [ nan, nan, nan, nan ]
// [ nan, nan, nan, nan ]
// [ nan, nan, nan, nan ]
// [ 0, 0, 0, 1 ]
for (std::size_t widthIndex = 0; widthIndex < 4; ++widthIndex) {
for (std::size_t heightIndex = 0; heightIndex < 3; ++heightIndex)
CHECK(std::isnan(viewMat.getElement(widthIndex, heightIndex)));
}
// If target == position, creates a look-at matrix filled with 0s except for the last row
CHECK(viewMat.strictlyEquals(Raz::Mat4f(0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 1.f)));

camera.setTarget(Raz::Vec3f(0.f, 0.f, -1.f));
camera.computeLookAt(Raz::Vec3f(0.f));
Expand Down

0 comments on commit f689f2c

Please sign in to comment.