light: fix up barycentric coords code, add tests

This commit is contained in:
Eric Wasylishen 2017-02-10 17:33:10 -07:00
parent 6f72ab5eda
commit 8ed7544063
4 changed files with 115 additions and 22 deletions

View File

@ -142,11 +142,13 @@ void AABB_Grow(vec3_t mins, vec3_t maxs, const vec3_t size) {
}
}
glm::vec2 Barycentric_FromPoint(const glm::vec3 &p, const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c)
glm::vec3 Barycentric_FromPoint(const glm::vec3 &p, const tri_t &tri)
{
const glm::vec3 v0 = b - a;
const glm::vec3 v1 = c - a;
const glm::vec3 v2 = p - a;
using std::get;
const glm::vec3 v0 = get<1>(tri) - get<0>(tri);
const glm::vec3 v1 = get<2>(tri) - get<0>(tri);
const glm::vec3 v2 = p - get<0>(tri);
float d00 = glm::dot(v0, v0);
float d01 = glm::dot(v0, v1);
float d11 = glm::dot(v1, v1);
@ -155,26 +157,34 @@ glm::vec2 Barycentric_FromPoint(const glm::vec3 &p, const glm::vec3 &a, const gl
float invDenom = (d00 * d11 - d01 * d01);
invDenom = 1.0/invDenom;
glm::vec2 res((d11 * d20 - d01 * d21) * invDenom,
(d00 * d21 - d01 * d20) * invDenom);
glm::vec3 res;
res[1] = (d11 * d20 - d01 * d21) * invDenom;
res[2] = (d00 * d21 - d01 * d20) * invDenom;
res[0] = 1.0f - res[1] - res[2];
return res;
}
// from global illumination total compendium p. 12
glm::vec2 Barycentric_Random(const float r1, const float r2)
glm::vec3 Barycentric_Random(const float r1, const float r2)
{
glm::vec2 res(1.0f - sqrtf(r1),
r2 * sqrtf(r1));
glm::vec3 res;
res.x = 1.0f - sqrtf(r1);
res.y = r2 * sqrtf(r1);
res.z = 1.0f - res.x - res.y;
return res;
}
/// Evaluates the given barycentric coord for the given triangle
glm::vec3 Barycentric_ToPoint(const glm::vec2 &bary,
const glm::vec3 &a,
const glm::vec3 &b,
const glm::vec3 &c)
glm::vec3 Barycentric_ToPoint(const glm::vec3 &bary,
const tri_t &tri)
{
const glm::vec3 pt = a + (bary.s * (b - a)) + (bary.t * (c - a));
using std::get;
const glm::vec3 pt = \
(bary.x * get<0>(tri))
+ (bary.y * get<1>(tri))
+ (bary.z * get<2>(tri));
return pt;
}
@ -297,6 +307,13 @@ glm::vec3 GLM_FaceNormal(std::vector<glm::vec3> points)
return normal;
}
glm::vec4 GLM_PolyPlane(const std::vector<glm::vec3> &points)
{
const vec3 normal = GLM_FaceNormal(points);
const float dist = dot(points.at(0), normal);
return vec4(normal, dist);
}
vector<vec4>
GLM_MakeInwardFacingEdgePlanes(std::vector<vec3> points)
{

View File

@ -279,16 +279,16 @@ public:
using aabb3 = aabb<glm::vec3>;
using aabb2 = aabb<glm::vec2>;
using tri_t = std::tuple<glm::vec3, glm::vec3, glm::vec3>;
/// abc - clockwise ordered triangle
/// p - point to get the barycentric coords of
glm::vec2 Barycentric_FromPoint(const glm::vec3 &p, const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c);
glm::vec2 Barycentric_Random(const float r1, const float r2);
glm::vec3 Barycentric_FromPoint(const glm::vec3 &p, const tri_t &tri);
glm::vec3 Barycentric_Random(const float r1, const float r2);
/// Evaluates the given barycentric coord for the given triangle
glm::vec3 Barycentric_ToPoint(const glm::vec2 &bary,
const glm::vec3 &a,
const glm::vec3 &b,
const glm::vec3 &c);
glm::vec3 Barycentric_ToPoint(const glm::vec3 &bary,
const tri_t &tri);
vec_t TriangleArea(const vec3_t v0, const vec3_t v1, const vec3_t v2);
@ -325,6 +325,7 @@ glm::vec3 GLM_TriangleCentroid(const glm::vec3 &v0, const glm::vec3 &v1, const g
float GLM_TriangleArea(const glm::vec3 &v0, const glm::vec3 &v1, const glm::vec3 &v2);
float GLM_DistAbovePlane(const glm::vec4 &plane, const glm::vec3 &point);
glm::vec3 GLM_PolyCentroid(const std::vector<glm::vec3> &points);
glm::vec4 GLM_PolyPlane(const std::vector<glm::vec3> &points);
/// Returns the index of the polygon edge, and the closest point on that edge, to the given point
std::pair<int, glm::vec3> GLM_ClosestPointOnPolyBoundary(const std::vector<glm::vec3> &poly, const glm::vec3 &point);

View File

@ -251,9 +251,9 @@ struct face_tris_t {
Vertex_GetPos_E(bsp, get<1>(tri)),
Vertex_GetPos_E(bsp, get<2>(tri)));
const glm::vec2 randomBary = Barycentric_Random(Random(), Random());
const glm::vec3 randomBary = Barycentric_Random(Random(), Random());
const glm::vec3 pt = Barycentric_ToPoint(randomBary, get<0>(triPts), get<1>(triPts), get<2>(triPts));
const glm::vec3 pt = Barycentric_ToPoint(randomBary, triPts);
return pt;
}
};

