common: add GLM_InterpolateNormal
This commit is contained in:
parent
8ed7544063
commit
b54f893942
|
|
@ -314,6 +314,20 @@ glm::vec4 GLM_PolyPlane(const std::vector<glm::vec3> &points)
|
|||
return vec4(normal, dist);
|
||||
}
|
||||
|
||||
std::pair<bool, vec4>
|
||||
GLM_MakeEdgePlane(const vec3 &v0, const vec3 &v1, const vec3 &faceNormal)
|
||||
{
|
||||
const float v0v1len = length(v1-v0);
|
||||
if (v0v1len < POINT_EQUAL_EPSILON)
|
||||
return make_pair(false, vec4(0));
|
||||
|
||||
const vec3 edgedir = (v1 - v0) / v0v1len;
|
||||
const vec3 edgeplane_normal = cross(edgedir, faceNormal);
|
||||
const float edgeplane_dist = dot(edgeplane_normal, v0);
|
||||
|
||||
return make_pair(true, vec4(edgeplane_normal, edgeplane_dist));
|
||||
}
|
||||
|
||||
vector<vec4>
|
||||
GLM_MakeInwardFacingEdgePlanes(std::vector<vec3> points)
|
||||
{
|
||||
|
|
@ -331,15 +345,11 @@ GLM_MakeInwardFacingEdgePlanes(std::vector<vec3> points)
|
|||
const vec3 v0 = points.at(i);
|
||||
const vec3 v1 = points.at((i+1) % points.size());
|
||||
|
||||
const float v0v1len = length(v1-v0);
|
||||
if (v0v1len < POINT_EQUAL_EPSILON)
|
||||
const auto edgeplane = GLM_MakeEdgePlane(v0, v1, faceNormal);
|
||||
if (!edgeplane.first)
|
||||
continue;
|
||||
|
||||
const vec3 edgedir = (v1 - v0) / v0v1len;
|
||||
const vec3 edgeplane_normal = cross(edgedir, faceNormal);
|
||||
const float edgeplane_dist = dot(edgeplane_normal, v0);
|
||||
|
||||
result.push_back(vec4(edgeplane_normal, edgeplane_dist));
|
||||
result.push_back(edgeplane.second);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -436,4 +446,37 @@ std::pair<int, glm::vec3> GLM_ClosestPointOnPolyBoundary(const std::vector<glm::
|
|||
return make_pair(bestI, bestPointOnPoly);
|
||||
}
|
||||
|
||||
std::pair<bool, glm::vec3> GLM_InterpolateNormal(const std::vector<glm::vec3> &points,
|
||||
const std::vector<glm::vec3> &normals,
|
||||
const glm::vec3 &point)
|
||||
{
|
||||
Q_assert(points.size() == normals.size());
|
||||
|
||||
// Step through the triangles, being careful to handle zero-size ones
|
||||
|
||||
const vec3 &p0 = points.at(0);
|
||||
const vec3 &n0 = normals.at(0);
|
||||
|
||||
const int N = points.size();
|
||||
for (int i=2; i<N; i++) {
|
||||
const vec3 &p1 = points.at(i-1);
|
||||
const vec3 &n1 = normals.at(i-1);
|
||||
const vec3 &p2 = points.at(i);
|
||||
const vec3 &n2 = normals.at(i);
|
||||
|
||||
const auto edgeplanes = GLM_MakeInwardFacingEdgePlanes({p0, p1, p2});
|
||||
if (edgeplanes.empty())
|
||||
continue;
|
||||
|
||||
if (GLM_EdgePlanes_PointInside(edgeplanes, point)) {
|
||||
// Found the correct triangle
|
||||
|
||||
const vec3 bary = Barycentric_FromPoint(point, make_tuple(p0, p1, p2));
|
||||
const vec3 interpolatedNormal = Barycentric_ToPoint(bary, make_tuple(n0, n1, n2));
|
||||
|
||||
return make_pair(true, interpolatedNormal);
|
||||
}
|
||||
}
|
||||
|
||||
return make_pair(false, vec3(0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -328,5 +328,8 @@ 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);
|
||||
|
||||
/// Returns `true` and the interpolated normal if `point` is in the polygon, otherwise returns false.
|
||||
std::pair<bool, glm::vec3> GLM_InterpolateNormal(const std::vector<glm::vec3> &points,
|
||||
const std::vector<glm::vec3> &normals,
|
||||
const glm::vec3 &point);
|
||||
#endif /* __COMMON_MATHLIB_H__ */
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
#include <glm/gtc/epsilon.hpp>
|
||||
|
||||
using namespace glm;
|
||||
using namespace std;
|
||||
|
|
@ -368,3 +369,45 @@ TEST(mathlib, BarycentricRandom) {
|
|||
EXPECT_FLOAT_EQ(0.0f, GLM_DistAbovePlane(plane, point));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mathlib, InterpolateNormals) {
|
||||
// This test relies on the way GLM_InterpolateNormal is implemented
|
||||
|
||||
// o--o--o
|
||||
// | / / |
|
||||
// |// |
|
||||
// o-----o
|
||||
|
||||
const vector<vec3> poly {
|
||||
{ 0,0,0 },
|
||||
{ 0,64,0 },
|
||||
{ 32,64,0 }, // colinear
|
||||
{ 64,64,0 },
|
||||
{ 64,0,0 }
|
||||
};
|
||||
|
||||
const vector<vec3> normals {
|
||||
{ 1,0,0 },
|
||||
{ 0,1,0 },
|
||||
{ 0,0,1 }, // colinear
|
||||
{ 0,0,0 },
|
||||
{ -1,0,0 }
|
||||
};
|
||||
|
||||
// First try all the known points
|
||||
for (int i=0; i<poly.size(); i++) {
|
||||
const auto res = GLM_InterpolateNormal(poly, normals, poly.at(i));
|
||||
EXPECT_EQ(true, res.first);
|
||||
EXPECT_TRUE(all(epsilonEqual(normals.at(i), res.second, vec3(POINT_EQUAL_EPSILON))));
|
||||
}
|
||||
|
||||
{
|
||||
const vec3 firstTriCentroid = (poly[0] + poly[1] + poly[2]) / 3.0f;
|
||||
const auto res = GLM_InterpolateNormal(poly, normals, firstTriCentroid);
|
||||
EXPECT_EQ(true, res.first);
|
||||
EXPECT_TRUE(all(epsilonEqual(vec3(1/3.0f), res.second, vec3(POINT_EQUAL_EPSILON))));
|
||||
}
|
||||
|
||||
// Outside poly
|
||||
EXPECT_FALSE(GLM_InterpolateNormal(poly, normals, vec3(-0.1, 0, 0)).first);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue