From a8d8abd105b4f47d6a5037d03f020aa9a7701493 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 22 Jan 2025 00:25:26 +0100 Subject: [PATCH] fix bsp triggering with negative, fix quad appending logic, fix quad update logic, fix split case logic to take on-plane vertices into account --- .../TranslucentGeometryCollector.java | 9 +-- .../bsp_tree/BSPResult.java | 5 +- .../bsp_tree/BSPWorkspace.java | 4 +- .../bsp_tree/InnerBinaryPartitionBSPNode.java | 18 ++---- .../bsp_tree/InnerPartitionBSPNode.java | 64 +++++++++++++++---- 5 files changed, 66 insertions(+), 34 deletions(-) diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 1ab5f9df9c..89042d29a6 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -327,10 +327,11 @@ private SortType sortTypeHeuristic() { // use the given set of quad count limits to determine if a static topo sort // should be attempted - var attemptLimitIndex = Mth.clamp(normalCount, 2, STATIC_TOPO_SORT_ATTEMPT_LIMITS.length - 1); - if (this.quads.length <= STATIC_TOPO_SORT_ATTEMPT_LIMITS[attemptLimitIndex]) { - return SortType.STATIC_TOPO; - } + // TODO: make topo sort fail on intersecting geometry when SPLIT_QUADS is enabled +// var attemptLimitIndex = Mth.clamp(normalCount, 2, STATIC_TOPO_SORT_ATTEMPT_LIMITS.length - 1); +// if (this.quads.length <= STATIC_TOPO_SORT_ATTEMPT_LIMITS[attemptLimitIndex]) { +// return SortType.STATIC_TOPO; +// } return SortType.DYNAMIC; } diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java index 9881d2ecef..9fb5a060fd 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java @@ -45,10 +45,9 @@ public void addModifiedQuadIndex(int index) { this.add(index); } - public int addAppendedQuadIndex() { - var index = this.addedQuadCount++; + public void addAppendedQuadIndex(int index) { this.add(index); - return index; + this.addedQuadCount++; } public int getAddedQuadCount() { diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java index 62ff84556b..78f4876fa6 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -46,9 +46,11 @@ void addUnalignedPartitionPlane(Vector3fc planeNormal, float distance) { int pushQuad(FullTQuad quad) { this.translucentVertexBuffer.push(quad.getVertices(), DefaultMaterials.TRANSLUCENT); + var index = this.size(); this.add(quad); + this.result.ensureUpdatedQuadIndexes().addAppendedQuadIndex(index); - return this.result.ensureUpdatedQuadIndexes().addAppendedQuadIndex(); + return index; } int updateQuad(FullTQuad quad, int quadIndex) { diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java index bb7bd9ab6e..bdd7073398 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -118,7 +118,7 @@ static BSPNode buildFromParts(BSPWorkspace workspace, IntArrayList indexes, int if (axis == UNALIGNED_AXIS) { workspace.addUnalignedPartitionPlane(planeNormal, partitionDistance); } else { - workspace.addAlignedPartitionPlane(axis, partitionDistance); + workspace.addAlignedPartitionPlane(axis, Math.abs(partitionDistance)); } BSPNode oldInsideNode = null; @@ -141,16 +141,10 @@ static BSPNode buildFromParts(BSPWorkspace workspace, IntArrayList indexes, int } var onPlaneArr = BSPSortState.compressIndexes(onPlane); - if (axis == UNALIGNED_AXIS) { - return new InnerBinaryPartitionBSPNode( - prepareNodeReuse(workspace, indexes, depth), - partitionDistance, planeNormal, - insideNode, outsideNode, onPlaneArr); - } else { - return new InnerBinaryPartitionBSPNode( - prepareNodeReuse(workspace, indexes, depth), - partitionDistance, axis, - insideNode, outsideNode, onPlaneArr); - } + // always use the correct plane normal here because just specifying the axis causes the constructor to use a wrong and unsigned normal + return new InnerBinaryPartitionBSPNode( + prepareNodeReuse(workspace, indexes, depth), + partitionDistance, planeNormal, + insideNode, outsideNode, onPlaneArr); } } diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 5424358c23..423fb069dc 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -439,6 +439,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS if (TranslucentGeometryCollector.SPLIT_QUADS) { // try static topo sorting first because splitting quads is even more expensive + // TODO: re-enable static topo sorting once it fails on intersecting quads // var multiLeafNode = buildTopoMultiLeafNode(workspace, indexes); // if (multiLeafNode != null) { // return multiLeafNode; @@ -471,6 +472,7 @@ static private BSPNode handleUnsortableBySplitting(BSPWorkspace workspace, IntAr representativeIndex = splittingGroup.getInt(0); } var representative = (FullTQuad) workspace.get(representativeIndex); + var representativeFacing = representative.getFacing(); int initialSplittingGroupSize = splittingGroup.size(); // split all quads by the splitting group's plane @@ -493,48 +495,82 @@ static private BSPNode handleUnsortableBySplitting(BSPWorkspace workspace, IntAr } var insideQuad = (FullTQuad) workspace.get(candidateIndex); + var quadFacing = insideQuad.getFacing(); + + // eliminate quads that lie in the split plane + if (quadFacing == representativeFacing && insideQuad.getAccurateDotProduct() == splitDistance && + (representativeFacing != ModelQuadFacing.UNASSIGNED || + insideQuad.getVeryAccurateNormal().equals(representative.getVeryAccurateNormal()))) { + splittingGroup.add(candidateIndex); + continue; + } + var vertices = insideQuad.getVertices(); // calculate inside/outside for each vertex - int vertexInsideMap = 0; - int vertexOnPlaneCount = 0; + int insideMap = 0; + int onPlaneMap = 0; for (int i = 0; i < 4; i++) { var vertex = vertices[i]; var dot = splitPlane.dot(vertex.x, vertex.y, vertex.z); if (dot < splitDistance) { - vertexInsideMap |= 1 << i; + insideMap |= 1 << i; } else if (dot == splitDistance) { - vertexOnPlaneCount++; + onPlaneMap |= 1 << i; } } - // add quads that are nearly coplanar to the splitting group to it - if (vertexOnPlaneCount >= 3) { + var onPlaneCount = Integer.bitCount(onPlaneMap); + var insideCount = Integer.bitCount(insideMap); + + // treat quads that are actually or nearly (i.e. bent) coplanar as on the plane + if (onPlaneCount >= 3) { splittingGroup.add(candidateIndex); continue; } - // simply add to inside or outside if not split - if (vertexInsideMap == 0) { + // the quad is outside if all vertices are either outside or on the plane + if (insideMap == 0) { outside.add(candidateIndex); continue; } - if (vertexInsideMap == 0b1111) { + + // the quad is inside if all vertices are either inside or on the plane + if ((insideMap | onPlaneMap) == 0b1111) { inside.add(candidateIndex); continue; } - // split with two quads or three quads depending on the orientation - var insideCount = Integer.bitCount(vertexInsideMap); + // after dealing with the other cases, now two vertices being on the plane implies the quad is split exactly along its diagonal + // insideCount is 2, onPlaneMap is 0b0101 or 0b1010 + if (onPlaneCount == 2) { + // this case can be treated like even splitting if the two on-plane vertices are declared as each part of one of the sides + if (onPlaneMap == 0b0101) { + insideMap |= 0b0001; + } else { + insideMap |= 0b0010; + } + insideCount = 2; + } + + // one vertex being on the plane now implies the quad is split on a vertex and through an edge. + // if there is one vertex inside (and two outside), move the on-plane vertex inside to produce an even split case. + // in the other case nothing needs to be done since for splitting the 0-bits in the insideMap are treated as outside. + else if (onPlaneCount == 1 && insideCount == 1) { + insideMap |= onPlaneMap; + insideCount = 2; + } + + // split evenly with two quads or three quads (corner chopped off) depending on the orientation FullTQuad outsideQuad = FullTQuad.splittingCopy(insideQuad); if (insideCount == 2) { - splitQuadEven(vertexInsideMap, insideQuad, outsideQuad, splitPlane, splitDistance); + splitQuadEven(insideMap, insideQuad, outsideQuad, splitPlane, splitDistance); } else if (insideCount == 3) { - var secondInsideQuad = splitQuadOdd(vertexInsideMap, insideCount, insideQuad, outsideQuad, splitPlane, splitDistance); + var secondInsideQuad = splitQuadOdd(insideMap, insideCount, insideQuad, outsideQuad, splitPlane, splitDistance); // TODO: Implement this } else { - var secondOutsideQuad = splitQuadOdd(vertexInsideMap, insideCount, insideQuad, outsideQuad, splitPlane, splitDistance); + var secondOutsideQuad = splitQuadOdd(insideMap, insideCount, insideQuad, outsideQuad, splitPlane, splitDistance); // TODO: Implement this }