Skip to content

Commit b2b8a88

Browse files
authored
faster section abb test (#3099)
1 parent a732ebc commit b2b8a88

File tree

3 files changed

+109
-19
lines changed

3 files changed

+109
-19
lines changed

common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -234,16 +234,12 @@ private static int nearestToZero(int min, int max) {
234234
public static final float CHUNK_SECTION_SIZE = CHUNK_SECTION_RADIUS + CHUNK_SECTION_MARGIN;
235235

236236
public static boolean isWithinFrustum(Viewport viewport, RenderSection section) {
237-
return viewport.isBoxVisible(section.getCenterX(), section.getCenterY(), section.getCenterZ(),
238-
CHUNK_SECTION_SIZE, CHUNK_SECTION_SIZE, CHUNK_SECTION_SIZE);
237+
return viewport.isBoxVisible(section.getCenterX(), section.getCenterY(), section.getCenterZ());
239238
}
240239

241-
// this bigger chunk section size is only used for frustum-testing nearby sections with large models
242-
private static final float CHUNK_SECTION_SIZE_NEARBY = CHUNK_SECTION_RADIUS + 2.0f /* bigger model extent */ + 0.125f /* epsilon */;
243-
240+
// Only used for nearby sections with large models
244241
public static boolean isWithinNearbySectionFrustum(Viewport viewport, RenderSection section) {
245-
return viewport.isBoxVisible(section.getCenterX(), section.getCenterY(), section.getCenterZ(),
246-
CHUNK_SECTION_SIZE_NEARBY, CHUNK_SECTION_SIZE_NEARBY, CHUNK_SECTION_SIZE_NEARBY);
242+
return viewport.isBoxVisibleLooser(section.getCenterX(), section.getCenterY(), section.getCenterZ());
247243
}
248244

249245
// This method visits sections near the origin that are not in the path of the graph traversal

common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/Viewport.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package net.caffeinemc.mods.sodium.client.render.viewport;
22

3-
import net.caffeinemc.mods.sodium.client.render.viewport.frustum.Frustum;
3+
import net.caffeinemc.mods.sodium.client.render.viewport.frustum.SimpleFrustum;
44
import net.minecraft.core.BlockPos;
55
import net.minecraft.core.SectionPos;
66
import org.joml.Vector3d;
77

88
public final class Viewport {
9-
private final Frustum frustum;
9+
private final SimpleFrustum frustum;
1010
private final CameraTransform transform;
1111

1212
private final SectionPos sectionCoords;
1313
private final BlockPos blockCoords;
1414

15-
public Viewport(Frustum frustum, Vector3d position) {
15+
public Viewport(SimpleFrustum frustum, Vector3d position) {
1616
this.frustum = frustum;
1717
this.transform = new CameraTransform(position.x, position.y, position.z);
1818

@@ -25,20 +25,20 @@ public Viewport(Frustum frustum, Vector3d position) {
2525
this.blockCoords = BlockPos.containing(position.x, position.y, position.z);
2626
}
2727

28-
public boolean isBoxVisible(int intOriginX, int intOriginY, int intOriginZ, float floatSizeX, float floatSizeY, float floatSizeZ) {
28+
public boolean isBoxVisible(int intOriginX, int intOriginY, int intOriginZ) {
2929
float floatOriginX = (intOriginX - this.transform.intX) - this.transform.fracX;
3030
float floatOriginY = (intOriginY - this.transform.intY) - this.transform.fracY;
3131
float floatOriginZ = (intOriginZ - this.transform.intZ) - this.transform.fracZ;
3232

33-
return this.frustum.testAab(
34-
floatOriginX - floatSizeX,
35-
floatOriginY - floatSizeY,
36-
floatOriginZ - floatSizeZ,
33+
return this.frustum.testCubeQuick(floatOriginX, floatOriginY, floatOriginZ);
34+
}
3735

38-
floatOriginX + floatSizeX,
39-
floatOriginY + floatSizeY,
40-
floatOriginZ + floatSizeZ
41-
);
36+
public boolean isBoxVisibleLooser(int intOriginX, int intOriginY, int intOriginZ) {
37+
float floatOriginX = (intOriginX - this.transform.intX) - this.transform.fracX;
38+
float floatOriginY = (intOriginY - this.transform.intY) - this.transform.fracY;
39+
float floatOriginZ = (intOriginZ - this.transform.intZ) - this.transform.fracZ;
40+
41+
return this.frustum.testCubeWithExtend(floatOriginX, floatOriginY, floatOriginZ, 1.0625f);
4242
}
4343

4444
public boolean isBoxVisibleDirect(float floatOriginX, float floatOriginY, float floatOriginZ, float floatSize) {

common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,106 @@
11
package net.caffeinemc.mods.sodium.client.render.viewport.frustum;
22

3+
import net.caffeinemc.mods.sodium.client.render.chunk.occlusion.OcclusionCuller;
34
import org.joml.FrustumIntersection;
5+
import org.joml.Vector4f;
6+
7+
import java.lang.invoke.MethodHandle;
8+
import java.lang.invoke.MethodHandles;
9+
import java.lang.reflect.Field;
410

511
public final class SimpleFrustum implements Frustum {
12+
private float nxX, nxY, nxZ, negNxW;
13+
private float pxX, pxY, pxZ, negPxW;
14+
private float nyX, nyY, nyZ, negNyW;
15+
private float pyX, pyY, pyZ, negPyW;
16+
private float nzX, nzY, nzZ, negNzW;
17+
private float pzX, pzY, pzZ, negPzW;
18+
619
private final FrustumIntersection frustum;
720

21+
private static final MethodHandle PLANES_GETTER;
22+
static {
23+
try {
24+
Field field = FrustumIntersection.class.getDeclaredField("planes");
25+
field.setAccessible(true);
26+
PLANES_GETTER = MethodHandles.lookup().unreflectGetter(field);
27+
} catch (NoSuchFieldException | IllegalAccessException e) {
28+
throw new RuntimeException("Failed to find planes field in JOML", e);
29+
}
30+
}
31+
832
public SimpleFrustum(FrustumIntersection frustumIntersection) {
933
this.frustum = frustumIntersection;
34+
Vector4f[] planes;
35+
try {
36+
planes = (Vector4f[]) PLANES_GETTER.invokeExact(frustumIntersection);
37+
} catch (Throwable e) {
38+
throw new RuntimeException("Failed to access planes field in FrustumIntersection", e);
39+
}
40+
41+
nxX = planes[0].x;
42+
nxY = planes[0].y;
43+
nxZ = planes[0].z;
44+
pxX = planes[1].x;
45+
pxY = planes[1].y;
46+
pxZ = planes[1].z;
47+
nyX = planes[2].x;
48+
nyY = planes[2].y;
49+
nyZ = planes[2].z;
50+
pyX = planes[3].x;
51+
pyY = planes[3].y;
52+
pyZ = planes[3].z;
53+
nzX = planes[4].x;
54+
nzY = planes[4].y;
55+
nzZ = planes[4].z;
56+
pzX = planes[5].x;
57+
pzY = planes[5].y;
58+
pzZ = planes[5].z;
59+
60+
final float size = OcclusionCuller.CHUNK_SECTION_SIZE;
61+
negNxW = -(planes[0].w + nxX * (nxX < 0 ? -size : size) +
62+
nxY * (nxY < 0 ? -size : size) +
63+
nxZ * (nxZ < 0 ? -size : size));
64+
negPxW = -(planes[1].w + pxX * (pxX < 0 ? -size : size) +
65+
pxY * (pxY < 0 ? -size : size) +
66+
pxZ * (pxZ < 0 ? -size : size));
67+
negNyW = -(planes[2].w + nyX * (nyX < 0 ? -size : size) +
68+
nyY * (nyY < 0 ? -size : size) +
69+
nyZ * (nyZ < 0 ? -size : size));
70+
negPyW = -(planes[3].w + pyX * (pyX < 0 ? -size : size) +
71+
pyY * (pyY < 0 ? -size : size) +
72+
pyZ * (pyZ < 0 ? -size : size));
73+
negNzW = -(planes[4].w + nzX * (nzX < 0 ? -size : size) +
74+
nzY * (nzY < 0 ? -size : size) +
75+
nzZ * (nzZ < 0 ? -size : size));
76+
negPzW = -(planes[5].w + pzX * (pzX < 0 ? -size : size) +
77+
pzY * (pzY < 0 ? -size : size) +
78+
pzZ * (pzZ < 0 ? -size : size));
79+
}
80+
81+
public boolean testCubeQuick(float x, float y, float z) {
82+
// Skip far plane checks because it has been ensured by searchDistance and isWithinRenderDistance check in OcclusionCuller
83+
return nxX * x + nxY * y + nxZ * z >= negNxW &&
84+
pxX * x + pxY * y + pxZ * z >= negPxW &&
85+
nyX * x + nyY * y + nyZ * z >= negNyW &&
86+
pyX * x + pyY * y + pyZ * z >= negPyW &&
87+
nzX * x + nzY * y + nzZ * z >= negNzW;
88+
}
89+
90+
public boolean testCubeWithExtend(float floatOriginX, float floatOriginY, float floatOriginZ, float extend) {
91+
float minX = floatOriginX - extend;
92+
float maxX = floatOriginX + extend;
93+
float minY = floatOriginY - extend;
94+
float maxY = floatOriginY + extend;
95+
float minZ = floatOriginZ - extend;
96+
float maxZ = floatOriginZ + extend;
97+
98+
return nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) + nxZ * (nxZ < 0 ? minZ : maxZ) >= negNxW &&
99+
pxX * (pxX < 0 ? minX : maxX) + pxY * (pxY < 0 ? minY : maxY) + pxZ * (pxZ < 0 ? minZ : maxZ) >= negPxW &&
100+
nyX * (nyX < 0 ? minX : maxX) + nyY * (nyY < 0 ? minY : maxY) + nyZ * (nyZ < 0 ? minZ : maxZ) >= negNyW &&
101+
pyX * (pyX < 0 ? minX : maxX) + pyY * (pyY < 0 ? minY : maxY) + pyZ * (pyZ < 0 ? minZ : maxZ) >= negPyW &&
102+
nzX * (nzX < 0 ? minX : maxX) + nzY * (nzY < 0 ? minY : maxY) + nzZ * (nzZ < 0 ? minZ : maxZ) >= negNzW &&
103+
pzX * (pzX < 0 ? minX : maxX) + pzY * (pzY < 0 ? minY : maxY) + pzZ * (pzZ < 0 ? minZ : maxZ) >= negPzW;
10104
}
11105

12106
@Override

0 commit comments

Comments
 (0)