Skip to content

Rendering issues with structures #2

@solonovamax

Description

@solonovamax

There is an issue with how structures are rendered, due to the depth test being enabled.

Patchouli fixes this by having their own custom VertexConsumerProvider.Immediate and RenderLayer implementations: https://github.com/VazkiiMods/Patchouli/blob/1.20.x/Xplat/src/main/java/vazkii/patchouli/client/handler/MultiblockVisualizationHandler.java#L340-L389

Implementing similar code myself fixes this:

Code Diff
--- old.StructureOverlayRenderer.java	2024-05-30 23:40:17.382540109 -0400
+++ StructureOverlayRenderer.java	2024-05-30 23:40:55.880873515 -0400
@@ -16,15 +16,19 @@
 import io.wispforest.owo.ui.event.WindowResizeCallback;
 import io.wispforest.owo.ui.hud.Hud;
 import io.wispforest.owo.ui.util.Delta;
+import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
 import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
 import net.fabricmc.fabric.api.event.player.UseBlockCallback;
 import net.minecraft.block.BlockState;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gl.Framebuffer;
 import net.minecraft.client.gl.SimpleFramebuffer;
+import net.minecraft.client.render.BufferBuilder;
 import net.minecraft.client.render.LightmapTextureManager;
 import net.minecraft.client.render.OverlayTexture;
 import net.minecraft.client.render.OverlayVertexConsumer;
+import net.minecraft.client.render.RenderLayer;
+import net.minecraft.client.render.VertexConsumer;
 import net.minecraft.client.render.VertexConsumerProvider;
 import net.minecraft.client.render.VertexConsumerProvider.Immediate;
 import net.minecraft.client.render.model.ModelLoader;
@@ -44,8 +48,11 @@
 import org.apache.commons.lang3.mutable.MutableBoolean;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL30C;
+import vazkii.patchouli.api.PatchouliAPI;
+import vazkii.patchouli.mixin.client.AccessorMultiBufferSource;

 import java.util.HashMap;
+import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.function.Supplier;

@@ -140,6 +147,7 @@

             var client = MinecraftClient.getInstance();
             var effectConsumers = client.getBufferBuilders().getEffectVertexConsumers();
+            var buffers = initBuffers(client.getBufferBuilders().getEntityVertexConsumers());
             var testPos = new BlockPos.Mutable();

             hudComponent.<FlowLayout>configure(layout -> {
@@ -179,7 +187,7 @@
                             }

                             if (entry.visibleLayer != -1 && pos.getY() != entry.visibleLayer) return;
-                            renderOverlayBlock(matrices, context.consumers(), pos, predicate, entry.rotation);
+                            renderOverlayBlock(matrices, buffers, pos, predicate, entry.rotation);

                         }, entry.rotation);

@@ -228,13 +236,14 @@
                         if (!client.player.isSneaking()) targetPos = targetPos.offset(target.getSide());

                         matrices.translate(targetPos.getX(), targetPos.getY(), targetPos.getZ());
-                        structure.forEachPredicate((pos, predicate) -> renderOverlayBlock(matrices, context.consumers(), pos, predicate, PENDING_OVERLAY.rotation), PENDING_OVERLAY.rotation);
+                        structure.forEachPredicate((pos, predicate) -> renderOverlayBlock(matrices, buffers, pos, predicate, PENDING_OVERLAY.rotation), PENDING_OVERLAY.rotation);
                     }
                 } else {
                     PENDING_OVERLAY = null;
                 }
             }

+            // buffers.
             matrices.pop();

             var framebuffer = FRAMEBUFFER.get();
@@ -244,7 +252,9 @@
             GL30C.glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, client.getFramebuffer().fbo);
             GL30C.glBlitFramebuffer(0, 0, framebuffer.textureWidth, framebuffer.textureHeight, 0, 0, client.getFramebuffer().textureWidth, client.getFramebuffer().textureHeight, GL30C.GL_DEPTH_BUFFER_BIT, GL30C.GL_NEAREST);

-            if (context.consumers() instanceof VertexConsumerProvider.Immediate immediate) immediate.draw();
+            // if (context.consumers() instanceof VertexConsumerProvider.Immediate immediate)
+            //     immediate.draw();
+            buffers.draw();
             effectConsumers.draw();
             client.getFramebuffer().beginWrite(false);

@@ -329,4 +339,61 @@
         }
     }

+    private static VertexConsumerProvider.Immediate initBuffers(VertexConsumerProvider.Immediate original) {
+		BufferBuilder fallback = ((AccessorMultiBufferSource) original).getFallbackBuffer();
+		Map<RenderLayer, BufferBuilder> layerBuffers = ((AccessorMultiBufferSource) original).getFixedBuffers();
+		Map<RenderLayer, BufferBuilder> remapped = new Object2ObjectLinkedOpenHashMap<>();
+		for (Map.Entry<RenderLayer, BufferBuilder> e : layerBuffers.entrySet()) {
+			remapped.put(GhostRenderLayer.remap(e.getKey()), e.getValue());
+		}
+		return new GhostVertexConsumerProvider(fallback, remapped);
+	}
+
+    private static class GhostVertexConsumerProvider extends VertexConsumerProvider.Immediate {
+
+        protected GhostVertexConsumerProvider(BufferBuilder fallbackBuffer, Map<RenderLayer, BufferBuilder> layerBuffers) {
+            super(fallbackBuffer, layerBuffers);
+        }
+
+        @Override
+        public VertexConsumer getBuffer(RenderLayer renderLayer) {
+            return super.getBuffer(GhostRenderLayer.remap(renderLayer));
+        }
+    }
+
+    private static class GhostRenderLayer extends RenderLayer {
+        private static final Map<RenderLayer, RenderLayer> remappedTypes = new IdentityHashMap<>();
+
+        private GhostRenderLayer(RenderLayer original) {
+            super(
+                    String.format("%s_%s_ghost", original.toString(), PatchouliAPI.MOD_ID),
+                    original.getVertexFormat(),
+                    original.getDrawMode(),
+                    original.getExpectedBufferSize(),
+                    original.hasCrumbling(),
+                    true,
+                    () -> {
+                        original.startDrawing();
+
+                        RenderSystem.disableDepthTest();
+                        RenderSystem.enableBlend();
+                        RenderSystem.setShaderColor(1, 1, 1, 0.75f);
+                    },
+                    () -> {
+                        RenderSystem.setShaderColor(1, 1, 1, 1);
+                        RenderSystem.disableBlend();
+                        RenderSystem.enableDepthTest();
+
+                        original.endDrawing();
+                    }
+            );
+        }
+
+        public static RenderLayer remap(RenderLayer in) {
+            if (in instanceof GhostRenderLayer)
+                return in;
+            else
+                return GhostRenderLayer.remappedTypes.computeIfAbsent(in, GhostRenderLayer::new);
+        }
+    }
 }
however, I'm also not a rendering person so I'm unsure of what like 75% of that code does, and it very well could be redundant or could be able to be avoided.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions