light: add FacePairConcavity

This commit is contained in:
Eric Wasylishen 2018-01-11 21:57:48 -07:00
parent a2db5a4ebe
commit 82e3aef283
3 changed files with 87 additions and 10 deletions

View File

@ -835,17 +835,15 @@ qvec3f ClosestPointOnLineSegment(const qvec3f &v, const qvec3f &w, const qvec3f&
} }
/// Returns degrees of clockwise rotation from start to end, assuming `normal` is pointing towards the viewer /// Returns degrees of clockwise rotation from start to end, assuming `normal` is pointing towards the viewer
float SignedDegreesBetweenUnitVectors(const vec3_t start, const vec3_t end, const vec3_t normal) float SignedDegreesBetweenUnitVectors(const qvec3f &start, const qvec3f &end, const qvec3f &normal)
{ {
const float cosangle = qmax(-1.0, qmin(1.0, DotProduct(start, end))); const float cosangle = qmax(-1.0, qmin(1.0, qv::dot(start, end)));
const float unsigned_degrees = acos(cosangle) * (360.0 / (2.0 * Q_PI)); const float unsigned_degrees = acos(cosangle) * (360.0 / (2.0 * Q_PI));
// get a normal for the rotation plane using the right-hand rule // get a normal for the rotation plane using the right-hand rule
vec3_t rotationNormal; const qvec3f rotationNormal = qv::normalize(qv::cross(start, end));
CrossProduct(start, end, rotationNormal);
VectorNormalize(rotationNormal);
const float normalsCosAngle = DotProduct(rotationNormal, normal); const float normalsCosAngle = qv::dot(rotationNormal, normal);
if (normalsCosAngle >= 0) { if (normalsCosAngle >= 0) {
// counterclockwise rotation // counterclockwise rotation
return -unsigned_degrees; return -unsigned_degrees;
@ -854,6 +852,24 @@ float SignedDegreesBetweenUnitVectors(const vec3_t start, const vec3_t end, cons
return unsigned_degrees; return unsigned_degrees;
} }
concavity_t FacePairConcavity(const qvec3f &face1Center,
const qvec3f &face1Normal,
const qvec3f &face2Center,
const qvec3f &face2Normal)
{
const qvec3f face1to2_dir = qv::normalize(face2Center - face1Center);
const qvec3f towards_viewer_dir = qv::cross(face1to2_dir, face1Normal);
const float degrees = SignedDegreesBetweenUnitVectors(face1Normal, face2Normal, towards_viewer_dir);
if (fabs(degrees) < DEGREES_EPSILON) {
return concavity_t::Coplanar;
} else if (degrees < 0.0f) {
return concavity_t::Concave;
} else {
return concavity_t::Convex;
}
}
/** /**
* do the line segments overlap at all? * do the line segments overlap at all?
* - if not colinear, returns false. * - if not colinear, returns false.

View File

@ -60,6 +60,7 @@ extern const vec3_t vec3_origin;
#define POINT_EQUAL_EPSILON 0.05f #define POINT_EQUAL_EPSILON 0.05f
#define NORMAL_EPSILON 0.000001 #define NORMAL_EPSILON 0.000001
#define DEGREES_EPSILON 0.001
qboolean VectorCompare(const vec3_t v1, const vec3_t v2, vec_t epsilon); qboolean VectorCompare(const vec3_t v1, const vec3_t v2, vec_t epsilon);
@ -367,7 +368,18 @@ float DistToLineSegment(const qvec3f &v, const qvec3f &w, const qvec3f &p);
qvec3f ClosestPointOnLineSegment(const qvec3f &v, const qvec3f &w, const qvec3f &p); qvec3f ClosestPointOnLineSegment(const qvec3f &v, const qvec3f &w, const qvec3f &p);
float SignedDegreesBetweenUnitVectors(const vec3_t start, const vec3_t end, const vec3_t normal); float SignedDegreesBetweenUnitVectors(const qvec3f &start, const qvec3f &end, const qvec3f &normal);
enum class concavity_t {
Coplanar,
Concave,
Convex
};
concavity_t FacePairConcavity(const qvec3f &face1Center,
const qvec3f &face1Normal,
const qvec3f &face2Center,
const qvec3f &face2Normal);
// Returns weights for f(0,0), f(1,0), f(0,1), f(1,1) // Returns weights for f(0,0), f(1,0), f(0,1), f(1,1)
// from: https://en.wikipedia.org/wiki/Bilinear_interpolation#Unit_Square // from: https://en.wikipedia.org/wiki/Bilinear_interpolation#Unit_Square

View File

@ -422,15 +422,64 @@ TEST(mathlib, ShrinkPoly2) {
} }
TEST(mathlib, SignedDegreesBetweenUnitVectors) { TEST(mathlib, SignedDegreesBetweenUnitVectors) {
const vec3_t up = {0, 0, 1}; const qvec3f up {0, 0, 1};
const vec3_t fwd = {0, 1, 0}; const qvec3f fwd {0, 1, 0};
const vec3_t right = {1, 0, 0}; const qvec3f right {1, 0, 0};
EXPECT_FLOAT_EQ(-90, SignedDegreesBetweenUnitVectors(right, fwd, up)); EXPECT_FLOAT_EQ(-90, SignedDegreesBetweenUnitVectors(right, fwd, up));
EXPECT_FLOAT_EQ(90, SignedDegreesBetweenUnitVectors(fwd, right, up)); EXPECT_FLOAT_EQ(90, SignedDegreesBetweenUnitVectors(fwd, right, up));
EXPECT_FLOAT_EQ(0, SignedDegreesBetweenUnitVectors(right, right, up)); EXPECT_FLOAT_EQ(0, SignedDegreesBetweenUnitVectors(right, right, up));
} }
TEST(mathlib, ConcavityTest_concave) {
const qvec3f face1center {0, 0, 10};
const qvec3f face2center {10, 0, 200};
const qvec3f face1normal {0, 0, 1};
const qvec3f face2normal {-1, 0, 0};
EXPECT_EQ(concavity_t::Concave, FacePairConcavity(face1center, face1normal, face2center, face2normal));
}
TEST(mathlib, ConcavityTest_concave2) {
const qvec3f face1center {0, 0, 10};
const qvec3f face2center {-10, 0, 200};
const qvec3f face1normal {0, 0, 1};
const qvec3f face2normal {1, 0, 0};
EXPECT_EQ(concavity_t::Concave, FacePairConcavity(face1center, face1normal, face2center, face2normal));
}
TEST(mathlib, ConcavityTest_convex) {
const qvec3f face1center {0, 0, 10};
const qvec3f face2center {10, 0, 5};
const qvec3f face1normal {0, 0, 1};
const qvec3f face2normal {1, 0, 0};
EXPECT_EQ(concavity_t::Convex, FacePairConcavity(face1center, face1normal, face2center, face2normal));
}
TEST(mathlib, ConcavityTest_convex2) {
const qvec3f face1center {0, 0, 10};
const qvec3f face2center {-10, 0, 5};
const qvec3f face1normal {0, 0, 1};
const qvec3f face2normal {-1, 0, 0};
EXPECT_EQ(concavity_t::Convex, FacePairConcavity(face1center, face1normal, face2center, face2normal));
}
TEST(mathlib, ConcavityTest_coplanar) {
const qvec3f face1center {0, 0, 10};
const qvec3f face2center {100, 100, 10};
const qvec3f face1normal {0, 0, 1};
const qvec3f face2normal {0, 0, 1};
EXPECT_EQ(concavity_t::Coplanar, FacePairConcavity(face1center, face1normal, face2center, face2normal));
}
static const float MANGLE_EPSILON = 0.1f; static const float MANGLE_EPSILON = 0.1f;
TEST(light, vec_from_mangle) { TEST(light, vec_from_mangle) {