Skip to content

Commit 3dbb6bb

Browse files
authored
Fix rare crash resulting from splitting of bent quads and fix corruption from too strict coplanarity check (#3439)
* Fix rare issue where bent quads are split on an edge, violating overly broad assumptions I made about the possible configurations of the quads. * Fix issue where sometimes quads were splitting their own coplanar water surface "siblings" which were actually also in the split plane, leading to corruption.
1 parent 3be6d3a commit 3dbb6bb

File tree

1 file changed

+29
-14
lines changed

1 file changed

+29
-14
lines changed

common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import net.caffeinemc.mods.sodium.client.util.MathUtil;
1717
import net.caffeinemc.mods.sodium.client.util.sorting.RadixSort;
1818
import net.minecraft.util.Mth;
19+
import org.joml.Vector3f;
1920
import org.joml.Vector3fc;
2021

2122
import java.util.Arrays;
@@ -471,6 +472,10 @@ static void flushBestSplittingGroup(IntArrayList splittingGroup, IntArrayList be
471472
splittingGroup.clear();
472473
}
473474

475+
private static boolean floatEquals(float a, float b) {
476+
return Float.floatToIntBits(a) == Float.floatToIntBits(b) || Math.abs(a - b) <= TQuad.VERTEX_EPSILON;
477+
}
478+
474479
static private BSPNode handleUnsortableBySplitting(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode, IntArrayList splittingGroup) {
475480
// pick the first quad if there's no prepared splitting group
476481
int representativeIndex;
@@ -487,6 +492,9 @@ static private BSPNode handleUnsortableBySplitting(BSPWorkspace workspace, IntAr
487492
// split all quads by the splitting group's plane
488493
var splitPlane = representative.getVeryAccurateNormal();
489494
var splitDistance = representative.getAccurateDotProduct();
495+
var splitPlaneNeg = splitPlane.negate(new Vector3f());
496+
var splitDistanceNeg = -splitDistance;
497+
var splitPlaneIsAligned = representativeFacing.isAligned();
490498

491499
IntArrayList inside = new IntArrayList();
492500
IntArrayList outside = new IntArrayList();
@@ -507,11 +515,17 @@ static private BSPNode handleUnsortableBySplitting(BSPWorkspace workspace, IntAr
507515
var quadFacing = insideQuad.getFacing();
508516

509517
// eliminate quads that lie in the split plane
510-
if (quadFacing == representativeFacing && insideQuad.getAccurateDotProduct() == splitDistance &&
511-
(representativeFacing != ModelQuadFacing.UNASSIGNED ||
512-
insideQuad.getVeryAccurateNormal().equals(splitPlane))) {
513-
splittingGroup.add(candidateIndex);
514-
continue;
518+
if (quadFacing == representativeFacing) {
519+
var accurateNormal = insideQuad.getVeryAccurateNormal();
520+
var accurateDotProduct = insideQuad.getAccurateDotProduct();
521+
var coplanar = floatEquals(accurateDotProduct, splitDistance) && (splitPlaneIsAligned ||
522+
accurateNormal.equals(splitPlane, TQuad.VERTEX_EPSILON));
523+
var antiCoplanar = coplanar || floatEquals(accurateDotProduct, splitDistanceNeg) && (splitPlaneIsAligned ||
524+
accurateNormal.equals(splitPlaneNeg, TQuad.VERTEX_EPSILON));
525+
if (coplanar || antiCoplanar) {
526+
splittingGroup.add(candidateIndex);
527+
continue;
528+
}
515529
}
516530

517531
// split the geometry with the plane
@@ -646,18 +660,19 @@ else if (insideCount == 1) {
646660
splitTriangleCorner(cornerIndex, outsideQuad, insideQuad, splitPlane, splitDistance);
647661
}
648662
} else { // uniqueVertices == 4, masked == unmasked
649-
// after dealing with the other cases, now two vertices being on the plane implies the quad is split exactly along its diagonal
650-
// insideCount is 2, onPlaneMap is 0b0101 or 0b1010
651-
if (onPlaneCount == 2) {
652-
// this case can be treated like even splitting if the two on-plane vertices are declared as each part of one of the sides
653-
if (onPlaneMap == 0b0101) {
654-
insideMap |= 0b0001;
655-
} else {
656-
insideMap |= 0b0010;
657-
}
663+
// it's split along the diagonal.
664+
// this case can be treated like even splitting if the two on-plane vertices are declared as each part of one of the sides
665+
if (onPlaneCount == 2 && onPlaneMap == 0b0101) {
666+
insideMap |= 0b0001;
667+
insideCount = 2;
668+
} else if (onPlaneCount == 2 && onPlaneMap == 0b1010) {
669+
insideMap |= 0b0010;
658670
insideCount = 2;
659671
}
660672

673+
// or it's a bent quad where one edge lies on the split and the opposite edge crosses the split.
674+
// in this case it simply falls through to one of the odd splitting modes
675+
661676
// one vertex being on the plane now implies the quad is split on a vertex and through an edge.
662677
// if there is one vertex inside (and two outside), move the on-plane vertex inside to produce an even split case.
663678
// in the other case nothing needs to be done since for splitting the 0-bits in the insideMap are treated as outside.

0 commit comments

Comments
 (0)