remove vertex rounding

fix vertex hash not including negative axis points
use angle instead of zero-area triangle
This commit is contained in:
Jonathan 2022-07-13 04:35:42 -04:00
parent cfb1bf0d2c
commit d9dc54d267
5 changed files with 35 additions and 32 deletions

View File

@ -35,7 +35,9 @@ struct face_t;
class mapentity_t;
struct tree_t;
bool WindingIsTiny(const winding_t &w, double size = 0.2);
constexpr vec_t EDGE_LENGTH_EPSILON = 0.2;
bool WindingIsTiny(const winding_t &w, double size = EDGE_LENGTH_EPSILON);
std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds);
std::unique_ptr<tree_t> BrushBSP(std::vector<std::unique_ptr<bspbrush_t>> brushlist);

View File

@ -177,10 +177,10 @@ struct mapdata_t
{
// insert each vert at floor(pos[axis]) and floor(pos[axis]) + 1 (for each axis)
// so e.g. a vert at (0.99, 0.99, 0.99) shows up if we search at (1.01, 1.01, 1.01)
// this is a bit wasteful, since it inserts 8 copies of each vert.
for (int32_t x = 0; x <= 1; x++) {
for (int32_t y = 0; y <= 1; y++) {
for (int32_t z = 0; z <= 1; z++) {
// this is a bit wasteful..
for (int32_t x = -1; x <= 1; x++) {
for (int32_t y = -1; y <= 1; y++) {
for (int32_t z = -1; z <= 1; z++) {
const qvec3i h{floor(point[0]) + x, floor(point[1]) + y, floor(point[2]) + z};
hashverts[h].push_front({ point, num });
}

View File

@ -355,12 +355,8 @@ Returns true if the winding would be crunched out of
existance by the vertex snapping.
================
*/
#define EDGE_LENGTH 0.2
bool WindingIsTiny(const winding_t &w, double size)
{
#if 0
return w.area() < size;
#else
int edges = 0;
for (size_t i = 0; i < w.size(); i++) {
size_t j = (i + 1) % w.size();
@ -372,7 +368,6 @@ bool WindingIsTiny(const winding_t &w, double size)
}
}
return true;
#endif
}
/*
@ -386,9 +381,10 @@ from basewinding for plane
bool WindingIsHuge(const winding_t &w)
{
for (size_t i = 0; i < w.size(); i++) {
for (size_t j = 0; j < 3; j++)
for (size_t j = 0; j < 3; j++) {
if (fabs(w[i][j]) > qbsp_options.worldextent.value())
return true;
}
}
return false;
}

View File

@ -54,20 +54,10 @@ static void MergeNodeFaces(node_t *node)
/*
=============
EmitVertex
NOTE: modifies input to be rounded!
=============
*/
inline void EmitVertex(qvec3d &vert, size_t &vert_id)
inline void EmitVertex(const qvec3d &vert, size_t &vert_id)
{
// if we're extremely close to an integral point,
// snap us to it.
for (auto &v : vert) {
double rounded = Q_rint(v);
if (fabs(v - rounded) < ZERO_EPSILON) {
v = rounded;
}
}
// already added
if (auto v = map.find_emitted_hash_vector(vert)) {
vert_id = *v;
@ -80,7 +70,7 @@ inline void EmitVertex(qvec3d &vert, size_t &vert_id)
map.bsp.dvertexes.emplace_back(vert);
}
// snap windings & output final vertices
// output final vertices
static void EmitFaceVertices(face_t *f)
{
if (ShouldOmitFace(f)) {

View File

@ -60,7 +60,7 @@ TestEdge
Can be recursively reentered
==========
*/
inline void TestEdge (vec_t start, vec_t end, size_t p1, size_t p2, size_t startvert, const std::vector<size_t> &edge_verts, const qvec3d &edge_start, const qvec3d &edge_dir, std::vector<size_t> &superface)
inline void TestEdge(vec_t start, vec_t end, size_t p1, size_t p2, size_t startvert, const std::vector<size_t> &edge_verts, const qvec3d &edge_start, const qvec3d &edge_dir, std::vector<size_t> &superface)
{
if (p1 == p2) {
// degenerate edge
@ -194,12 +194,27 @@ inline void SplitFaceIntoFragments(std::vector<size_t> &superface, std::vector<s
}
}
inline bool IsZeroAreaTriangle(size_t v0, size_t v1, size_t v2)
float AngleOfTriangle(const qvec3d &a, const qvec3d &b, const qvec3d &c)
{
qvec3d d1 = map.bsp.dvertexes[v2] - map.bsp.dvertexes[v0];
qvec3d d2 = map.bsp.dvertexes[v1] - map.bsp.dvertexes[v0];
vec_t total = 0.5 * qv::length(qv::cross(d1, d2));
return total < ZERO_TRI_AREA_EPSILON;
vec_t num = (b[0]-a[0])*(c[0]-a[0])+(b[1]-a[1])*(c[1]-a[1])+(b[2]-a[2])*(c[2]-a[2]);
vec_t den = sqrt(pow((b[0]-a[0]),2)+pow((b[1]-a[1]),2)+pow((b[2]-a[2]),2))*
sqrt(pow((c[0]-a[0]),2)+pow((c[1]-a[1]),2)+pow((c[2]-a[2]),2));
return acos(num / den) * (180.0 / 3.141592653589793238463);
}
// Check whether the given input triangle would be valid
// on the given face and not have any other points
// intersecting it.
inline bool TriangleIsValid(size_t v0, size_t v1, size_t v2, const std::vector<size_t> &face, float angle_epsilon)
{
if (AngleOfTriangle(map.bsp.dvertexes[v0], map.bsp.dvertexes[v1], map.bsp.dvertexes[v2]) < angle_epsilon ||
AngleOfTriangle(map.bsp.dvertexes[v1], map.bsp.dvertexes[v2], map.bsp.dvertexes[v0]) < angle_epsilon ||
AngleOfTriangle(map.bsp.dvertexes[v2], map.bsp.dvertexes[v0], map.bsp.dvertexes[v1]) < angle_epsilon) {
return false;
}
return true;
}
/*
@ -274,7 +289,7 @@ static std::vector<std::vector<size_t>> RetopologizeFace(const std::vector<size_
end = (seed + 2) % input.size();
auto v2 = input[end];
if (IsZeroAreaTriangle(v0, v1, v2)) {
if (!TriangleIsValid(v0, v1, v2, input, 0.01)) {
continue;
}
@ -421,7 +436,7 @@ static void FixFaceEdges(node_t *headnode, node_t *node, face_t *f)
}
// brute force rotating the start point until we find a valid winding
// that doesn't have any zero-area triangles
// that doesn't have any T-junctions
size_t i = 0;
for (; i < superface.size(); i++) {
@ -433,7 +448,7 @@ static void FixFaceEdges(node_t *headnode, node_t *node, face_t *f)
auto v1 = superface[(i + x + 1) % superface.size()];
auto v2 = superface[(i + x + 2) % superface.size()];
if (IsZeroAreaTriangle(v0, v1, v2)) {
if (!TriangleIsValid(v0, v1, v2, superface, 0.01)) {
break;
}
}