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

[TS] Fix sorting failures on rotated cuboids #2812

Merged
merged 1 commit into from
Oct 26, 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
Original file line number Diff line number Diff line change
Expand Up @@ -25,37 +25,42 @@ public class TQuad {

private ModelQuadFacing facing;
private final float[] extents;
private float[] vertexPositions;
private final int packedNormal;
private float dotProduct;
private final float accurateDotProduct;
private float quantizedDotProduct;
private Vector3fc center; // null on aligned quads
private Vector3fc quantizedNormal;
private Vector3fc accurateNormal;

private TQuad(ModelQuadFacing facing, float[] extents, Vector3fc center, int packedNormal) {
private TQuad(ModelQuadFacing facing, float[] extents, float[] vertexPositions, Vector3fc center, int packedNormal) {
this.facing = facing;
this.extents = extents;
this.vertexPositions = vertexPositions;
this.center = center;
this.packedNormal = packedNormal;

if (this.facing.isAligned()) {
this.dotProduct = getAlignedDotProduct(this.facing, this.extents);
this.accurateDotProduct = getAlignedDotProduct(this.facing, this.extents);
} else {
float normX = NormI8.unpackX(this.packedNormal);
float normY = NormI8.unpackY(this.packedNormal);
float normZ = NormI8.unpackZ(this.packedNormal);
this.dotProduct = this.getCenter().dot(normX, normY, normZ);
this.accurateDotProduct = this.getCenter().dot(normX, normY, normZ);
}
this.quantizedDotProduct = this.accurateDotProduct;
}

private static float getAlignedDotProduct(ModelQuadFacing facing, float[] extents) {
return extents[facing.ordinal()] * facing.getSign();
}

static TQuad fromAligned(ModelQuadFacing facing, float[] extents, Vector3fc center) {
return new TQuad(facing, extents, center, ModelQuadFacing.PACKED_ALIGNED_NORMALS[facing.ordinal()]);
static TQuad fromAligned(ModelQuadFacing facing, float[] extents, float[] vertexPositions, Vector3fc center) {
return new TQuad(facing, extents, vertexPositions, center, ModelQuadFacing.PACKED_ALIGNED_NORMALS[facing.ordinal()]);
}

static TQuad fromUnaligned(ModelQuadFacing facing, float[] extents, Vector3fc center, int packedNormal) {
return new TQuad(facing, extents, center, packedNormal);
static TQuad fromUnaligned(ModelQuadFacing facing, float[] extents, float[] vertexPositions, Vector3fc center, int packedNormal) {
return new TQuad(facing, extents, vertexPositions, center, packedNormal);
}

public ModelQuadFacing getFacing() {
Expand All @@ -73,9 +78,9 @@ public ModelQuadFacing useQuantizedFacing() {
this.getQuantizedNormal();
this.facing = ModelQuadFacing.fromNormal(this.quantizedNormal.x(), this.quantizedNormal.y(), this.quantizedNormal.z());
if (this.facing.isAligned()) {
this.dotProduct = getAlignedDotProduct(this.facing, this.extents);
this.quantizedDotProduct = getAlignedDotProduct(this.facing, this.extents);
} else {
this.dotProduct = this.getCenter().dot(this.quantizedNormal);
this.quantizedDotProduct = this.getCenter().dot(this.quantizedNormal);
}
}

Expand All @@ -86,6 +91,31 @@ public float[] getExtents() {
return this.extents;
}

public float[] getVertexPositions() {
// calculate vertex positions from extents if there's no cached value
// (we don't want to be preemptively collecting vertex positions for all aligned quads)
if (this.vertexPositions == null) {
this.vertexPositions = new float[12];

var facingAxis = this.facing.getAxis();
var xRange = facingAxis == 0 ? 0 : 3;
var yRange = facingAxis == 1 ? 0 : 3;
var zRange = facingAxis == 2 ? 0 : 3;

var itemIndex = 0;
for (int x = 0; x <= xRange; x += 3) {
for (int y = 0; y <= yRange; y += 3) {
for (int z = 0; z <= zRange; z += 3) {
this.vertexPositions[itemIndex++] = this.extents[x];
this.vertexPositions[itemIndex++] = this.extents[y + 1];
this.vertexPositions[itemIndex++] = this.extents[z + 2];
}
}
}
}
return this.vertexPositions;
}

public Vector3fc getCenter() {
// calculate aligned quad center on demand
if (this.center == null) {
Expand All @@ -97,8 +127,12 @@ public Vector3fc getCenter() {
return this.center;
}

public float getDotProduct() {
return this.dotProduct;
public float getAccurateDotProduct() {
return this.accurateDotProduct;
}

public float getQuantizedDotProduct() {
return this.quantizedDotProduct;
}

public int getPackedNormal() {
Expand All @@ -116,6 +150,20 @@ public Vector3fc getQuantizedNormal() {
return this.quantizedNormal;
}

public Vector3fc getAccurateNormal() {
if (this.facing.isAligned()) {
return this.facing.getAlignedNormal();
} else {
if (this.accurateNormal == null) {
this.accurateNormal = new Vector3f(
NormI8.unpackX(this.packedNormal),
NormI8.unpackY(this.packedNormal),
NormI8.unpackZ(this.packedNormal));
}
return this.accurateNormal;
}
}

private void computeQuantizedNormal() {
float normX = NormI8.unpackX(this.packedNormal);
float normY = NormI8.unpackY(this.packedNormal);
Expand Down Expand Up @@ -150,7 +198,7 @@ int getQuadHash() {
} else {
result = 31 * result + this.packedNormal;
}
result = 31 * result + Float.hashCode(this.dotProduct);
result = 31 * result + Float.hashCode(this.quantizedDotProduct);
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, M
float lastX = vertices[3].x;
float lastY = vertices[3].y;
float lastZ = vertices[3].z;
int uniqueQuads = 0;
int uniqueVertexes = 0;

float posXExtent = Float.NEGATIVE_INFINITY;
float posYExtent = Float.NEGATIVE_INFINITY;
Expand All @@ -141,7 +141,7 @@ public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, M
xSum += x;
ySum += y;
zSum += z;
uniqueQuads++;
uniqueVertexes++;
}
if (i != 3) {
lastX = x;
Expand Down Expand Up @@ -185,13 +185,38 @@ public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, M
}

Vector3fc center = null;
if (!facing.isAligned() || uniqueQuads != 4) {
var centerX = xSum / uniqueQuads;
var centerY = ySum / uniqueQuads;
var centerZ = zSum / uniqueQuads;
if (!facing.isAligned() || uniqueVertexes != 4) {
var centerX = xSum / uniqueVertexes;
var centerY = ySum / uniqueVertexes;
var centerZ = zSum / uniqueVertexes;
center = new Vector3f(centerX, centerY, centerZ);
}

// check if we need to store vertex positions for this quad, only necessary if it's unaligned or rotated (yet aligned)
var needsVertexPositions = uniqueVertexes != 4 || !facing.isAligned();
if (!needsVertexPositions) {
for (int i = 0; i < 4; i++) {
var vertex = vertices[i];
if (vertex.x != posYExtent && vertex.x != negYExtent ||
vertex.y != posZExtent && vertex.y != negZExtent ||
vertex.z != posXExtent && vertex.z != negXExtent) {
needsVertexPositions = true;
break;
}
}
}

float[] vertexPositions = null;
if (needsVertexPositions) {
vertexPositions = new float[12];
for (int i = 0, itemIndex = 0; i < 4; i++) {
var vertex = vertices[i];
vertexPositions[itemIndex++] = vertex.x;
vertexPositions[itemIndex++] = vertex.y;
vertexPositions[itemIndex++] = vertex.z;
}
}

if (facing.isAligned()) {
// only update global extents if there are no unaligned quads since this is only
// used for the convex box test which doesn't work with unaligned quads anyway
Expand All @@ -204,11 +229,11 @@ public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, M
this.extents[5] = Math.min(this.extents[5], negZExtent);
}

var quad = TQuad.fromAligned(facing, extents, center);
var quad = TQuad.fromAligned(facing, extents, vertexPositions, center);
quadList.add(quad);

var extreme = this.alignedExtremes[direction];
var distance = quad.getDotProduct();
var distance = quad.getAccurateDotProduct();

// check if this is a new dot product for this distance
var existingExtreme = this.alignedExtremes[direction];
Expand All @@ -225,11 +250,11 @@ public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, M
} else {
this.hasUnaligned = true;

var quad = TQuad.fromUnaligned(facing, extents, center, packedNormal);
var quad = TQuad.fromUnaligned(facing, extents, vertexPositions, center, packedNormal);
quadList.add(quad);

// update the two unaligned normals that are tracked
var distance = quad.getDotProduct();
var distance = quad.getAccurateDotProduct();
if (packedNormal == this.unalignedANormal) {
if (Float.isNaN(this.unalignedADistance1)) {
this.unalignedADistance1 = distance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ private static boolean doubleLeafPossible(TQuad quadA, TQuad quadB) {
// opposite normal (distance irrelevant)
if (NormI8.isOpposite(packedNormalA, packedNormalB)
// same normal and same distance
|| packedNormalA == packedNormalB && quadA.getDotProduct() == quadB.getDotProduct()) {
|| packedNormalA == packedNormalB && quadA.getAccurateDotProduct() == quadB.getAccurateDotProduct()) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ static private BSPNode buildSNRLeafNodeFromQuads(BSPWorkspace workspace, IntArra

for (int i = 0; i < indexes.size(); i++) {
var quadIndex = indexes.getInt(i);
keys[i] = MathUtil.floatToComparableInt(workspace.quads[quadIndex].getDotProduct());
keys[i] = MathUtil.floatToComparableInt(workspace.quads[quadIndex].getAccurateDotProduct());
}

quadIndexes = RadixSort.sort(keys);
Expand All @@ -553,7 +553,7 @@ static private BSPNode buildSNRLeafNodeFromQuads(BSPWorkspace workspace, IntArra

for (int i = 0; i < indexes.size(); i++) {
var quadIndex = indexes.getInt(i);
int dotProductComponent = MathUtil.floatToComparableInt(workspace.quads[quadIndex].getDotProduct());
int dotProductComponent = MathUtil.floatToComparableInt(workspace.quads[quadIndex].getAccurateDotProduct());
sortData[i] = (long) dotProductComponent << 32 | quadIndex;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data;

import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes;
import net.caffeinemc.mods.sodium.client.util.sorting.RadixSort;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data;

import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad;
import net.caffeinemc.mods.sodium.client.util.MathUtil;
Expand Down Expand Up @@ -50,7 +49,7 @@ private static StaticNormalRelativeData fromDoubleUnaligned(int[] vertexCounts,
final var keys = new int[quads.length];

for (int q = 0; q < quads.length; q++) {
keys[q] = MathUtil.floatToComparableInt(quads[q].getDotProduct());
keys[q] = MathUtil.floatToComparableInt(quads[q].getAccurateDotProduct());
}

var indices = RadixSort.sort(keys);
Expand All @@ -62,7 +61,7 @@ private static StaticNormalRelativeData fromDoubleUnaligned(int[] vertexCounts,
final var sortData = new long[quads.length];

for (int q = 0; q < quads.length; q++) {
int dotProductComponent = MathUtil.floatToComparableInt(quads[q].getDotProduct());
int dotProductComponent = MathUtil.floatToComparableInt(quads[q].getAccurateDotProduct());
sortData[q] = (long) dotProductComponent << 32 | q;
}

Expand Down Expand Up @@ -116,7 +115,7 @@ private static StaticNormalRelativeData fromMixed(int[] vertexCounts,
final var keys = new int[count];

for (int q = 0; q < count; q++) {
keys[q] = MathUtil.floatToComparableInt(quads[quadIndex++].getDotProduct());
keys[q] = MathUtil.floatToComparableInt(quads[quadIndex++].getAccurateDotProduct());
}

var indices = RadixSort.sort(keys);
Expand All @@ -127,7 +126,7 @@ private static StaticNormalRelativeData fromMixed(int[] vertexCounts,
} else {
for (int i = 0; i < count; i++) {
var quad = quads[quadIndex++];
int dotProductComponent = MathUtil.floatToComparableInt(quad.getDotProduct());
int dotProductComponent = MathUtil.floatToComparableInt(quad.getAccurateDotProduct());
sortData[i] = (long) dotProductComponent << 32 | i;
}

Expand Down
Loading