Fix bug in bitangent calculation - thank you AlexP

Allow `calc_sides` to skip writing outputs if they are not required, & return counts since they are constant sized
This commit is contained in:
Jonathan 2022-01-20 16:35:56 -05:00
parent 02a4463d00
commit 0cca14d1b2
4 changed files with 34 additions and 21 deletions

View File

@ -57,6 +57,7 @@ enum side_t : int8_t
SIDE_FRONT,
SIDE_BACK,
SIDE_ON,
SIDE_TOTAL,
SIDE_CROSS = -2
};

View File

@ -531,30 +531,46 @@ public:
return result;
}
// dists/sides must have (size() + 1) reserved
inline void calc_sides(const qplane3d &plane, vec_t *dists, side_t *sides, int32_t counts[3],
// dists/sides can be null, or must have (size() + 1) reserved
inline std::array<size_t, SIDE_TOTAL> calc_sides(const qplane3d &plane, vec_t *dists, side_t *sides,
const vec_t &on_epsilon = DEFAULT_ON_EPSILON) const
{
std::array<size_t, SIDE_TOTAL> counts {};
/* determine sides for each point */
size_t i;
for (i = 0; i < count; i++) {
vec_t dot = plane.distance_to(at(i));
dists[i] = dot;
if (dists) {
dists[i] = dot;
}
side_t side;
if (dot > on_epsilon)
sides[i] = SIDE_FRONT;
side = SIDE_FRONT;
else if (dot < -on_epsilon)
sides[i] = SIDE_BACK;
side = SIDE_BACK;
else
sides[i] = SIDE_ON;
side = SIDE_ON;
counts[sides[i]]++;
counts[side]++;
if (sides) {
sides[i] = side;
}
}
sides[i] = sides[SIDE_FRONT];
dists[i] = dists[SIDE_FRONT];
if (sides) {
sides[i] = sides[SIDE_FRONT];
}
if (dists) {
dists[i] = dists[SIDE_FRONT];
}
return counts;
}
/*
@ -571,9 +587,8 @@ public:
{
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (count + 1));
side_t *sides = (side_t *)alloca(sizeof(side_t) * (count + 1));
int counts[3]{};
calc_sides(plane, dists, sides, counts, on_epsilon);
std::array<size_t, SIDE_TOTAL> counts = calc_sides(plane, dists, sides, on_epsilon);
if (keepon && !counts[SIDE_FRONT] && !counts[SIDE_BACK])
return {*this, std::nullopt};

View File

@ -555,7 +555,7 @@ void CalculateVertexNormals(const mbsp_t *bsp)
// face tangent
auto t1 = TexSpaceToWorld(bsp, &f);
std::tuple<qvec3f, qvec3f> tangents(t1.col(0).xyz(), qv::normalize(qv::cross(f_norm, t1.col(0).xyz())));
std::tuple<qvec3f, qvec3f> tangents(t1.col(0).xyz(), qv::normalize(t1.col(1).xyz()));
// gather up f and neighboursToSmooth
std::vector<const mface_t *> fPlusNeighbours;
@ -573,7 +573,7 @@ void CalculateVertexNormals(const mbsp_t *bsp)
// f2 face tangent
auto t2 = TexSpaceToWorld(bsp, f2);
std::tuple<qvec3f, qvec3f> f2_tangents(t2.col(0).xyz(), qv::normalize(qv::cross(f2_norm, t2.col(0).xyz())));
std::tuple<qvec3f, qvec3f> f2_tangents(t2.col(0).xyz(), qv::normalize(t2.col(1).xyz()));
// walk the vertices of f2, and add their contribution to smoothedNormals
for (int j = 0; j < f2->numedges; j++) {

View File

@ -110,7 +110,7 @@ void SplitFace(face_t *in, const qplane3d &split, face_t **front, face_t **back)
{
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (in->w.size() + 1));
side_t *sides = (side_t *)alloca(sizeof(side_t) * (in->w.size() + 1));
int counts[3]{};
std::array<size_t, SIDE_TOTAL> counts { };
vec_t dot;
size_t i, j;
face_t *newf, *new2;
@ -128,7 +128,7 @@ void SplitFace(face_t *in, const qplane3d &split, face_t **front, face_t **back)
counts[SIDE_FRONT] = 0;
counts[SIDE_BACK] = 1;
} else {
in->w.calc_sides(split, dists, sides, counts, ON_EPSILON);
counts = in->w.calc_sides(split, dists, sides, ON_EPSILON);
}
// Plane doesn't split this face after all
@ -241,6 +241,8 @@ Faces exactly on the plane will stay inside unless overdrawn by later brush
*/
static void ClipInside(const face_t *clipface, bool precedence, face_t **inside, face_t **outside)
{
std::vector<vec_t> dists;
std::vector<side_t> sides;
face_t *face, *next, *frags[2];
const qbsp_plane_t &splitplane = map.planes[clipface->planenum];
@ -255,12 +257,7 @@ static void ClipInside(const face_t *clipface, bool precedence, face_t **inside,
*/
bool spurious_onplane = false;
{
vec_t *dists = (vec_t *)malloc(sizeof(vec_t) * (face->w.size() + 1));
side_t *sides = (side_t *)malloc(sizeof(side_t) * (face->w.size() + 1));
int counts[3]{};
face->w.calc_sides(splitplane, dists, sides, counts, ON_EPSILON);
free(dists);
free(sides);
std::array<size_t, SIDE_TOTAL> counts = face->w.calc_sides(splitplane, nullptr, nullptr, ON_EPSILON);
if (counts[SIDE_ON] && !counts[SIDE_FRONT] && !counts[SIDE_BACK]) {
spurious_onplane = true;