Browse Source

Math: add reflect() and refract() functions.

Co-authored-by: Vladimír Vondruš <mosra@centrum.cz>
pull/388/merge
Nghia Truong 6 years ago committed by Vladimír Vondruš
parent
commit
1ef813fdad
  1. 52
      src/Magnum/Math/Functions.h
  2. 3
      src/Magnum/Math/Matrix3.h
  3. 3
      src/Magnum/Math/Matrix4.h
  4. 1
      src/Magnum/Math/Test/CMakeLists.txt
  5. 58
      src/Magnum/Math/Test/FunctionsTest.cpp

52
src/Magnum/Math/Functions.h

@ -654,6 +654,58 @@ template<std::size_t size, class T> inline Vector<size, T> sqrtInverted(const Ve
return Vector<size, T>(T(1))/Math::sqrt(a);
}
/**
@brief Reflect a vector
@m_since_latest
Reflects the vector off a surface given the surface outward normal. Expects
that the normal vector is normalized. For a vector @f$ \boldsymbol{v} @f$ and a
normal @f$ \boldsymbol{n} @f$, the reflection vector @f$ \boldsymbol{r} @f$ is
calculated as: @f[
\boldsymbol{r} = \boldsymbol{v} - 2 (\boldsymbol{n} \cdot \boldsymbol{v}) \boldsymbol{n}
@f]
@see @ref dot(const Vector<size, T>&, const Vector<size, T>&), @ref refract(),
@ref Vector::isNormalized(), @ref Matrix3::reflection(),
@ref Matrix4::reflection()
*/
template<std::size_t size, class T> inline Vector<size, T> reflect(const Vector<size, T>& vector, const Vector<size, T>& normal) {
CORRADE_ASSERT(normal.isNormalized(),
"Math::reflect(): normal" << normal << "is not normalized", {});
return vector - T(2.0)*dot(vector, normal)*normal;
}
/**
@brief Refract a vector
@m_since_latest
Refracts a vector through a medium given the surface outward normal and ratio
of indices of refraction eta. Expects that both @p vector and @p normal is
normalized. For a vector @f$ \boldsymbol{v} @f$, normal @f$ \boldsymbol{n} @f$
and a ratio of indices of refraction @f$ \eta @f$, the refraction vector
@f$ \boldsymbol{r} @f$ is calculated as: @f[
\begin{array}{rcl}
\eta & = & \cfrac{\text{IOR}_\text{source}}{\text{IOR}_\text{destination}} \\[10pt]
k & = & 1 - \eta^2 (1 - (\boldsymbol{n} \cdot \boldsymbol{v})^2) \\
\boldsymbol{r} & = & \begin{cases}
\boldsymbol{0}, & \text{if} ~ k < 0 \\
\eta \boldsymbol{v} - (\eta (\boldsymbol{n} \cdot \boldsymbol{v}) + \sqrt{k}) \boldsymbol{n}, & \text{if} ~ k \ge 0
\end{cases}
\end{array}
@f]
Wikipedia has a [List of refractive indices](https://en.wikipedia.org/wiki/List_of_refractive_indices).
@see @ref dot(const Vector<size, T>&, const Vector<size, T>&), @ref reflect(),
@ref Vector::isNormalized()
*/
template<std::size_t size, class T> inline Vector<size, T> refract(const Vector<size, T>& vector, const Vector<size, T>& normal, T eta) {
CORRADE_ASSERT(vector.isNormalized() && normal.isNormalized(),
"Math::refract(): vectors" << vector << "and" << normal << "are not normalized", {});
const T dot = Math::dot(vector, normal);
const T k = T(1.0) - eta*eta*(T(1.0) - dot*dot);
if(k < T(0.0)) return {};
return eta*vector - (eta*dot + std::sqrt(k))*normal;
}
/*@}*/
}}

3
src/Magnum/Math/Matrix3.h

