Frustum filtering tracker
This commit is contained in:
@@ -0,0 +1,59 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: NanaChiyo0721 <nanachiyo0721@163.com>
|
||||||
|
Date: Thu, 16 Jul 2026 23:04:23 +0800
|
||||||
|
Subject: [PATCH] Frustum filtering tracker
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||||
|
index 849ad46b2941ebba91b428846b3b20d11ee5e1c9..3291d17bc176b306a792a1ca59254615b188ee9e 100644
|
||||||
|
--- a/net/minecraft/server/level/ChunkMap.java
|
||||||
|
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||||
|
@@ -932,6 +932,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
|
||||||
|
public void move(final ServerPlayer player) {
|
||||||
|
// Paper - optimise entity tracker
|
||||||
|
|
||||||
|
+ if (player.culling != null) player.culling.updateFrustum(); // Shiroha - Frustum filtering tracker
|
||||||
|
SectionPos oldSection = player.getLastSectionPos();
|
||||||
|
SectionPos newSection = SectionPos.of(player);
|
||||||
|
//boolean wasIgnored = this.playerMap.ignored(player); // Folia - region threading
|
||||||
|
@@ -1054,6 +1055,11 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
|
||||||
|
final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup entityLookup = (ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup)((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getEntityLookup();;
|
||||||
|
final ca.spottedleaf.moonrise.common.misc.NearbyPlayers nearbyPlayers = this.level.moonrise$getNearbyPlayers(); // Folia - region threading
|
||||||
|
|
||||||
|
+ // Shiroha start - Frustum filtering tracker
|
||||||
|
+ for (var player : worldData.getLocalPlayers()) {
|
||||||
|
+ if (player.culling != null) player.culling.updateFrustum();
|
||||||
|
+ }
|
||||||
|
+ // Shiroha end - Frustum filtering tracker
|
||||||
|
final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.world.entity.Entity> trackerEntities = worldData.trackerEntities; // Folia - region threading
|
||||||
|
final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked();
|
||||||
|
for (int i = 0, len = totalEntities = trackerEntities.size(); i < len; ++i) { // Folia - region threading
|
||||||
|
@@ -1371,6 +1377,15 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
|
||||||
|
if (visibleToPlayer && (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player) || !player.getBukkitEntity().canSee(this.entity.getBukkitEntity()))) { // Paper - only consider hits // Folia - region threading
|
||||||
|
visibleToPlayer = false;
|
||||||
|
}
|
||||||
|
+ // Shiroha start - Frustum filtering tracker
|
||||||
|
+ if (player.culling != null) {
|
||||||
|
+ player.culling.far((float) Math.sqrt(distanceSquared));
|
||||||
|
+
|
||||||
|
+ if (visibleToPlayer && !player.isSpectator() && distanceSquared > ((int)io.nanachiyo0721.shiroha.config.modules.optimizations.FrustumFilteringTrackerConfig.minForceVisibleDistance ^ 2)) {
|
||||||
|
+ visibleToPlayer = player.culling.isVisibleFor(this.entity.getBoundingBox());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Shiroha end - Frustum filtering tracker
|
||||||
|
// CraftBukkit end
|
||||||
|
if (visibleToPlayer) {
|
||||||
|
if (this.seenBy.add(player.connection)) {
|
||||||
|
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
|
||||||
|
index e5e5e1da691dc71dc806d3b039ff02b1fa50eacf..81c5a042b288fb1208bd71239b16f65dd63e69d6 100644
|
||||||
|
--- a/net/minecraft/world/entity/player/Player.java
|
||||||
|
+++ b/net/minecraft/world/entity/player/Player.java
|
||||||
|
@@ -186,6 +186,8 @@ public abstract class Player extends Avatar implements ContainerUser {
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
+ public io.nanachiyo0721.shiroha.utils.Culling culling = io.nanachiyo0721.shiroha.utils.Culling.newDefault(this); // Shiroha - Frustum filtering tracker
|
||||||
|
+
|
||||||
|
public Player(final Level level, final GameProfile gameProfile) {
|
||||||
|
super(EntityTypes.PLAYER, level);
|
||||||
|
this.setUUID(gameProfile.id());
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package io.nanachiyo0721.shiroha.config.modules.optimizations;
|
||||||
|
|
||||||
|
import io.nanachiyo0721.shiroha.config.IConfigModule;
|
||||||
|
import io.nanachiyo0721.shiroha.config.flags.ConfigClassInfo;
|
||||||
|
import io.nanachiyo0721.shiroha.config.flags.ConfigInfo;
|
||||||
|
import io.nanachiyo0721.shiroha.enums.EnumConfigCategory;
|
||||||
|
|
||||||
|
@ConfigClassInfo(name = "frustum_filtering_tracker", category = EnumConfigCategory.OPTIMIZATIONS)
|
||||||
|
public class FrustumFilteringTrackerConfig implements IConfigModule {
|
||||||
|
@ConfigInfo(name = "enabled")
|
||||||
|
public static boolean enabled = false;
|
||||||
|
@ConfigInfo(name = "min_force_visible_distance")
|
||||||
|
public static double minForceVisibleDistance = 5.0D;
|
||||||
|
}
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
package io.nanachiyo0721.shiroha.utils;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jspecify.annotations.NonNull;
|
||||||
|
|
||||||
|
public class Culling {
|
||||||
|
private static final float VERTICAL_FOV_RAD = (float) Math.toRadians(120);
|
||||||
|
private static final float ASPECT = 1.0f;
|
||||||
|
private static final float NEAR = 0.1f;
|
||||||
|
private static final float FAR = 32.0f;
|
||||||
|
|
||||||
|
private float fov;
|
||||||
|
private float aspect;
|
||||||
|
private float near;
|
||||||
|
private float far;
|
||||||
|
|
||||||
|
private final Player player;
|
||||||
|
private float[] planes;
|
||||||
|
|
||||||
|
@Contract(value = "_ -> new", pure = true)
|
||||||
|
public static @NonNull Culling newDefault(Player player) {
|
||||||
|
return fromBuilder(new Builder(), player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(value = "_, _ -> new", pure = true)
|
||||||
|
public static @NonNull Culling fromBuilder(@NonNull Builder builder, Player player) {
|
||||||
|
return new Culling(builder.fov, builder.aspect, builder.near, builder.far, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private float fov;
|
||||||
|
private float aspect;
|
||||||
|
private float near;
|
||||||
|
private float far;
|
||||||
|
|
||||||
|
|
||||||
|
public Builder() {
|
||||||
|
this.fov = VERTICAL_FOV_RAD;
|
||||||
|
this.aspect = ASPECT;
|
||||||
|
this.near = NEAR;
|
||||||
|
this.far = FAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder fov(float fov) {
|
||||||
|
this.fov = fov;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder aspect(float aspect) {
|
||||||
|
this.aspect = aspect;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder near(float near) {
|
||||||
|
this.near = near;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder far(float far) {
|
||||||
|
this.far = far;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Culling build(Player player) {
|
||||||
|
return fromBuilder(this, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Culling(float fov, float aspect, float near, float far, Player player) {
|
||||||
|
this.fov = fov;
|
||||||
|
this.aspect = aspect;
|
||||||
|
this.near = near;
|
||||||
|
this.far = far;
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float @NonNull [] buildFrustumPlanes(
|
||||||
|
float eyeX, float eyeY, float eyeZ,
|
||||||
|
float forwardX, float forwardY, float forwardZ,
|
||||||
|
float upX, float upY, float upZ,
|
||||||
|
float verticalFovRad, float aspect, float nearDist, float farDist) {
|
||||||
|
float lenF = (float) Math.sqrt(forwardX * forwardX + forwardY * forwardY + forwardZ * forwardZ);
|
||||||
|
float fx = forwardX / lenF;
|
||||||
|
float fy = forwardY / lenF;
|
||||||
|
float fz = forwardZ / lenF;
|
||||||
|
|
||||||
|
float rx = fy * upZ - fz * upY;
|
||||||
|
float ry = fz * upX - fx * upZ;
|
||||||
|
float rz = fx * upY - fy * upX;
|
||||||
|
float lenR = (float) Math.sqrt(rx * rx + ry * ry + rz * rz);
|
||||||
|
|
||||||
|
if (lenR < 1.0e-4f) {
|
||||||
|
float fallbackUpX = 0.0f, fallbackUpY = 0.0f, fallbackUpZ = 1.0f;
|
||||||
|
if (Math.abs(fz) > 0.999f) {
|
||||||
|
fallbackUpX = 1.0f;
|
||||||
|
fallbackUpY = 0.0f;
|
||||||
|
fallbackUpZ = 0.0f;
|
||||||
|
}
|
||||||
|
rx = fy * fallbackUpZ - fz * fallbackUpY;
|
||||||
|
ry = fz * fallbackUpX - fx * fallbackUpZ;
|
||||||
|
rz = fx * fallbackUpY - fy * fallbackUpX;
|
||||||
|
lenR = (float) Math.sqrt(rx * rx + ry * ry + rz * rz);
|
||||||
|
}
|
||||||
|
|
||||||
|
rx /= lenR;
|
||||||
|
ry /= lenR;
|
||||||
|
rz /= lenR;
|
||||||
|
|
||||||
|
float ux = ry * fz - rz * fy;
|
||||||
|
float uy = rz * fx - rx * fz;
|
||||||
|
float uz = rx * fy - ry * fx;
|
||||||
|
float lenU = (float) Math.sqrt(ux * ux + uy * uy + uz * uz);
|
||||||
|
ux /= lenU;
|
||||||
|
uy /= lenU;
|
||||||
|
uz /= lenU;
|
||||||
|
|
||||||
|
float tanHalf = (float) Math.tan(verticalFovRad * 0.5);
|
||||||
|
float halfVNear = tanHalf * nearDist;
|
||||||
|
float halfHNear = halfVNear * aspect;
|
||||||
|
float halfVFar = tanHalf * farDist;
|
||||||
|
float halfHFar = halfVFar * aspect;
|
||||||
|
|
||||||
|
float nearCX = eyeX + fx * nearDist;
|
||||||
|
float nearCY = eyeY + fy * nearDist;
|
||||||
|
float nearCZ = eyeZ + fz * nearDist;
|
||||||
|
|
||||||
|
float farCX = eyeX + fx * farDist;
|
||||||
|
float farCY = eyeY + fy * farDist;
|
||||||
|
float farCZ = eyeZ + fz * farDist;
|
||||||
|
|
||||||
|
float ntlX = nearCX + ux * halfVNear - rx * halfHNear;
|
||||||
|
float ntlY = nearCY + uy * halfVNear - ry * halfHNear;
|
||||||
|
float ntlZ = nearCZ + uz * halfVNear - rz * halfHNear;
|
||||||
|
|
||||||
|
float ntrX = nearCX + ux * halfVNear + rx * halfHNear;
|
||||||
|
float ntrY = nearCY + uy * halfVNear + ry * halfHNear;
|
||||||
|
float ntrZ = nearCZ + uz * halfVNear + rz * halfHNear;
|
||||||
|
|
||||||
|
float nblX = nearCX - ux * halfVNear - rx * halfHNear;
|
||||||
|
float nblY = nearCY - uy * halfVNear - ry * halfHNear;
|
||||||
|
float nblZ = nearCZ - uz * halfVNear - rz * halfHNear;
|
||||||
|
|
||||||
|
float nbrX = nearCX - ux * halfVNear + rx * halfHNear;
|
||||||
|
float nbrY = nearCY - uy * halfVNear + ry * halfHNear;
|
||||||
|
float nbrZ = nearCZ - uz * halfVNear + rz * halfHNear;
|
||||||
|
|
||||||
|
float ftlX = farCX + ux * halfVFar - rx * halfHFar;
|
||||||
|
float ftlY = farCY + uy * halfVFar - ry * halfHFar;
|
||||||
|
float ftlZ = farCZ + uz * halfVFar - rz * halfHFar;
|
||||||
|
|
||||||
|
float ftrX = farCX + ux * halfVFar + rx * halfHFar;
|
||||||
|
float ftrY = farCY + uy * halfVFar + ry * halfHFar;
|
||||||
|
float ftrZ = farCZ + uz * halfVFar + rz * halfHFar;
|
||||||
|
|
||||||
|
float fbrX = farCX - ux * halfVFar + rx * halfHFar;
|
||||||
|
float fbrY = farCY - uy * halfVFar + ry * halfHFar;
|
||||||
|
float fbrZ = farCZ - uz * halfVFar + rz * halfHFar;
|
||||||
|
|
||||||
|
float midDist = (nearDist + farDist) * 0.5f;
|
||||||
|
float refX = eyeX + fx * midDist;
|
||||||
|
float refY = eyeY + fy * midDist;
|
||||||
|
float refZ = eyeZ + fz * midDist;
|
||||||
|
|
||||||
|
float[] planes = new float[24];
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
idx = computePlane(planes, idx,
|
||||||
|
eyeX, eyeY, eyeZ,
|
||||||
|
ntlX, ntlY, ntlZ,
|
||||||
|
nblX, nblY, nblZ,
|
||||||
|
refX, refY, refZ);
|
||||||
|
|
||||||
|
idx = computePlane(planes, idx,
|
||||||
|
eyeX, eyeY, eyeZ,
|
||||||
|
nbrX, nbrY, nbrZ,
|
||||||
|
ntrX, ntrY, ntrZ,
|
||||||
|
refX, refY, refZ);
|
||||||
|
|
||||||
|
idx = computePlane(planes, idx,
|
||||||
|
eyeX, eyeY, eyeZ,
|
||||||
|
nblX, nblY, nblZ,
|
||||||
|
nbrX, nbrY, nbrZ,
|
||||||
|
refX, refY, refZ);
|
||||||
|
|
||||||
|
idx = computePlane(planes, idx,
|
||||||
|
eyeX, eyeY, eyeZ,
|
||||||
|
ntrX, ntrY, ntrZ,
|
||||||
|
ntlX, ntlY, ntlZ,
|
||||||
|
refX, refY, refZ);
|
||||||
|
|
||||||
|
idx = computePlane(planes, idx,
|
||||||
|
ntlX, ntlY, ntlZ,
|
||||||
|
ntrX, ntrY, ntrZ,
|
||||||
|
nblX, nblY, nblZ,
|
||||||
|
refX, refY, refZ);
|
||||||
|
|
||||||
|
idx = computePlane(planes, idx,
|
||||||
|
ftrX, ftrY, ftrZ,
|
||||||
|
ftlX, ftlY, ftlZ,
|
||||||
|
fbrX, fbrY, fbrZ,
|
||||||
|
refX, refY, refZ);
|
||||||
|
|
||||||
|
return planes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int computePlane(float[] out, int start,
|
||||||
|
float p0x, float p0y, float p0z,
|
||||||
|
float p1x, float p1y, float p1z,
|
||||||
|
float p2x, float p2y, float p2z,
|
||||||
|
float refX, float refY, float refZ) {
|
||||||
|
float e1x = p1x - p0x, e1y = p1y - p0y, e1z = p1z - p0z;
|
||||||
|
float e2x = p2x - p0x, e2y = p2y - p0y, e2z = p2z - p0z;
|
||||||
|
|
||||||
|
float nx = e1y * e2z - e1z * e2y;
|
||||||
|
float ny = e1z * e2x - e1x * e2z;
|
||||||
|
float nz = e1x * e2y - e1y * e2x;
|
||||||
|
|
||||||
|
float d = -(nx * p0x + ny * p0y + nz * p0z);
|
||||||
|
float val = nx * refX + ny * refY + nz * refZ + d;
|
||||||
|
|
||||||
|
if (val < 0.0f) {
|
||||||
|
nx = -nx;
|
||||||
|
ny = -ny;
|
||||||
|
nz = -nz;
|
||||||
|
d = -d;
|
||||||
|
}
|
||||||
|
|
||||||
|
float len = (float) Math.sqrt(nx * nx + ny * ny + nz * nz);
|
||||||
|
nx /= len;
|
||||||
|
ny /= len;
|
||||||
|
nz /= len;
|
||||||
|
|
||||||
|
d = -(nx * p0x + ny * p0y + nz * p0z);
|
||||||
|
|
||||||
|
out[start] = nx;
|
||||||
|
out[start + 1] = ny;
|
||||||
|
out[start + 2] = nz;
|
||||||
|
out[start + 3] = d;
|
||||||
|
|
||||||
|
return start + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply(@NonNull Builder builder) {
|
||||||
|
this.fov = builder.fov;
|
||||||
|
this.aspect = builder.aspect;
|
||||||
|
this.near = builder.near;
|
||||||
|
this.far = builder.far;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateFrustum() {
|
||||||
|
Vec3 eye = this.player.getEyePosition();
|
||||||
|
Vec3 look = this.player.getLookAngle();
|
||||||
|
this.planes = buildFrustumPlanes(
|
||||||
|
(float) eye.x, (float) eye.y, (float) eye.z,
|
||||||
|
(float) look.x, (float) look.y, (float) look.z,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
this.fov, this.aspect, this.near, this.far
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void far(float far) {
|
||||||
|
this.far = far;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisibleFor(@NonNull AABB box) {
|
||||||
|
final float[] planes = this.planes;
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
int base = i << 2;
|
||||||
|
float nx = planes[base], ny = planes[base+1], nz = planes[base+2], d = planes[base+3];
|
||||||
|
float px = (nx >= 0) ? (float) box.maxX : (float) box.minX;
|
||||||
|
float py = (ny >= 0) ? (float) box.maxY : (float) box.minY;
|
||||||
|
float pz = (nz >= 0) ? (float) box.maxZ : (float) box.minZ;
|
||||||
|
|
||||||
|
if (nx * px + ny * py + nz * pz + d < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user