Improve portal rendering

This commit is contained in:
Sollace 2024-01-27 04:08:56 +00:00
parent da3aec8d83
commit 80500a74c8
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
11 changed files with 169 additions and 42 deletions

View file

@ -23,6 +23,7 @@ import com.minelittlepony.unicopia.client.particle.ShockwaveParticle;
import com.minelittlepony.unicopia.client.particle.SphereParticle; import com.minelittlepony.unicopia.client.particle.SphereParticle;
import com.minelittlepony.unicopia.client.render.*; import com.minelittlepony.unicopia.client.render.*;
import com.minelittlepony.unicopia.client.render.entity.*; 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.client.render.spell.SpellRendererFactory;
import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.item.ChameleonItem; import com.minelittlepony.unicopia.item.ChameleonItem;
@ -128,6 +129,7 @@ public interface URenderers {
TerraformBoatClientHelper.registerModelLayers(Unicopia.id("palm"), false); TerraformBoatClientHelper.registerModelLayers(Unicopia.id("palm"), false);
SpellRendererFactory.bootstrap(); SpellRendererFactory.bootstrap();
UShaders.bootstrap();
} }
private static void register(DynamicItemRenderer renderer, ItemConvertible...items) { private static void register(DynamicItemRenderer renderer, ItemConvertible...items) {

View file

@ -42,7 +42,7 @@ public abstract class AbstractGeometryBasedParticle extends Particle {
int light = getBrightness(tickDelta); int light = getBrightness(tickDelta);
buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT);
for (RenderUtil.Vertex corner : corners) { 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(); te.draw();
} }

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.client.render; package com.minelittlepony.unicopia.client.render;
import org.joml.Matrix4f;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.joml.Vector4f; import org.joml.Vector4f;
@ -11,17 +12,18 @@ import net.minecraft.client.util.math.MatrixStack;
public class RenderUtil { public class RenderUtil {
public static final Vector4f TEMP_VECTOR = new Vector4f(); 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[] { public static final Vertex[] UNIT_FACE = new Vertex[] {
new Vertex(new Vector3f(0, 0, 0), 1, 1), new Vertex(0, 0, 0, 1, 1),
new Vertex(new Vector3f(0, 1, 0), 1, 0), new Vertex(0, 1, 0, 1, 0),
new Vertex(new Vector3f(1, 1, 0), 0, 0), new Vertex(1, 1, 0, 0, 0),
new Vertex(new Vector3f(1, 0, 0), 0, 1) new Vertex(1, 0, 0, 0, 1)
}; };
public static final Vertex[] FRAME_BUFFER_VERTICES = new Vertex[] { public static final Vertex[] FRAME_BUFFER_VERTICES = new Vertex[] {
new Vertex(new Vector3f(0, 1, 0), 0, 0), new Vertex(0, 1, 0, 0, 0),
new Vertex(new Vector3f(1, 1, 0), 1, 0), new Vertex(1, 1, 0, 1, 0),
new Vertex(new Vector3f(1, 0, 0), 1, 1), new Vertex(1, 0, 0, 1, 1),
new Vertex(new Vector3f(0, 0, 0), 0, 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) { 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) { 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); buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT);
Matrix4f positionmatrix = matrices.peek().getPositionMatrix();
for (Vertex vertex : UNIT_FACE) { for (Vertex vertex : UNIT_FACE) {
Vector4f position = vertex.position(matrices); Vector4f position = vertex.position(positionmatrix);
buffer.vertex(position.x, position.y, position.z).texture(vertex.u() * uScale, vertex.v() * vScale).color(r, g, b, a).light(light).next(); 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(); te.draw();
} }
public record Vertex(Vector3f position, float u, float v) { public record Vertex(Vector3f position, Vector3f texture) {
public Vector4f position(MatrixStack matrices) { public Vertex(float x, float y, float z, float u, float v) {
matrices.peek().getPositionMatrix().transform(TEMP_VECTOR.set(position, 1)); this(new Vector3f(x, y, z), new Vector3f(u, v, 1));
return TEMP_VECTOR; }
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));
} }
} }
} }

