Начинающий
- Статус
- Оффлайн
- Регистрация
- 25 Дек 2025
- Сообщения
- 29
- Реакции
- 0
Java:
package Neleryse.nls.util.render.world;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.RenderTickCounter;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.BufferAllocator;
import net.minecraft.util.math.Vec3d;
import org.joml.Matrix4f;
import java.util.Objects;
/**
* Provides contextual rendering state for post-world rendering passes and custom overlays.
*/
public final class WorldRenderer implements AutoCloseable {
private static final int DEFAULT_BUFFER_CAPACITY_BYTES = 1 << 18; // 256 KiB
private final Camera camera;
private final MatrixStack matrixStack;
private final Matrix4f positionMatrix;
private final Matrix4f worldMatrix;
private final Matrix4f projectionMatrix;
private final BufferAllocator bufferAllocator;
private final VertexConsumerProvider.Immediate immediate;
private final float tickDelta;
private boolean closed;
private WorldRenderer(Camera camera,
MatrixStack matrixStack,
Matrix4f positionMatrix,
Matrix4f worldMatrix,
Matrix4f projectionMatrix,
BufferAllocator bufferAllocator,
VertexConsumerProvider.Immediate immediate,
float tickDelta) {
this.camera = camera;
this.matrixStack = matrixStack;
this.positionMatrix = positionMatrix;
this.worldMatrix = worldMatrix;
this.projectionMatrix = projectionMatrix;
this.bufferAllocator = bufferAllocator;
this.immediate = immediate;
this.tickDelta = tickDelta;
}
public static WorldRenderer begin(MinecraftClient client,
RenderTickCounter tickCounter,
Camera camera,
Matrix4f positionMatrix,
Matrix4f projectionMatrix) {
Objects.requireNonNull(client, "client");
Objects.requireNonNull(tickCounter, "tickCounter");
Objects.requireNonNull(camera, "camera");
Objects.requireNonNull(positionMatrix, "positionMatrix");
Objects.requireNonNull(projectionMatrix, "projectionMatrix");
MatrixStack stack = new MatrixStack();
Matrix4f basePositionMatrix = new Matrix4f(positionMatrix);
Matrix4f baseWorldMatrix = new Matrix4f(basePositionMatrix);
stack.multiplyPositionMatrix(new Matrix4f(basePositionMatrix));
BufferAllocator allocator = new BufferAllocator(DEFAULT_BUFFER_CAPACITY_BYTES);
VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(allocator);
float tickDelta = tickCounter.getTickProgress(false);
return new WorldRenderer(
camera,
stack,
basePositionMatrix,
baseWorldMatrix,
new Matrix4f(projectionMatrix),
allocator,
immediate,
tickDelta
);
}
public Camera camera() {
return camera;
}
/**
* Returns the matrix stack seeded with the vanilla position matrix captured when this renderer began.
*
* <p>The stack is not pre-translated by the camera position; camera-relative adjustment is handled when
* geometry is emitted.</p>
*/
public MatrixStack matrixStack() {
return matrixStack;
}
public Matrix4f positionMatrix() {
return new Matrix4f(positionMatrix);
}
/**
* Returns a copy of the base world-space position matrix captured when this renderer began.
*
* <p>The matrix is aligned with vanilla's position matrix and does not include an implicit camera translation.</p>
*/
public Matrix4f worldMatrix() {
return new Matrix4f(worldMatrix);
}
public Matrix4f projectionMatrix() {
return new Matrix4f(projectionMatrix);
}
public float tickDelta() {
return tickDelta;
}
public VertexConsumerProvider.Immediate bufferSource() {
if (closed) {
throw new IllegalStateException("Cannot access buffers after the world renderer has been closed.");
}
return immediate;
}
public VertexConsumer getBuffer(RenderLayer layer) {
Objects.requireNonNull(layer, "layer");
if (closed) {
throw new IllegalStateException("Cannot request buffers after the world renderer has been closed.");
}
return immediate.getBuffer(layer);
}
public void drawQuad(Vec3d v0, Vec3d v1, Vec3d v2, Vec3d v3, int rgbaColor, boolean depthTest) {
Objects.requireNonNull(v0, "v0");
Objects.requireNonNull(v1, "v1");
Objects.requireNonNull(v2, "v2");
Objects.requireNonNull(v3, "v3");
RenderLayer layer = depthTest ? WorldRenderLayers.POSITION_COLOR_QUADS() : WorldRenderLayers.POSITION_COLOR_QUADS_NO_DEPTH();
WorldGeometryEmitter emitter = new WorldGeometryEmitter(this, matrixStack.peek(), getBuffer(layer));
emitter.emitQuad(v0, v1, v2, v3, rgbaColor);
}
public void drawCube(Vec3d min, Vec3d max, int rgbaColor, boolean depthTest) {
Objects.requireNonNull(min, "min");
Objects.requireNonNull(max, "max");
RenderLayer layer = depthTest ? WorldRenderLayers.POSITION_COLOR_QUADS() : WorldRenderLayers.POSITION_COLOR_QUADS_NO_DEPTH();
WorldGeometryEmitter emitter = new WorldGeometryEmitter(this, matrixStack.peek(), getBuffer(layer));
emitter.emitCube(min, max, rgbaColor);
}
public void drawLine(Vec3d start, Vec3d end, double width, int rgbaColor, boolean depthTest) {
Objects.requireNonNull(start, "start");
Objects.requireNonNull(end, "end");
if (!Double.isFinite(width)) {
throw new IllegalArgumentException("Line width must be finite.");
}
if (width < 0.0D) {
throw new IllegalArgumentException("Line width cannot be negative.");
}
RenderLayer layer = depthTest ? WorldRenderLayers.LINES(width) : WorldRenderLayers.LINES_NO_DEPTH(width);
WorldGeometryEmitter emitter = new WorldGeometryEmitter(this, matrixStack.peek(), getBuffer(layer));
emitter.emitLine(start, end, rgbaColor);
}
public void drawTexturedQuad(Vec3d v0, Vec3d v1, Vec3d v2, Vec3d v3,
float u0, float v0Coord,
float u1, float v1Coord,
float u2, float v2Coord,
float u3, float v3Coord,
int rgbaColor) {
Objects.requireNonNull(v0, "v0");
Objects.requireNonNull(v1, "v1");
Objects.requireNonNull(v2, "v2");
Objects.requireNonNull(v3, "v3");
RenderLayer layer = WorldRenderLayers.TEXTURED_QUADS();
WorldGeometryEmitter emitter = new WorldGeometryEmitter(this, matrixStack.peek(), getBuffer(layer));
emitter.emitTexturedQuad(v0, v1, v2, v3, u0, v0Coord, u1, v1Coord, u2, v2Coord, u3, v3Coord, rgbaColor);
}
public void flush() {
if (closed) {
return;
}
immediate.draw();
}
@Override
public void close() {
if (closed) {
return;
}
closed = true;
try {
bufferAllocator.close();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException("Failed to release world renderer buffers.", e);
}
}
}