View File

@ -293,3 +293,78 @@ TEST(mathlib, ClosestPointOnPolyBoundary) {
EXPECT_EQ(make_pair(0, vec3(0,0,0)), GLM_ClosestPointOnPolyBoundary(poly, vec3(-1,-1,0)));
}
TEST(mathlib, PolygonCentroid) {
// poor test.. but at least checks that the colinear point is treated correctly
const vector<vec3> poly {
{ 0,0,0 },
{ 0,32,0 }, // colinear
{ 0,64,0 },
{ 64,64,0 },
{ 64,0,0 }
};
EXPECT_EQ(vec3(32,32,0), GLM_PolyCentroid(poly));
}
TEST(mathlib, BarycentricFromPoint) {
const tri_t tri = make_tuple<vec3,vec3,vec3>( // clockwise
{ 0,0,0 },
{ 0,64,0 },
{ 64,0,0 }
);
EXPECT_EQ(vec3(1,0,0), Barycentric_FromPoint(get<0>(tri), tri));
EXPECT_EQ(vec3(0,1,0), Barycentric_FromPoint(get<1>(tri), tri));
EXPECT_EQ(vec3(0,0,1), Barycentric_FromPoint(get<2>(tri), tri));
EXPECT_EQ(vec3(0.5, 0.5, 0.0), Barycentric_FromPoint(vec3(0,32,0), tri));
EXPECT_EQ(vec3(0.0, 0.5, 0.5), Barycentric_FromPoint(vec3(32,32,0), tri));
EXPECT_EQ(vec3(0.5, 0.0, 0.5), Barycentric_FromPoint(vec3(32,0,0), tri));
}
TEST(mathlib, BarycentricToPoint) {
const tri_t tri = make_tuple<vec3,vec3,vec3>( // clockwise
{ 0,0,0 },
{ 0,64,0 },
{ 64,0,0 }
);
EXPECT_EQ(get<0>(tri), Barycentric_ToPoint(vec3(1,0,0), tri));
EXPECT_EQ(get<1>(tri), Barycentric_ToPoint(vec3(0,1,0), tri));
EXPECT_EQ(get<2>(tri), Barycentric_ToPoint(vec3(0,0,1), tri));
EXPECT_EQ(vec3(0,32,0), Barycentric_ToPoint(vec3(0.5, 0.5, 0.0), tri));
EXPECT_EQ(vec3(32,32,0), Barycentric_ToPoint(vec3(0.0, 0.5, 0.5), tri));
EXPECT_EQ(vec3(32,0,0), Barycentric_ToPoint(vec3(0.5, 0.0, 0.5), tri));
}
TEST(mathlib, BarycentricRandom) {
const tri_t tri = make_tuple<vec3,vec3,vec3>( // clockwise
{ 0,0,0 },
{ 0,64,0 },
{ 64,0,0 }
);
const auto triAsVec = vector<vec3>{get<0>(tri), get<1>(tri), get<2>(tri)};
const auto edges = GLM_MakeInwardFacingEdgePlanes(triAsVec);
const auto plane = GLM_PolyPlane(triAsVec);
for (int i=0; i<100; i++) {
const float r0 = Random();
const float r1 = Random();
ASSERT_GE(r0, 0);
ASSERT_GE(r1, 0);
ASSERT_LE(r0, 1);
ASSERT_LE(r1, 1);
const auto bary = Barycentric_Random(r0, r1);
EXPECT_FLOAT_EQ(1.0f, bary.x + bary.y + bary.z);
const vec3 point = Barycentric_ToPoint(bary, tri);
EXPECT_TRUE(GLM_EdgePlanes_PointInside(edges, point));
EXPECT_FLOAT_EQ(0.0f, GLM_DistAbovePlane(plane, point));
}
}