mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
fix(D233): fast3d trivial-reject drops visible triangles with a behind-camera vertex (#63)
gfx_sp_tri1's CPU-side trivial-reject AND-test trusted per-vertex outcodes (x<-w / x>w / y<-w / y>w / z>w) that are only valid half-space tests when w>0. A vertex that has crossed behind the camera plane (w<0 -- common when the camera is close to a large room-structure polygon, e.g. walls/ceiling trusses near a doorway) flips the comparison sense, so its outcode can come out wrong. When that spurious bit happens to match the other two genuinely correct vertices' bits, the AND-reduction fired and dropped the whole triangle before it ever reached OpenGL -- even though GL's own homogeneous clipper (which handles w<0 correctly) would have rendered the visible part of it. This reads exactly like D233 (indoor geometry intermittently vanishing near doors while props/furniture keep drawing): large near-camera polygons are far more likely to have a vertex cross behind the eye than small self-contained prop meshes, and the backface-cull code six lines below already special-cases this same w-sign hazard for its own cross-product sign -- the trivial-reject block above it never got the same treatment. Fix: skip the trivial-reject AND-test whenever any of the triangle's three vertices has w<0, deferring to GL's clipper instead. This can only ever send MORE triangles to the GPU than before, never fewer, so it cannot make anything newly invisible. Also investigated D234 (Dam guard towers, only the first renders) under the same M-106 hypothesis that it shares a root cause with D233/D222 -- did not find fast3d-side evidence for it; left open in findings.md with the ruled-out mechanisms and a next-step recommendation. D222 (FovScale breaks culling) is a separate, already-characterised game-logic bug in src/game/fr.c/bondview2.c, out of this fast3d-only fix's scope. Build verified green (MSYS2 mingw64 cmake+ninja, full link succeeds). Could not visually verify -- this worktree has no ROM/data and no interactive display; see docs/dev/findings.md D233 entry for the exact human verification steps (GE_PCDUMP on a doorway-heavy interior). docs/dev/findings.md: D233 (FIXED, high confidence on mechanism/unverified visually) + D234 (OPEN, not root-caused) entries added. docs/porting-notes.md: generalised the w<0 trivial-reject hazard as a recurring class for any future CPU-side "skip this triangle" heuristic. docs/dev/findings-index.csv regenerated. Claude-Session: https://claude.ai/code/session_016TaKy6AAsVUTfjkhrX6CjG
This commit is contained in:
1 parent
067c8384d0
commit
650ac57fc6
4 files changed
+42
-3
No files matched your search
+20
-1
@@ -1453,7 +1453,26 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
||||
struct LoadedVertex* v_arr[3] = { v1, v2, v3 };
|
||||
|
||||
if ((rsp.extra_geometry_mode & G_NO_CLIPPING_EXT) == 0) {
|
||||
if (v1->clip_rej & v2->clip_rej & v3->clip_rej) {
|
||||
/* D233: the outcode bits set in gfx_sp_vertex (x<-w / x>w / y<-w /
|
||||
* y>w / z>w) are only valid half-space tests when w>0. A vertex
|
||||
* that has crossed behind the camera plane (w<0) flips the sense of
|
||||
* those comparisons, so its clip_rej bits can come out wrong. If
|
||||
* that spurious bit happens to match the other two (genuinely
|
||||
* correct) vertices' bits, the AND-reduction below fires and drops
|
||||
* the whole triangle before it ever reaches the GPU -- even though
|
||||
* OpenGL's own homogeneous clipper (which handles w<0 correctly)
|
||||
* would have rendered the visible portion of it. This hits large
|
||||
* polygons near the camera (room walls/ceilings near a doorway,
|
||||
* where the camera is close enough for a vertex to sit behind it)
|
||||
* far more than small prop models, matching D233's "room geometry
|
||||
* intermittently vanishes near doors, furniture/terminals still
|
||||
* draw" report. Fix: never trust the trivial-reject AND test when
|
||||
* any vertex has a negative w -- defer to GL's clipper instead,
|
||||
* same as the backface-cull code just below already does for the
|
||||
* same w-sign hazard. Worst case for the (rare) mixed-sign case is
|
||||
* a few extra triangles reaching the GPU; never fewer. */
|
||||
bool any_behind_camera = (v1->w < 0) || (v2->w < 0) || (v3->w < 0);
|
||||
if (!any_behind_camera && (v1->clip_rej & v2->clip_rej & v3->clip_rej)) {
|
||||
// The whole triangle lies outside the visible area
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user