View file

@ -12,10 +12,10 @@ public record BezierSegment(
public BezierSegment(Vector3f from, Vector3f to, float height) { public BezierSegment(Vector3f from, Vector3f to, float height) {
this(new RenderUtil.Vertex[] { this(new RenderUtil.Vertex[] {
new RenderUtil.Vertex(new Vector3f(from.x, from.y - height/2F, from.z), 0, 0), // bottom left new RenderUtil.Vertex(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(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(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(to.x, to.y - height/2F, to.z, 0, 1) // bottom right
}); });
} }

View file

@ -1,25 +1,35 @@
package com.minelittlepony.unicopia.client.render.model; package com.minelittlepony.unicopia.client.render.model;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.joml.Vector3f; import org.joml.Matrix4f;
import org.joml.Vector4f; import org.joml.Vector4f;
import com.minelittlepony.unicopia.client.render.RenderUtil; import com.minelittlepony.unicopia.client.render.RenderUtil;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
public class BakedModel { public class BakedModel {
protected final List<RenderUtil.Vertex> vertices = new ArrayList<>(); protected final List<RenderUtil.Vertex> 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) { protected void addVertex(Vector4f vertex) {
addVertex(vertex.x, vertex.y, vertex.z, (vertex.x + 1) * 0.5F, (vertex.z + 1) * 0.5F); 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) { 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) { 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.push();
matrices.scale(scale, scale, scale); matrices.scale(scale, scale, scale);
Matrix4f positionmatrix = matrices.peek().getPositionMatrix();
for (RenderUtil.Vertex vertex : vertices) { for (RenderUtil.Vertex vertex : vertices) {
Vector4f pos = vertex.position(matrices); Vector4f pos = vertex.position(positionmatrix);
buffer.vertex(pos.x, pos.y, pos.z, r, g, b, a, vertex.u(), vertex.v(), overlay, light, 0, 0, 0); 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(); 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); scale = Math.abs(scale);
if (scale < 0.001F) { if (scale < 0.001F) {
return; return;
@ -45,10 +58,13 @@ public class BakedModel {
matrices.push(); matrices.push();
matrices.scale(scale, scale, scale); matrices.scale(scale, scale, scale);
Matrix4f positionmatrix = matrices.peek().getPositionMatrix();
for (RenderUtil.Vertex vertex : vertices) { for (RenderUtil.Vertex vertex : vertices) {
Vector4f pos = vertex.position(matrices); Vector4f pos = vertex.position(positionmatrix);
buffer.vertex(pos.x, pos.y, pos.z).texture(vertex.u() * uScale, vertex.v() * vScale).color(r, g, b, a).next(); 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(); matrices.pop();
textureMatrix.identity();
} }
} }

View file

@ -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<ShaderProgram> renderTypePortalSurfaceProgram = register("rendertype_portal_surface", VertexFormats.POSITION_COLOR);
public static ShaderProgram getRenderTypePortalSurfaceProgram() {
return renderTypePortalSurfaceProgram.get();
}
public static void bootstrap() { }
static Supplier<ShaderProgram> register(String name, VertexFormat format) {
AtomicReference<ShaderProgram> holder = new AtomicReference<>();
CoreShaderRegistrationCallback.EVENT.register(context -> context.register(Unicopia.id(name), format, holder::set));
return holder::get;
}
}

View file

@ -15,6 +15,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.PortalSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.PortalSpell;
import com.minelittlepony.unicopia.client.render.RenderLayers; import com.minelittlepony.unicopia.client.render.RenderLayers;
import com.minelittlepony.unicopia.client.render.model.SphereModel; 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.EntityReference;
import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.mixin.client.MixinMinecraftClient; 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.BufferBuilder;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Frustum; import net.minecraft.client.render.Frustum;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.VertexFormat; 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.client.world.ClientWorld;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.screen.PlayerScreenHandler; import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
class PortalFrameBuffer implements AutoCloseable { class PortalFrameBuffer implements AutoCloseable {
@ -92,10 +93,14 @@ class PortalFrameBuffer implements AutoCloseable {
BufferBuilder buffer = tessellator.getBuffer(); BufferBuilder buffer = tessellator.getBuffer();
float uScale = (float)framebuffer.viewportWidth / (float)framebuffer.textureWidth; float uScale = (float)framebuffer.viewportWidth / (float)framebuffer.textureWidth;
float vScale = (float)framebuffer.viewportHeight / (float)framebuffer.textureHeight; 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()); RenderSystem._setShaderTexture(0, framebuffer.getColorAttachment());
buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR); 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(); tessellator.draw();
client.getTextureManager().bindTexture(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE); client.getTextureManager().bindTexture(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE);
@ -110,11 +115,11 @@ class PortalFrameBuffer implements AutoCloseable {
public void build(PortalSpell spell, Caster<?> caster, EntityReference.EntityValues<Entity> target) { public void build(PortalSpell spell, Caster<?> caster, EntityReference.EntityValues<Entity> target) {
if (framebuffer != null && System.currentTimeMillis() % 100 != 0) { if (framebuffer != null && System.currentTimeMillis() % 1 != 0) {
return; return;
} }
if (pendingDraw && recursionCount > 0) { if (pendingDraw && recursionCount > 2) {
innerBuild(spell, caster, target); innerBuild(spell, caster, target);
return; return;
} }
@ -134,7 +139,7 @@ class PortalFrameBuffer implements AutoCloseable {
synchronized (client) { synchronized (client) {
pendingDraw = false; pendingDraw = false;
if (recursionCount > 2) { if (recursionCount > 0) {
return; return;
} }
recursionCount++; recursionCount++;
@ -149,10 +154,17 @@ class PortalFrameBuffer implements AutoCloseable {
int originalFov = fov.getValue(); int originalFov = fov.getValue();
fov.setValue(110); fov.setValue(110);
Camera camera = client.gameRenderer.getCamera();
Entity cameraEntity = UEntities.CAST_SPELL.create(caster.asWorld()); Entity cameraEntity = UEntities.CAST_SPELL.create(caster.asWorld());
cameraEntity.setPosition(target.pos()); Vec3d offset = new Vec3d(0, -0.2F, -0.2F).rotateY(-spell.getTargetYaw() * MathHelper.RADIANS_PER_DEGREE);
cameraEntity.setPitch(spell.getTargetPitch());
cameraEntity.setYaw(spell.getTargetYaw() + 180); 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); 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); renderer.scheduleBlockRenders((int)cameraEntity.getX() / 16, (int)cameraEntity.getY() / 16, (int)cameraEntity.getZ() / 16);
client.gameRenderer.setRenderHand(false); client.gameRenderer.setRenderHand(false);
MatrixStack matrices = new MatrixStack();
matrices.scale((float)width / height, 1, 1); client.gameRenderer.renderWorld(1, 0, new MatrixStack());
client.gameRenderer.renderWorld(1, 0, matrices);
// Strip transparency // Strip transparency
RenderSystem.colorMask(false, false, false, true); RenderSystem.colorMask(false, false, false, true);

View file

@ -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.RenderLayers;
import com.minelittlepony.unicopia.client.render.model.SphereModel; import com.minelittlepony.unicopia.client.render.model.SphereModel;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Frustum; import net.minecraft.client.render.Frustum;
@ -49,6 +48,9 @@ public class PortalSpellRenderer extends SpellRenderer<PortalSpell> {
if (caster.asEntity().distanceTo(client.cameraEntity) > 50) { if (caster.asEntity().distanceTo(client.cameraEntity) > 50) {
return; // don't bother rendering if too far away return; // don't bother rendering if too far away
} }
if (client.cameraEntity == caster.asEntity()) {
return;
}
matrices.push(); matrices.push();
matrices.scale(strength, strength, strength); matrices.scale(strength, strength, strength);

View file

@ -0,0 +1,20 @@
#version 150
#moj_import <matrix.glsl>
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);
}

View file

@ -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 ] }
]
}

View file

@ -0,0 +1,19 @@
#version 150
#moj_import <projection.glsl>
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);
}