From 80500a74c8d21750b6434c7c51ffb506803238c9 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 27 Jan 2024 04:08:56 +0000 Subject: [PATCH] Improve portal rendering --- .../unicopia/client/URenderers.java | 2 + .../AbstractGeometryBasedParticle.java | 2 +- .../unicopia/client/render/RenderUtil.java | 38 ++++++++++++------- .../client/render/bezier/BezierSegment.java | 8 ++-- .../client/render/model/BakedModel.java | 34 ++++++++++++----- .../client/render/shader/UShaders.java | 29 ++++++++++++++ .../render/spell/PortalFrameBuffer.java | 35 ++++++++++------- .../render/spell/PortalSpellRenderer.java | 4 +- .../core/rendertype_portal_surface.fsh | 20 ++++++++++ .../core/rendertype_portal_surface.json | 20 ++++++++++ .../core/rendertype_portal_surface.vsh | 19 ++++++++++ 11 files changed, 169 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/render/shader/UShaders.java create mode 100644 src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.fsh create mode 100644 src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.json create mode 100644 src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.vsh diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index c09bbf8e..ebe72254 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -23,6 +23,7 @@ import com.minelittlepony.unicopia.client.particle.ShockwaveParticle; import com.minelittlepony.unicopia.client.particle.SphereParticle; import com.minelittlepony.unicopia.client.render.*; import com.minelittlepony.unicopia.client.render.entity.*; +import com.minelittlepony.unicopia.client.render.shader.UShaders; import com.minelittlepony.unicopia.client.render.spell.SpellRendererFactory; import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.item.ChameleonItem; @@ -128,6 +129,7 @@ public interface URenderers { TerraformBoatClientHelper.registerModelLayers(Unicopia.id("palm"), false); SpellRendererFactory.bootstrap(); + UShaders.bootstrap(); } private static void register(DynamicItemRenderer renderer, ItemConvertible...items) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/AbstractGeometryBasedParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/AbstractGeometryBasedParticle.java index 297c2e65..1714d93a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/AbstractGeometryBasedParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/AbstractGeometryBasedParticle.java @@ -42,7 +42,7 @@ public abstract class AbstractGeometryBasedParticle extends Particle { int light = getBrightness(tickDelta); buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); for (RenderUtil.Vertex corner : corners) { - buffer.vertex(corner.position().x, corner.position().y, corner.position().z).texture(corner.u(), corner.v()).color(red, green, blue, alpha).light(light).next(); + buffer.vertex(corner.position().x, corner.position().y, corner.position().z).texture(corner.texture().x, corner.texture().y).color(red, green, blue, alpha).light(light).next(); } te.draw(); } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java b/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java index a9cbbd1e..cb43a128 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java @@ -1,5 +1,6 @@ package com.minelittlepony.unicopia.client.render; +import org.joml.Matrix4f; import org.joml.Vector3f; import org.joml.Vector4f; @@ -11,17 +12,18 @@ import net.minecraft.client.util.math.MatrixStack; public class RenderUtil { public static final Vector4f TEMP_VECTOR = new Vector4f(); + private static final Vector4f TEMP_UV_VECTOR = new Vector4f(); public static final Vertex[] UNIT_FACE = new Vertex[] { - new Vertex(new Vector3f(0, 0, 0), 1, 1), - new Vertex(new Vector3f(0, 1, 0), 1, 0), - new Vertex(new Vector3f(1, 1, 0), 0, 0), - new Vertex(new Vector3f(1, 0, 0), 0, 1) + new Vertex(0, 0, 0, 1, 1), + new Vertex(0, 1, 0, 1, 0), + new Vertex(1, 1, 0, 0, 0), + new Vertex(1, 0, 0, 0, 1) }; public static final Vertex[] FRAME_BUFFER_VERTICES = new Vertex[] { - new Vertex(new Vector3f(0, 1, 0), 0, 0), - new Vertex(new Vector3f(1, 1, 0), 1, 0), - new Vertex(new Vector3f(1, 0, 0), 1, 1), - new Vertex(new Vector3f(0, 0, 0), 0, 1) + new Vertex(0, 1, 0, 0, 0), + new Vertex(1, 1, 0, 1, 0), + new Vertex(1, 0, 0, 1, 1), + new Vertex(0, 0, 0, 0, 1) }; public static void renderFace(MatrixStack matrices, Tessellator te, BufferBuilder buffer, float r, float g, float b, float a, int light) { @@ -30,17 +32,25 @@ public class RenderUtil { public static void renderFace(MatrixStack matrices, Tessellator te, BufferBuilder buffer, float r, float g, float b, float a, int light, float uScale, float vScale) { buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); + Matrix4f positionmatrix = matrices.peek().getPositionMatrix(); for (Vertex vertex : UNIT_FACE) { - Vector4f position = vertex.position(matrices); - buffer.vertex(position.x, position.y, position.z).texture(vertex.u() * uScale, vertex.v() * vScale).color(r, g, b, a).light(light).next(); + Vector4f position = vertex.position(positionmatrix); + buffer.vertex(position.x, position.y, position.z).texture(vertex.texture().x * uScale, vertex.texture().y * vScale).color(r, g, b, a).light(light).next(); } te.draw(); } - public record Vertex(Vector3f position, float u, float v) { - public Vector4f position(MatrixStack matrices) { - matrices.peek().getPositionMatrix().transform(TEMP_VECTOR.set(position, 1)); - return TEMP_VECTOR; + public record Vertex(Vector3f position, Vector3f texture) { + public Vertex(float x, float y, float z, float u, float v) { + this(new Vector3f(x, y, z), new Vector3f(u, v, 1)); + } + + public Vector4f position(Matrix4f mat) { + return mat.transform(TEMP_VECTOR.set(position, 1)); + } + + public Vector4f texture(Matrix4f mat) { + return mat.transform(TEMP_UV_VECTOR.set(texture, 1)); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/bezier/BezierSegment.java b/src/main/java/com/minelittlepony/unicopia/client/render/bezier/BezierSegment.java index d8ce8d35..bb30b1f5 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/bezier/BezierSegment.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/bezier/BezierSegment.java @@ -12,10 +12,10 @@ public record BezierSegment( public BezierSegment(Vector3f from, Vector3f to, float height) { this(new RenderUtil.Vertex[] { - new RenderUtil.Vertex(new Vector3f(from.x, from.y - height/2F, from.z), 0, 0), // bottom left - new RenderUtil.Vertex(new Vector3f(from.x, from.y + height/2F, from.z), 1, 0), // top left - new RenderUtil.Vertex(new Vector3f(to.x, to.y + height/2F, to.z), 1, 1), // top right - new RenderUtil.Vertex(new Vector3f(to.x, to.y - height/2F, to.z), 0, 1) // bottom right + new RenderUtil.Vertex(from.x, from.y - height/2F, from.z, 0, 0), // bottom left + new RenderUtil.Vertex(from.x, from.y + height/2F, from.z, 1, 0), // top left + new RenderUtil.Vertex(to.x, to.y + height/2F, to.z, 1, 1), // top right + new RenderUtil.Vertex(to.x, to.y - height/2F, to.z, 0, 1) // bottom right }); } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/model/BakedModel.java b/src/main/java/com/minelittlepony/unicopia/client/render/model/BakedModel.java index d2c03914..3bceca54 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/model/BakedModel.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/model/BakedModel.java @@ -1,25 +1,35 @@ package com.minelittlepony.unicopia.client.render.model; -import java.util.ArrayList; import java.util.List; -import org.joml.Vector3f; +import org.joml.Matrix4f; import org.joml.Vector4f; import com.minelittlepony.unicopia.client.render.RenderUtil; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.util.math.MatrixStack; public class BakedModel { - protected final List vertices = new ArrayList<>(); + protected final List vertices = new ObjectArrayList<>(); + + private final Matrix4f textureMatrix = new Matrix4f(); + + public Matrix4f getTextureMatrix() { + return textureMatrix; + } + + public void scaleUV(float uScale, float vScale) { + getTextureMatrix().scale(uScale, vScale, 1); + } protected void addVertex(Vector4f vertex) { addVertex(vertex.x, vertex.y, vertex.z, (vertex.x + 1) * 0.5F, (vertex.z + 1) * 0.5F); } protected void addVertex(float x, float y, float z, float u, float v) { - vertices.add(new RenderUtil.Vertex(new Vector3f(x, y, z), u, v)); + vertices.add(new RenderUtil.Vertex(x, y, z, u, v)); } public final void render(MatrixStack matrices, VertexConsumer buffer, int light, int overlay, float scale, float r, float g, float b, float a) { @@ -30,14 +40,17 @@ public class BakedModel { matrices.push(); matrices.scale(scale, scale, scale); + Matrix4f positionmatrix = matrices.peek().getPositionMatrix(); for (RenderUtil.Vertex vertex : vertices) { - Vector4f pos = vertex.position(matrices); - buffer.vertex(pos.x, pos.y, pos.z, r, g, b, a, vertex.u(), vertex.v(), overlay, light, 0, 0, 0); + Vector4f pos = vertex.position(positionmatrix); + Vector4f tex = vertex.texture(textureMatrix); + buffer.vertex(pos.x, pos.y, pos.z, r, g, b, a, tex.x, tex.y, overlay, light, 0, 0, 0); } matrices.pop(); + textureMatrix.identity(); } - public final void render(MatrixStack matrices, VertexConsumer buffer, float scale, float r, float g, float b, float a, float uScale, float vScale) { + public final void render(MatrixStack matrices, VertexConsumer buffer, float scale, float r, float g, float b, float a) { scale = Math.abs(scale); if (scale < 0.001F) { return; @@ -45,10 +58,13 @@ public class BakedModel { matrices.push(); matrices.scale(scale, scale, scale); + Matrix4f positionmatrix = matrices.peek().getPositionMatrix(); for (RenderUtil.Vertex vertex : vertices) { - Vector4f pos = vertex.position(matrices); - buffer.vertex(pos.x, pos.y, pos.z).texture(vertex.u() * uScale, vertex.v() * vScale).color(r, g, b, a).next(); + Vector4f pos = vertex.position(positionmatrix); + Vector4f tex = vertex.texture(textureMatrix); + buffer.vertex(pos.x, pos.y, pos.z).texture(tex.x, tex.y).color(r, g, b, a).next(); } matrices.pop(); + textureMatrix.identity(); } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/shader/UShaders.java b/src/main/java/com/minelittlepony/unicopia/client/render/shader/UShaders.java new file mode 100644 index 00000000..fd86786d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/shader/UShaders.java @@ -0,0 +1,29 @@ +package com.minelittlepony.unicopia.client.render.shader; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.Unicopia; +import net.fabricmc.fabric.api.client.rendering.v1.CoreShaderRegistrationCallback; +import net.minecraft.client.gl.ShaderProgram; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormats; + +public final class UShaders { + @Nullable + private static Supplier renderTypePortalSurfaceProgram = register("rendertype_portal_surface", VertexFormats.POSITION_COLOR); + + public static ShaderProgram getRenderTypePortalSurfaceProgram() { + return renderTypePortalSurfaceProgram.get(); + } + + public static void bootstrap() { } + + static Supplier register(String name, VertexFormat format) { + AtomicReference holder = new AtomicReference<>(); + CoreShaderRegistrationCallback.EVENT.register(context -> context.register(Unicopia.id(name), format, holder::set)); + return holder::get; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java index f864c098..161d667e 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java @@ -15,6 +15,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.PortalSpell; import com.minelittlepony.unicopia.client.render.RenderLayers; import com.minelittlepony.unicopia.client.render.model.SphereModel; +import com.minelittlepony.unicopia.client.render.shader.UShaders; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.mixin.client.MixinMinecraftClient; @@ -30,7 +31,6 @@ import net.minecraft.client.render.BackgroundRenderer; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Camera; import net.minecraft.client.render.Frustum; -import net.minecraft.client.render.GameRenderer; import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexFormat; @@ -41,6 +41,7 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; import net.minecraft.screen.PlayerScreenHandler; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; class PortalFrameBuffer implements AutoCloseable { @@ -92,10 +93,14 @@ class PortalFrameBuffer implements AutoCloseable { BufferBuilder buffer = tessellator.getBuffer(); float uScale = (float)framebuffer.viewportWidth / (float)framebuffer.textureWidth; float vScale = (float)framebuffer.viewportHeight / (float)framebuffer.textureHeight; - RenderSystem.setShader(GameRenderer::getPositionTexColorProgram); + RenderSystem.setShader(UShaders::getRenderTypePortalSurfaceProgram); + //RenderSystem.setShader(GameRenderer::getPositionTexColorProgram); RenderSystem._setShaderTexture(0, framebuffer.getColorAttachment()); buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR); - SphereModel.DISK.render(matrices, buffer, 2F, 1, 1, 1, 1, uScale, vScale); + SphereModel.DISK.scaleUV(uScale, vScale); + + RenderSystem.setTextureMatrix(SphereModel.DISK.getTextureMatrix()); + SphereModel.DISK.render(matrices, buffer, 2F, 1, 1, 1, 1); tessellator.draw(); client.getTextureManager().bindTexture(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE); @@ -110,11 +115,11 @@ class PortalFrameBuffer implements AutoCloseable { public void build(PortalSpell spell, Caster caster, EntityReference.EntityValues target) { - if (framebuffer != null && System.currentTimeMillis() % 100 != 0) { + if (framebuffer != null && System.currentTimeMillis() % 1 != 0) { return; } - if (pendingDraw && recursionCount > 0) { + if (pendingDraw && recursionCount > 2) { innerBuild(spell, caster, target); return; } @@ -134,7 +139,7 @@ class PortalFrameBuffer implements AutoCloseable { synchronized (client) { pendingDraw = false; - if (recursionCount > 2) { + if (recursionCount > 0) { return; } recursionCount++; @@ -149,10 +154,17 @@ class PortalFrameBuffer implements AutoCloseable { int originalFov = fov.getValue(); fov.setValue(110); + Camera camera = client.gameRenderer.getCamera(); + Entity cameraEntity = UEntities.CAST_SPELL.create(caster.asWorld()); - cameraEntity.setPosition(target.pos()); - cameraEntity.setPitch(spell.getTargetPitch()); - cameraEntity.setYaw(spell.getTargetYaw() + 180); + Vec3d offset = new Vec3d(0, -0.2F, -0.2F).rotateY(-spell.getTargetYaw() * MathHelper.RADIANS_PER_DEGREE); + + float yaw = spell.getTargetYaw() + camera.getYaw() - spell.getYaw() + 180; + float pitch = spell.getTargetPitch() + (camera.getPitch() - spell.getPitch()) * 1.65F; + + cameraEntity.setPosition(target.pos().add(offset)); + cameraEntity.setPitch(pitch); + cameraEntity.setYaw(yaw); drawWorld(cameraEntity, 400, 400); @@ -220,11 +232,8 @@ class PortalFrameBuffer implements AutoCloseable { renderer.scheduleBlockRenders((int)cameraEntity.getX() / 16, (int)cameraEntity.getY() / 16, (int)cameraEntity.getZ() / 16); client.gameRenderer.setRenderHand(false); - MatrixStack matrices = new MatrixStack(); - matrices.scale((float)width / height, 1, 1); - - client.gameRenderer.renderWorld(1, 0, matrices); + client.gameRenderer.renderWorld(1, 0, new MatrixStack()); // Strip transparency RenderSystem.colorMask(false, false, false, true); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java index 4324ef30..a509d1fc 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java @@ -5,7 +5,6 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.PortalSpell; import com.minelittlepony.unicopia.client.render.RenderLayers; import com.minelittlepony.unicopia.client.render.model.SphereModel; import com.minelittlepony.unicopia.entity.EntityReference; - import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.Frustum; @@ -49,6 +48,9 @@ public class PortalSpellRenderer extends SpellRenderer { if (caster.asEntity().distanceTo(client.cameraEntity) > 50) { return; // don't bother rendering if too far away } + if (client.cameraEntity == caster.asEntity()) { + return; + } matrices.push(); matrices.scale(strength, strength, strength); diff --git a/src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.fsh b/src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.fsh new file mode 100644 index 00000000..09b197aa --- /dev/null +++ b/src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.fsh @@ -0,0 +1,20 @@ +#version 150 + +#moj_import + +uniform sampler2D Sampler0; +uniform sampler2D Sampler1; + +uniform vec4 ColorModulator; +uniform float GameTime; +uniform int EndPortalLayers; + +in vec4 texProj0; +in vec4 vertexColor; + +out vec4 fragColor; + +void main() { + vec4 scale = vec4(0.25, 0.25, 0.25, 0.25); + fragColor = textureProj(Sampler0, texProj0 * scale); +} diff --git a/src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.json b/src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.json new file mode 100644 index 00000000..4c978b4f --- /dev/null +++ b/src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.json @@ -0,0 +1,20 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha" + }, + "vertex": "unicopia:rendertype_portal_surface", + "fragment": "unicopia:rendertype_portal_surface", + "attributes": [], + "samplers": [ + { "name": "Sampler0" }, + { "name": "Sampler1" } + ], + "uniforms": [ + { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "GameTime", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "EndPortalLayers", "type": "int", "count": 1, "values": [ 15 ] } + ] +} diff --git a/src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.vsh b/src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.vsh new file mode 100644 index 00000000..42aadd7b --- /dev/null +++ b/src/main/resources/assets/unicopia/shaders/core/rendertype_portal_surface.vsh @@ -0,0 +1,19 @@ +#version 150 + +#moj_import + +in vec3 Position; +in vec4 Color; + +uniform mat4 ModelViewMat; +uniform mat4 ProjMat; + +out vec4 texProj0; +out vec4 vertexColor; + +void main() { + gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); + + vertexColor = Color; + texProj0 = projection_from_position(gl_Position); +}