Skip to content

Commit

Permalink
Add unit test for increasing W along target vector
Browse files Browse the repository at this point in the history
W coordinate increases from 0 at the projected light apex to 1 at the target
plane.
  • Loading branch information
Matthew Mott committed Mar 17, 2021
1 parent c3dfa16 commit 31e7f01
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 40 deletions.
53 changes: 28 additions & 25 deletions libs/math/Vector3.h
Expand Up @@ -195,27 +195,6 @@ class BasicVector3
return *this;
}

/* Define the multiplications * and *= with a scalar
*/
template<typename OtherElement>
BasicVector3<Element> operator* (const OtherElement& other) const {
Element factor = static_cast<Element>(other);
return BasicVector3<Element>(
_v[0] * factor,
_v[1] * factor,
_v[2] * factor
);
}

template<typename OtherElement>
BasicVector3<Element>& operator*= (const OtherElement& other) {
Element factor = static_cast<Element>(other);
_v[0] *= factor;
_v[1] *= factor;
_v[2] *= factor;
return *this;
}

/* Define the division operators / and /= with another Vector3 of type OtherElement
* The vectors are divided element-wise
*/
Expand Down Expand Up @@ -300,7 +279,7 @@ class BasicVector3
_v[0] *= inverseLength;
_v[1] *= inverseLength;
_v[2] *= inverseLength;

return length;
}

Expand Down Expand Up @@ -402,7 +381,7 @@ class BasicVector3
template<typename OtherT>
bool isParallel(const BasicVector3<OtherT>& other) const
{
return float_equal_epsilon(angle(other), 0.0, 0.001) ||
return float_equal_epsilon(angle(other), 0.0, 0.001) ||
float_equal_epsilon(angle(other), c_pi, 0.001);
}

Expand All @@ -425,8 +404,8 @@ class BasicVector3
template<typename OtherElement, typename Epsilon>
bool isEqual(const BasicVector3<OtherElement>& other, Epsilon epsilon) const
{
return float_equal_epsilon(x(), other.x(), epsilon) &&
float_equal_epsilon(y(), other.y(), epsilon) &&
return float_equal_epsilon(x(), other.x(), epsilon) &&
float_equal_epsilon(y(), other.y(), epsilon) &&
float_equal_epsilon(z(), other.z(), epsilon);
}

Expand Down Expand Up @@ -473,6 +452,30 @@ class BasicVector3
}
};

/// Multiply vector components with a scalar and return the result
template <typename T, typename S>
BasicVector3<T> operator*(const BasicVector3<T>& v, S s)
{
T factor = static_cast<T>(s);
return BasicVector3<T>(v.x() * factor, v.y() * factor, v.z() * factor);
}

/// Multiply vector components with a scalar and return the result
template <typename T>
BasicVector3<T> operator*(T s, const BasicVector3<T>& v)
{
return v * s;
}

/// Multiply vector components with a scalar and modify in place
template <typename T, typename S>
BasicVector3<T>& operator*=(BasicVector3<T>& v, S other)
{
T factor = static_cast<T>(other);
v.set(v.x() * factor, v.y() * factor, v.z() * factor);
return v;
}

/// Stream insertion for BasicVector3
template<typename T>
inline std::ostream& operator<<(std::ostream& st, BasicVector3<T> vec)
Expand Down
43 changes: 28 additions & 15 deletions test/Renderer.cpp
Expand Up @@ -16,6 +16,9 @@ IEntityNodePtr createByClassName(const std::string& className)
return GlobalEntityModule().createEntity(cls);
}

using V4 = Vector4;
using V3 = Vector3;

// Wrapper for a light entity and its respective node interfaces
struct Light
{
Expand All @@ -41,16 +44,16 @@ struct Light
}

// Construct a light with a specified radius and default origin
static Light withRadius(const Vector3& radius)
static Light withRadius(const V3& radius)
{
Light light;
light.entity->setKeyValue("light_radius", string::to_string(radius));
return light;
}

