capture projection/view matrices for world-to-screen projection

MatrixCapture keeps the matrices from the level render pass so 2d
overlays (nametags) can project world positions onto the gui-scaled
screen.
This commit is contained in:
froslanz
2026-10-24 19:13:22 -04:00
parent 18095e351d
commit eed627a677
2 changed files with 53 additions and 0 deletions
@@ -7,6 +7,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import cc.fros.event.impl.render.Render3DEvent;
import cc.fros.event.impl.render.RenderBlockOutlineEvent;
import cc.fros.util.render.MatrixCapture;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.renderer.LevelRenderer;
@@ -37,6 +38,9 @@ public class MixinLevelRenderer {
Camera camera, Matrix4f positionMatrix, Matrix4f matrix4f, Matrix4f projectionMatrix,
GpuBufferSlice fogBuffer, Vector4f fogColor, boolean renderSky, CallbackInfo ci, @Local ProfilerFiller profiler) {
MatrixCapture.projection = new Matrix4f(projectionMatrix);
MatrixCapture.view = new Matrix4f(positionMatrix);
PoseStack stack = new PoseStack();
stack.pushPose();
stack.mulPose(Axis.XP.rotationDegrees(mc.gameRenderer.getMainCamera().xRot()));
@@ -0,0 +1,49 @@
package cc.fros.util.render;
import cc.fros.util.traits.Util;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix4f;
import org.joml.Vector4f;
/**
* Projection/view matrices captured during the level pass, used to project
* world positions onto the gui-scaled screen for 2d overlays like nametags.
*/
public final class MatrixCapture implements Util {
public static Matrix4f projection;
public static Matrix4f view;
private MatrixCapture() {
throw new AssertionError();
}
public static float[] worldToScreen(double worldX, double worldY, double worldZ) {
if (projection == null || view == null) return null;
Vec3 camPos = mc.gameRenderer.getMainCamera().position();
Matrix4f mvp = projection.mul(view, new Matrix4f());
Vector4f point = new Vector4f(
(float) (worldX - camPos.x()),
(float) (worldY - camPos.y()),
(float) (worldZ - camPos.z()),
1.0f
);
mvp.transform(point);
if (point.w <= 0.0f) return null;
float ndcX = point.x / point.w;
float ndcY = point.y / point.w;
if (ndcX < -1.1f || ndcX > 1.1f || ndcY < -1.1f || ndcY > 1.1f) return null;
int guiW = mc.getWindow().getGuiScaledWidth();
int guiH = mc.getWindow().getGuiScaledHeight();
return new float[]{
(ndcX + 1.0f) / 2.0f * guiW,
(1.0f - ndcY) / 2.0f * guiH
};
}
}