@ -113,7 +113,8 @@ template<class T> class Matrix3: public Matrix3x3<T> {
* @cpp Matrix3::scaling(Vector2::yScale(-1.0f)) @ce. @f[
* \boldsymbol{A} = \boldsymbol{I} - 2 \boldsymbol{NN}^T ~~~~~ \boldsymbol{N} = \begin{pmatrix} n_x \\ n_y \end{pmatrix}
* @f]
* @see @ref Matrix4::reflection(), @ref Vector::isNormalized()
* @see @ref Matrix4::reflection(), @ref Vector::isNormalized(),
* @ref reflect()
*/
static Matrix3<T> reflection(const Vector2<T>& normal) {
CORRADE_ASSERT(normal.isNormalized(),

3
src/Magnum/Math/Matrix4.h

@ -183,7 +183,8 @@ template<class T> class Matrix4: public Matrix4x4<T> {
* @cpp Matrix4::scaling(Vector3::yScale(-1.0f)) @ce. @f[
* \boldsymbol{A} = \boldsymbol{I} - 2 \boldsymbol{NN}^T ~~~~~ \boldsymbol{N} = \begin{pmatrix} n_x \\ n_y \\ n_z \end{pmatrix}
* @f]
* @see @ref Matrix3::reflection(), @ref Vector::isNormalized()
* @see @ref Matrix3::reflection(), @ref Vector::isNormalized(),
* @ref reflect()
*/
static Matrix4<T> reflection(const Vector3<T>& normal);

1
src/Magnum/Math/Test/CMakeLists.txt

@ -78,6 +78,7 @@ set_property(TARGET
MathCubicHermiteTest
MathDualComplexTest
MathFrustumTest
MathFunctionsTest
MathQuaternionTest
MathDualQuaternionTest

58
src/Magnum/Math/Test/FunctionsTest.cpp

@ -23,8 +23,10 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Numeric.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Math/Functions.h"
#include "Magnum/Math/Vector4.h"
@ -69,6 +71,11 @@ struct FunctionsTest: Corrade::TestSuite::Tester {
void isNan();
void isNanfVector();
void reflect();
void reflectNotNormalized();
void refract();
void refractNotNormalized();
void trigonometric();
void trigonometricWithBase();
template<class T> void sincos();
@ -125,6 +132,11 @@ FunctionsTest::FunctionsTest() {
&FunctionsTest::isNan,
&FunctionsTest::isNanfVector,
&FunctionsTest::reflect,
&FunctionsTest::reflectNotNormalized,
&FunctionsTest::refract,
&FunctionsTest::refractNotNormalized,
&FunctionsTest::trigonometric,
&FunctionsTest::trigonometricWithBase,
&FunctionsTest::sincos<Float>,
@ -440,6 +452,52 @@ void FunctionsTest::isNanfVector() {
CORRADE_COMPARE(Math::isNan(Vector3{0.3f, -Constants::inf(), 1.0f}), Math::BoolVector<3>{0x00});
}
void FunctionsTest::reflect() {
/* Reflection along Y will simply flip the Y component */
CORRADE_COMPARE(Math::reflect(
Vector3{1.0f, 2.0f, 3.0f},
Vector3::yAxis()),
(Vector3{1.0f, -2.0f, 3.0f}));
CORRADE_COMPARE(Math::reflect(
Vector3{2.0f, 1.0f, 1.0f},
Vector3{1.0f, -1.0f, 1.0f}.normalized()),
(Vector3{0.666667f, 2.33333f, -0.333333f}));
}
void FunctionsTest::reflectNotNormalized() {
std::ostringstream out;
Error redirectError{&out};
Math::reflect(Vector3{}, Vector3{1.0f});
CORRADE_COMPARE(out.str(),
"Math::reflect(): normal Vector(1, 1, 1) is not normalized\n");
}
void FunctionsTest::refract() {
CORRADE_COMPARE(Math::refract(
Vector3{1.0f, 0.0f, 1.0f}.normalized(),
Vector3{0.0f, 0.0f, -1.0f}, 1.0f/1.5f),
(Vector3{0.471405f, 0.0f, 0.881917f}));
CORRADE_COMPARE(Math::refract(
Vector3{4.0f, 1.0f, 1.0f}.normalized(),
Vector3{0.0f, -2.0f, -1.0f}.normalized(), 1.0f/1.5f),
(Vector3{0.628539f, 0.661393f, 0.409264f}));
/* Total absorption */
CORRADE_COMPARE(Math::refract(
Vector3{1.0f, 0.1f, 0.0f}.normalized(),
Vector3::yAxis(), 1.5f),
Vector3{0.0f});
}
void FunctionsTest::refractNotNormalized() {
std::ostringstream out;
Error redirectError{&out};
Math::refract(Vector3{}, Vector3{1.0f}, 0.0f);
CORRADE_COMPARE(out.str(),
"Math::refract(): vectors Vector(0, 0, 0) and Vector(1, 1, 1) are not normalized\n");
}
void FunctionsTest::trigonometric() {
CORRADE_COMPARE(Math::sin(Deg(30.0f)), 0.5f);
CORRADE_COMPARE(Math::sin(Rad(Constants::pi()/6)), 0.5f);

Loading…
Cancel
Save