diff --git a/include/RaZ/Math/Vector.hpp b/include/RaZ/Math/Vector.hpp index dc74319c..e03bed1a 100644 --- a/include/RaZ/Math/Vector.hpp +++ b/include/RaZ/Math/Vector.hpp @@ -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 , uint64_t, T>> - constexpr SqLengthT computeSquaredLength() const noexcept { return dot(*this); } + constexpr SqLengthT computeSquaredLength() const noexcept { return static_cast(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 , float, T>> diff --git a/include/RaZ/Math/Vector.inl b/include/RaZ/Math/Vector.inl index 00d0204e..26c17df9 100644 --- a/include/RaZ/Math/Vector.inl +++ b/include/RaZ/Math/Vector.inl @@ -103,8 +103,12 @@ template constexpr Vector Vector::normalize() const noexcept { static_assert(std::is_floating_point_v, "Error: The normalized vector's type must be floating-point."); + const NormedT sqLength = computeSquaredLength(); Vector res(*this); - res /= computeLength(); + + if (sqLength != static_cast(0)) + res /= std::sqrt(sqLength); + return res; } diff --git a/tests/src/RaZ/Math/Vector.cpp b/tests/src/RaZ/Math/Vector.cpp index 4137d007..3ccfc6de 100644 --- a/tests/src/RaZ/Math/Vector.cpp +++ b/tests/src/RaZ/Math/Vector.cpp @@ -265,6 +265,12 @@ TEST_CASE("Vector normalization") { CHECK(std::is_same_v().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") { diff --git a/tests/src/RaZ/Render/Camera.cpp b/tests/src/RaZ/Render/Camera.cpp index a35462ca..ad5f2b79 100644 --- a/tests/src/RaZ/Render/Camera.cpp +++ b/tests/src/RaZ/Render/Camera.cpp @@ -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));