Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RENDERER: Add option to filter out collinear vertices. #940

Merged
merged 1 commit into from
Sep 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions help_variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -15627,6 +15627,23 @@
"remarks": "See also: r_nearclip.",
"type": "float"
},
"r_remove_collinear_vertices": {
"default": "0",
"desc": "Filter out vertices causing triangles to have zero area. These types of triangles are a sore spot in some GPUs that risk introducing glitches. An expected side effect is a risk of seeing a sparkling pixel.",
"group-id": "35",
"remarks": "For macOS arm64 this is force-enabled to prevent cheating. This filtering is a temporary workaround before adding code to avoid generating such triangles in the first place.",
"type": "boolean",
"values": [
{
"description": "Disable filtering of collinear vertices.",
"name": "false"
},
{
"description": "Enable filtering of collinear vertices.",
"name": "true"
}
]
},
"r_fastsky": {
"default": "0",
"group-id": "51",
Expand Down
60 changes: 59 additions & 1 deletion src/r_lightmaps.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,9 +590,56 @@ static int LightmapAllocBlock(int w, int h, int *x, int *y)
return LightmapAllocBlock(w, h, x, y);
}

#define EPSILON 1e-6

// Check if triangle has a ~zero area
// https://en.wikipedia.org/wiki/Collinearity
static qbool R_ArePointsColinear(const vec3_t v1, const vec3_t v2, const vec3_t v3)
{
vec3_t d0, d1, cross;

VectorSubtract(v2, v1, d0);
VectorSubtract(v3, v2, d1);

CrossProduct(d0, d1, cross);

return DotProduct(cross, cross) < EPSILON;
}

static void R_RemoveColinearVertices(glpoly_t *poly, float new_verts[][VERTEXSIZE])
{
int i, v1_index, v2_index, v3_index, new_numverts = 0;
int numverts = poly->numverts;

v1_index = numverts - 1;
v2_index = 0;
v3_index = 1;

for (i = 0; i < numverts; i++) {
float *v1 = poly->verts[v1_index];
float *v2 = poly->verts[v2_index];
float *v3 = poly->verts[v3_index];

if (!R_ArePointsColinear(v1, v2, v3)) {
memcpy(new_verts[new_numverts], v2, sizeof(float) * VERTEXSIZE);
new_numverts++;
}

v1_index = v2_index;
v2_index = v3_index;
v3_index = (v3_index + 1) % numverts;
}

if (new_numverts > 0) {
memcpy(poly->verts, new_verts, new_numverts * sizeof(float) * VERTEXSIZE);
poly->numverts = new_numverts;
}
}

//
static void R_BuildSurfaceDisplayList(model_t* currentmodel, msurface_t *fa)
{
extern cvar_t r_remove_collinear_vertices;
int i, lindex, lnumverts;
medge_t *pedges, *r_pedge;
float *vec, s, t;
Expand Down Expand Up @@ -684,8 +731,19 @@ static void R_BuildSurfaceDisplayList(model_t* currentmodel, msurface_t *fa)
}
poly->numverts = lnumverts;

// Some GPUs misbehave if fed triangles of empty size.
if (r_remove_collinear_vertices.value) {
if (poly->numverts > 4) {
float (*new_verts)[VERTEXSIZE] = Q_malloc(poly->numverts * sizeof(float[VERTEXSIZE]));
R_RemoveColinearVertices(poly, new_verts);
Q_free(new_verts);
} else {
float new_verts[4][VERTEXSIZE];
R_RemoveColinearVertices(poly, new_verts);
}
}

R_BrushModelPolygonToTriangleStrip(poly);
return;
}

static void R_BuildLightmapData(msurface_t* surf, int surfnum)
Expand Down
13 changes: 13 additions & 0 deletions src/r_rmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ static void OnDynamicLightingChange(cvar_t* var, char* value, qbool* cancel)
}
}

static void OnRemoveCollinearVerticesChanged(cvar_t* var, char* value, qbool* cancel)
{
#if defined(__APPLE__) && defined(__aarch64__)
// At least arm64 based MacBook laptops are known to require this workaround.
Cvar_SetIgnoreCallback(var, "1");
*cancel = true;
#endif
}

cvar_t cl_multiview = {"cl_multiview", "0" };
cvar_t cl_mvdisplayhud = {"cl_mvdisplayhud", "1"};
cvar_t cl_mvhudvertical = {"cl_mvhudvertical", "0"};
Expand Down Expand Up @@ -238,6 +247,8 @@ cvar_t gl_smoothmodels = {"gl_smoothmodels", "1"};

cvar_t gl_vbo_clientmemory = {"gl_vbo_clientmemory", "0", CVAR_LATCH_GFX };

cvar_t r_remove_collinear_vertices = {"r_remove_collinear_vertices", "0", 0, OnRemoveCollinearVerticesChanged};

//Returns true if the box is completely outside the frustom
qbool R_CullBox(vec3_t mins, vec3_t maxs)
{
Expand Down Expand Up @@ -750,6 +761,8 @@ void R_Init(void)
Cvar_Register(&cl_mvinset_top);
Cvar_Register(&cl_mvinset_right);

Cvar_Register(&r_remove_collinear_vertices);

Cvar_ResetCurrentGroup();

if (!hud_netgraph) {
Expand Down
Loading