Skip to content

Commit

Permalink
Improve radius descriptor rendering for high coordinate values
Browse files Browse the repository at this point in the history
Fixes #4651 and also reduces potential Z-fighting between the flat shapes rendered by Gaia landmines, luminizer binding radius descriptors, and flower radius descriptors.
  • Loading branch information
TheRealWormbo committed May 25, 2024
1 parent f947257 commit 232f95c
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,23 @@ public final class RenderHelper extends RenderType {

private static final int ITEM_AND_PADDING_WIDTH = 20;

private static final double INITIAL_OFFSET = 0.005;
private static final double OFFSET_INCREMENT = 0.001;
// Global y offset so that overlapping landmines or radius descriptors do not Z-fight
private static double offY = INITIAL_OFFSET;

public static double getOffY() {
return offY;
}

public static void incrementOffY() {
offY += OFFSET_INCREMENT;
}

public static void onWorldRenderLast() {
offY = INITIAL_OFFSET;
}

private static RenderType makeLayer(String name, VertexFormat format, VertexFormat.Mode mode,
int bufSize, boolean hasCrumbling, boolean sortOnUpload, CompositeState glState) {
return RenderTypeAccessor.create(name, format, mode, bufSize, hasCrumbling, sortOnUpload, glState);
Expand Down Expand Up @@ -324,6 +341,15 @@ public static void triangleFan(Runnable center, List<Runnable> vertices) {
}
}

public static void flatRectangle(VertexConsumer buffer, Matrix4f mat,
float xMin, float xMax, float y, float zMin, float zMax,
int r, int g, int b, int a) {
buffer.vertex(mat, xMax, y, zMin).color(r, g, b, a).endVertex();
buffer.vertex(mat, xMin, y, zMin).color(r, g, b, a).endVertex();
buffer.vertex(mat, xMin, y, zMax).color(r, g, b, a).endVertex();
buffer.vertex(mat, xMax, y, zMax).color(r, g, b, a).endVertex();
}

public static void renderProgressPie(GuiGraphics gui, int x, int y, float progress, ItemStack stack) {
PoseStack ms = gui.pose();
Minecraft mc = Minecraft.getInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@
import vazkii.botania.common.item.WandOfTheForestItem;
import vazkii.botania.common.item.equipment.bauble.ManaseerMonocleItem;

import java.util.ArrayList;
import java.util.List;

public class SpecialFlowerBlockEntityRenderer<T extends SpecialFlowerBlockEntity> implements BlockEntityRenderer<T> {

public static final int INNER_ALPHA = 32;
public static final int OUTER_ALPHA = 64;
public static final float FRAME_WIDTH = 1F / 16F;
public static final float Y_OFFSET_INNER = 1F / 16F;
public static final float Y_OFFSET_OUTER = FRAME_WIDTH + FRAME_WIDTH / 4F;
public static final int TOTAL_ANGLES = 360;
public static final double DEGREES_TO_RADIAN = (Math.PI / (double) (TOTAL_ANGLES / 2));

public SpecialFlowerBlockEntityRenderer(BlockEntityRendererProvider.Context ctx) {}

@Override
Expand Down Expand Up @@ -77,12 +83,13 @@ public void render(SpecialFlowerBlockEntity tile, float partialTicks, PoseStack
public static void renderRadius(BlockEntity tile, PoseStack ms, MultiBufferSource buffers, @Nullable RadiusDescriptor descriptor) {
if (descriptor != null) {
ms.pushPose();
ms.translate(-tile.getBlockPos().getX(), -tile.getBlockPos().getY(), -tile.getBlockPos().getZ());
ms.translate(0, RenderHelper.getOffY(), 0);
if (descriptor instanceof RadiusDescriptor.Circle circle) {
renderCircle(ms, buffers, circle.subtileCoords(), circle.radius());
renderCircle(ms, buffers, tile.getBlockPos(), circle.subtileCoords(), circle.radius());
} else if (descriptor instanceof RadiusDescriptor.Rectangle rectangle) {
renderRectangle(ms, buffers, rectangle.aabb(), true, null, (byte) 32);
renderRectangle(ms, buffers, tile.getBlockPos(), rectangle.aabb());
}
RenderHelper.incrementOffY();
ms.popPose();
}
}
Expand All @@ -95,87 +102,67 @@ public static boolean hasBindingAttempt(LivingEntity view, BlockPos tilePos) {
return false;
}

private static void renderCircle(PoseStack ms, MultiBufferSource buffers, BlockPos center, double radius) {
public static void renderCircle(PoseStack ms, MultiBufferSource buffers, BlockPos tilePos, BlockPos center, double radius) {
ms.pushPose();
double x = center.getX() + 0.5;
double y = center.getY();
double z = center.getZ() + 0.5;
ms.translate(x, y, z);
ms.translate(center.getX() - tilePos.getX() + 0.5, center.getY() - tilePos.getY(), center.getZ() - tilePos.getZ() + 0.5);

int color = Mth.hsvToRgb(ClientTickHandler.ticksInGame % 200 / 200F, 0.6F, 1F);
int r = (color >> 16 & 0xFF);
int g = (color >> 8 & 0xFF);
int b = (color & 0xFF);

int alpha = 32;
float f = 1F / 16F;

int totalAngles = 360;
int drawAngles = 360;
int step = totalAngles / drawAngles;

radius -= f;
VertexConsumer buffer = buffers.getBuffer(RenderHelper.CIRCLE);
Matrix4f mat = ms.last().pose();

Runnable centerFunc = () -> buffer.vertex(mat, 0, f, 0).color(r, g, b, alpha).endVertex();
List<Runnable> vertexFuncs = new ArrayList<>();
for (int i = 0; i < totalAngles + 1; i += step) {
double rad = (totalAngles - i) * Math.PI / 180.0;
float xp = (float) (Math.cos(rad) * radius);
float zp = (float) (Math.sin(rad) * radius);
vertexFuncs.add(() -> buffer.vertex(mat, xp, f, zp).color(r, g, b, alpha).endVertex());
}
RenderHelper.triangleFan(centerFunc, vertexFuncs);

radius += f;
float f1 = f + f / 4F;
int alpha2 = 64;

centerFunc = () -> buffer.vertex(mat, 0, f1, 0).color(r, g, b, alpha2).endVertex();
vertexFuncs.clear();
for (int i = 0; i < totalAngles + 1; i += step) {
double rad = (totalAngles - i) * Math.PI / 180.0;
float xp = (float) (Math.cos(rad) * radius);
float zp = (float) (Math.sin(rad) * radius);
vertexFuncs.add(() -> buffer.vertex(mat, xp, f1, zp).color(r, g, b, alpha2).endVertex());
double innerRadius = radius - FRAME_WIDTH;
Runnable centerFuncInner = () -> buffer.vertex(mat, 0, Y_OFFSET_INNER, 0).color(r, g, b, INNER_ALPHA).endVertex();
Runnable centerFuncOuter = () -> buffer.vertex(mat, 0, Y_OFFSET_OUTER, 0).color(r, g, b, OUTER_ALPHA).endVertex();
Runnable[] vertexFuncsInner = new Runnable[TOTAL_ANGLES + 1];
Runnable[] vertexFuncsOuter = new Runnable[TOTAL_ANGLES + 1];

for (int i = 0; i < TOTAL_ANGLES; i++) {
double rad = (TOTAL_ANGLES - i) * DEGREES_TO_RADIAN;
double cos = Math.cos(rad);
double sin = Math.sin(rad);

float xpInner = (float) (cos * innerRadius);
float zpInner = (float) (sin * innerRadius);
vertexFuncsInner[i] = (() -> buffer.vertex(mat, xpInner, Y_OFFSET_INNER, zpInner).color(r, g, b, INNER_ALPHA).endVertex());

float xpOuter = (float) (Math.cos(rad) * radius);
float zpOuter = (float) (Math.sin(rad) * radius);
vertexFuncsOuter[i] = (() -> buffer.vertex(mat, xpOuter, Y_OFFSET_OUTER, zpOuter).color(r, g, b, OUTER_ALPHA).endVertex());
}
RenderHelper.triangleFan(centerFunc, vertexFuncs);
vertexFuncsInner[TOTAL_ANGLES] = vertexFuncsInner[0];
vertexFuncsOuter[TOTAL_ANGLES] = vertexFuncsOuter[0];

RenderHelper.triangleFan(centerFuncInner, vertexFuncsInner);
RenderHelper.triangleFan(centerFuncOuter, vertexFuncsOuter);

ms.popPose();
}

public static void renderRectangle(PoseStack ms, MultiBufferSource buffers, AABB aabb, boolean inner, @Nullable Integer color, byte alpha) {
public static void renderRectangle(PoseStack ms, MultiBufferSource buffers, BlockPos tilePos, AABB aabb) {
ms.pushPose();
ms.translate(aabb.minX, aabb.minY, aabb.minZ);
ms.translate(aabb.minX - tilePos.getX(), aabb.minY - tilePos.getY(), aabb.minZ - tilePos.getZ());

if (color == null) {
color = Mth.hsvToRgb(ClientTickHandler.ticksInGame % 200 / 200F, 0.6F, 1F);
}
int color = Mth.hsvToRgb(ClientTickHandler.ticksInGame % 200 / 200F, 0.6F, 1F);
int r = (color >> 16 & 0xFF);
int g = (color >> 8 & 0xFF);
int b = (color & 0xFF);

float f = 1F / 16F;
float x = (float) (aabb.maxX - aabb.minX - f);
float z = (float) (aabb.maxZ - aabb.minZ - f);
float xSize = (float) aabb.getXsize();
float zSize = (float) aabb.getZsize();
float xSizeInner = xSize - FRAME_WIDTH;
float zSizeInner = zSize - FRAME_WIDTH;

VertexConsumer buffer = buffers.getBuffer(RenderHelper.RECTANGLE);
Matrix4f mat = ms.last().pose();
buffer.vertex(mat, x, f, f).color(r, g, b, alpha).endVertex();
buffer.vertex(mat, f, f, f).color(r, g, b, alpha).endVertex();
buffer.vertex(mat, f, f, z).color(r, g, b, alpha).endVertex();
buffer.vertex(mat, x, f, z).color(r, g, b, alpha).endVertex();

if (inner) {
x += f;
z += f;
float f1 = f + f / 4F;
alpha *= 2;
buffer.vertex(mat, x, f1, 0).color(r, g, b, alpha).endVertex();
buffer.vertex(mat, 0, f1, 0).color(r, g, b, alpha).endVertex();
buffer.vertex(mat, 0, f1, z).color(r, g, b, alpha).endVertex();
buffer.vertex(mat, x, f1, z).color(r, g, b, alpha).endVertex();
}
RenderHelper.flatRectangle(buffer, mat, FRAME_WIDTH, xSizeInner, Y_OFFSET_INNER, FRAME_WIDTH, zSizeInner,
r, g, b, INNER_ALPHA);
RenderHelper.flatRectangle(buffer, mat, 0, xSize, Y_OFFSET_OUTER, 0, zSize, r, g, b, OUTER_ALPHA);

ms.popPose();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package vazkii.botania.client.render.entity;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;

import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRenderer;
Expand All @@ -18,24 +19,18 @@
import net.minecraft.world.phys.AABB;

import org.jetbrains.annotations.NotNull;
import org.joml.Matrix4f;

import vazkii.botania.client.core.handler.ClientTickHandler;
import vazkii.botania.client.render.block_entity.SpecialFlowerBlockEntityRenderer;
import vazkii.botania.client.core.helper.RenderHelper;
import vazkii.botania.common.entity.MagicLandmineEntity;

public class MagicLandmineRenderer extends EntityRenderer<MagicLandmineEntity> {
private static final double INITIAL_OFFSET = -1.0 / 16 + 0.005;
// Global y offset so that overlapping landmines do not Z-fight
public static double offY = INITIAL_OFFSET;

public MagicLandmineRenderer(EntityRendererProvider.Context ctx) {
super(ctx);
}

public static void onWorldRenderLast() {
offY = INITIAL_OFFSET;
}

@Override
public void render(MagicLandmineEntity e, float entityYaw, float partialTicks, PoseStack ms, MultiBufferSource buffers, int light) {
super.render(e, entityYaw, partialTicks, ms, buffers, light);
Expand All @@ -47,7 +42,6 @@ public void render(MagicLandmineEntity e, float entityYaw, float partialTicks, P
int r = (int) (105 * gs);
int g = (int) (25 * gs);
int b = (int) (145 * gs);
int color = r << 16 | g << 8 | b;

int alpha = 32;
if (e.tickCount < 8) {
Expand All @@ -56,8 +50,16 @@ public void render(MagicLandmineEntity e, float entityYaw, float partialTicks, P
alpha *= Math.min(1F - (e.tickCount - 47 + partialTicks) / 8F, 1F);
}

SpecialFlowerBlockEntityRenderer.renderRectangle(ms, buffers, aabb, false, color, (byte) alpha);
offY += 0.001;
ms.translate(aabb.minX, aabb.minY + RenderHelper.getOffY(), aabb.minZ);

float f = 1F / 16F;
float x = (float) (aabb.getXsize() - f);
float z = (float) (aabb.getZsize() - f);

VertexConsumer buffer = buffers.getBuffer(RenderHelper.RECTANGLE);
Matrix4f mat = ms.last().pose();
RenderHelper.flatRectangle(buffer, mat, f, x, 0, f, z, r, g, b, alpha);
RenderHelper.incrementOffY();
ms.popPose();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import net.minecraft.client.renderer.RenderBuffers;
import net.minecraft.world.level.Level;

import vazkii.botania.client.core.helper.RenderHelper;
import vazkii.botania.client.fx.BoltRenderer;
import vazkii.botania.client.render.entity.MagicLandmineRenderer;
import vazkii.botania.common.item.AssemblyHaloItem;

public final class WorldOverlays {
Expand All @@ -16,7 +16,7 @@ public static void renderWorldLast(Camera camera, float tickDelta, PoseStack mat
AssemblyHaloItem.Rendering.onRenderWorldLast(camera, tickDelta, matrix, buffers);
BoundBlockRenderer.onWorldRenderLast(camera, matrix, level);
AstrolabePreviewHandler.onWorldRenderLast(matrix, buffers, level);
MagicLandmineRenderer.onWorldRenderLast();
RenderHelper.onWorldRenderLast();
}

private WorldOverlays() {}
Expand Down

0 comments on commit 232f95c

Please sign in to comment.