// Construct a projected light with specified vectors
static Light projected(const Vector3& target, const Vector3& right,
const Vector3& up)
static Light projected(const V3& target, const V3& right,
const V3& up)
{
Light light;
light.entity->setKeyValue("light_target", string::to_string(target));
Expand All @@ -70,7 +73,7 @@ TEST_F(RendererTest, CreateLightNode)

TEST_F(RendererTest, GetLightTextureTransform)
{
Vector3 SIZE(10, 128, 1002);
V3 SIZE(10, 128, 1002);
Light light = Light::withRadius(SIZE);

// Get the texture matrix transform
Expand All @@ -88,13 +91,13 @@ TEST_F(RendererTest, GetLightTextureTransform)
TEST_F(RendererTest, UpdateLightRadius)
{
// Set initial radius
Light light = Light::withRadius(Vector3(256, 64, 512));
Light light = Light::withRadius(V3(256, 64, 512));

// Save initial matrix
const Matrix4 initMat = light.getMatrix();

// Change the light radius
Vector3 SIZE(92, 100, 64);
V3 SIZE(92, 100, 64);
light.entity->setKeyValue("light_radius", string::to_string(SIZE));

// Matrix should have changed from its initial value
Expand All @@ -110,7 +113,7 @@ TEST_F(RendererTest, UpdateLightRadius)

TEST_F(RendererTest, LightCenterDoesNotAffectMatrix)
{
Vector3 SIZE(100, 128, 2046);
V3 SIZE(100, 128, 2046);
Light light = Light::withRadius(SIZE);

// Store initial matrix
Expand All @@ -129,17 +132,17 @@ TEST_F(RendererTest, LightCenterDoesNotAffectMatrix)

TEST_F(RendererTest, LightMatrixInWorldSpace)
{
const Vector3 RADIUS(32, 32, 32);
const V3 RADIUS(32, 32, 32);
Light light = Light::withRadius(RADIUS);

// Set an origin
const Vector3 ORIGIN(128, 64, -192);
const V3 ORIGIN(128, 64, -192);
light.entity->setKeyValue("origin", string::to_string(ORIGIN));

// Light matrix should subtract the origin scaled to the light bounds (twice
// the radius), then add the 0.5 offset to get to [0, 1].
Matrix4 texMat = light.getMatrix();
const Vector3 BOUNDS = RADIUS * 2;
const V3 BOUNDS = RADIUS * 2;
EXPECT_EQ(
texMat,
Matrix4::byRows(0.5 / RADIUS.x(), 0, 0, 0.5 - ORIGIN.x() / BOUNDS.x(),
Expand All @@ -152,9 +155,7 @@ TEST_F(RendererTest, LightMatrixInWorldSpace)
TEST_F(RendererTest, SimpleProjectedLight)
{
// Create a light at the origin, pointing directly downwards
const Vector3 TARGET(0, 0, -8);
const Vector3 UP(0, 4, 0);
const Vector3 RIGHT(4, 0, 0);
const V3 TARGET(0, 0, -8), UP(0, 4, 0), RIGHT(4, 0, 0);
Light light = Light::projected(TARGET, RIGHT, UP);

// Inspect the matrix by transforming some key points into texture space.
Expand All @@ -167,8 +168,20 @@ TEST_F(RendererTest, SimpleProjectedLight)
// coordinate must go to -INF or +INF in texture space. This is achieved in
// projective space by setting the W coordinate to 0, while the X/Y/Z
// coordinates are unchanged (and irrelevant).
const Vector4 origin = texMat.transform(Vector4(0, 0, 0, 1));
EXPECT_EQ(origin, Vector4(0, 0, 0, 0));
const V4 origin = texMat.transform(V4(0, 0, 0, 1));
EXPECT_EQ(origin, V4(0, 0, 0, 0));

// Any point on the Z=0 plane should also have the same W coordinate of 0
EXPECT_EQ(texMat.transform(V4(128, 456, 0, 1)).w(), 0);
EXPECT_EQ(texMat.transform(V4(9999, -500, 0, 1)).w(), 0);
EXPECT_EQ(texMat.transform(V4(0.004, 23.3445, 0, 1)).w(), 0);

// The W coordinate should increase linearly from 0 at the origin to 1 at
// the target plane.
EXPECT_EQ(texMat.transform(V4(0.25 * TARGET)).w(), 0.25);
EXPECT_EQ(texMat.transform(V4(0.5 * TARGET)).w(), 0.5);
EXPECT_EQ(texMat.transform(V4(0.75 * TARGET)).w(), 0.75);
EXPECT_EQ(texMat.transform(V4(TARGET)).w(), 1);
}

}

0 comments on commit 31e7f01

Please sign in to comment.