Working custom renderer for cloaks
This commit is contained in:
@@ -12,10 +12,6 @@ import net.minecraft.client.render.entity.equipment.EquipmentModelLoader;
|
|||||||
import net.minecraft.client.render.entity.equipment.EquipmentModel.LayerType;
|
import net.minecraft.client.render.entity.equipment.EquipmentModel.LayerType;
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||||
import net.minecraft.client.render.entity.model.BipedEntityModel;
|
|
||||||
import net.minecraft.client.render.entity.model.EntityModelLayers;
|
|
||||||
import net.minecraft.client.render.entity.model.LoadedEntityModels;
|
|
||||||
import net.minecraft.client.render.entity.model.PlayerCapeModel;
|
|
||||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||||
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
||||||
import net.minecraft.client.util.SkinTextures;
|
import net.minecraft.client.util.SkinTextures;
|
||||||
@@ -28,14 +24,11 @@ import net.minecraft.registry.RegistryKey;
|
|||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
||||||
private final BipedEntityModel<PlayerEntityRenderState> model;
|
|
||||||
private final EquipmentModelLoader equipmentModelLoader;
|
private final EquipmentModelLoader equipmentModelLoader;
|
||||||
|
|
||||||
public CloakFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context,
|
public CloakFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context,
|
||||||
LoadedEntityModels modelLoader, EquipmentModelLoader equipmentModelLoader) {
|
EquipmentModelLoader equipmentModelLoader) {
|
||||||
super(context);
|
super(context);
|
||||||
this.model = new PlayerCapeModel<PlayerEntityRenderState>(
|
|
||||||
modelLoader.getModelPart(EntityModelLayers.PLAYER_CAPE));
|
|
||||||
this.equipmentModelLoader = equipmentModelLoader;
|
this.equipmentModelLoader = equipmentModelLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +43,159 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render quad with correct winding order (counter-clockwise for front face)
|
||||||
|
private void renderCapeQuad(VertexConsumer vertexConsumer, MatrixStack matrixStack,
|
||||||
|
float x1, float y1, float z1, float x2, float y2, float z2,
|
||||||
|
float u1, float v1, float u2, float v2, int light, int overlay,
|
||||||
|
float normalX, float normalY, float normalZ, boolean flipWinding) {
|
||||||
|
MatrixStack.Entry entry = matrixStack.peek();
|
||||||
|
|
||||||
|
if (!flipWinding) {
|
||||||
|
// Counter-clockwise winding (front face)
|
||||||
|
// Vertex 1 (bottom-left)
|
||||||
|
vertexConsumer.vertex(entry.getPositionMatrix(), x1, y2, z1)
|
||||||
|
.color(255, 255, 255, 255)
|
||||||
|
.texture(u1, v2)
|
||||||
|
.overlay(overlay)
|
||||||
|
.light(light)
|
||||||
|
.normal(normalX, normalY, normalZ);
|
||||||
|
|
||||||
|
// Vertex 2 (bottom-right)
|
||||||
|
vertexConsumer.vertex(entry.getPositionMatrix(), x2, y2, z2)
|
||||||
|
.color(255, 255, 255, 255)
|
||||||
|
.texture(u2, v2)
|
||||||
|
.overlay(overlay)
|
||||||
|
.light(light)
|
||||||
|
.normal(normalX, normalY, normalZ);
|
||||||
|
|
||||||
|
// Vertex 3 (top-right)
|
||||||
|
vertexConsumer.vertex(entry.getPositionMatrix(), x2, y1, z2)
|
||||||
|
.color(255, 255, 255, 255)
|
||||||
|
.texture(u2, v1)
|
||||||
|
.overlay(overlay)
|
||||||
|
.light(light)
|
||||||
|
.normal(normalX, normalY, normalZ);
|
||||||
|
|
||||||
|
// Vertex 4 (top-left)
|
||||||
|
vertexConsumer.vertex(entry.getPositionMatrix(), x1, y1, z1)
|
||||||
|
.color(255, 255, 255, 255)
|
||||||
|
.texture(u1, v1)
|
||||||
|
.overlay(overlay)
|
||||||
|
.light(light)
|
||||||
|
.normal(normalX, normalY, normalZ);
|
||||||
|
} else {
|
||||||
|
// Clockwise winding (back face) - reverse vertex order
|
||||||
|
// Vertex 4 (top-left)
|
||||||
|
vertexConsumer.vertex(entry.getPositionMatrix(), x1, y1, z1)
|
||||||
|
.color(255, 255, 255, 255)
|
||||||
|
.texture(u1, v1)
|
||||||
|
.overlay(overlay)
|
||||||
|
.light(light)
|
||||||
|
.normal(normalX, normalY, normalZ);
|
||||||
|
|
||||||
|
// Vertex 3 (top-right)
|
||||||
|
vertexConsumer.vertex(entry.getPositionMatrix(), x2, y1, z2)
|
||||||
|
.color(255, 255, 255, 255)
|
||||||
|
.texture(u2, v1)
|
||||||
|
.overlay(overlay)
|
||||||
|
.light(light)
|
||||||
|
.normal(normalX, normalY, normalZ);
|
||||||
|
|
||||||
|
// Vertex 2 (bottom-right)
|
||||||
|
vertexConsumer.vertex(entry.getPositionMatrix(), x2, y2, z2)
|
||||||
|
.color(255, 255, 255, 255)
|
||||||
|
.texture(u2, v2)
|
||||||
|
.overlay(overlay)
|
||||||
|
.light(light)
|
||||||
|
.normal(normalX, normalY, normalZ);
|
||||||
|
|
||||||
|
// Vertex 1 (bottom-left)
|
||||||
|
vertexConsumer.vertex(entry.getPositionMatrix(), x1, y2, z1)
|
||||||
|
.color(255, 255, 255, 255)
|
||||||
|
.texture(u1, v2)
|
||||||
|
.overlay(overlay)
|
||||||
|
.light(light)
|
||||||
|
.normal(normalX, normalY, normalZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderCape(MatrixStack matrixStack, VertexConsumer vertexConsumer,
|
||||||
|
PlayerEntityRenderState playerState, int light, int overlay) {
|
||||||
|
// Cape dimensions (similar to vanilla cape model)
|
||||||
|
float capeWidth = 10.0f / 16.0f; // 10 pixels wide
|
||||||
|
float capeHeight = 16.0f / 16.0f; // 16 pixels tall
|
||||||
|
float capeDepth = 1.0f / 16.0f; // 1 pixel deep
|
||||||
|
|
||||||
|
// Position the cape behind the player
|
||||||
|
matrixStack.push();
|
||||||
|
|
||||||
|
// Apply player body rotation
|
||||||
|
matrixStack.translate(0.0f, 0.0f, 0.125f); // Move cape slightly behind player
|
||||||
|
|
||||||
|
// Render the main cape body
|
||||||
|
float x1 = -capeWidth / 2.0f;
|
||||||
|
float x2 = capeWidth / 2.0f;
|
||||||
|
float y1 = 0.0f;
|
||||||
|
float y2 = -capeHeight;
|
||||||
|
float z1 = 0.0f;
|
||||||
|
float z2 = capeDepth;
|
||||||
|
|
||||||
|
// UV coordinates for cape texture (assuming 64x32 texture)
|
||||||
|
// Front face UV (outside of cape)
|
||||||
|
float frontU1 = 1.0f / 64.0f; // Start at pixel 1
|
||||||
|
float frontU2 = 11.0f / 64.0f; // End at pixel 11 (10 pixels wide)
|
||||||
|
float frontV1 = 1.0f / 32.0f; // Start at pixel 1
|
||||||
|
float frontV2 = 17.0f / 32.0f; // End at pixel 17 (16 pixels tall)
|
||||||
|
|
||||||
|
// Back face UV (inside of cape) - typically offset in cape texture
|
||||||
|
float backU1 = 12.0f / 64.0f; // Back texture starts after front
|
||||||
|
float backU2 = 22.0f / 64.0f; // 10 pixels wide
|
||||||
|
float backV1 = 1.0f / 32.0f;
|
||||||
|
float backV2 = 17.0f / 32.0f;
|
||||||
|
|
||||||
|
// Bottom face UV (lower edge of cape)
|
||||||
|
float bottomU1 = 1.0f / 64.0f; // Start at pixel 1
|
||||||
|
float bottomU2 = 11.0f / 64.0f; // End at pixel 11
|
||||||
|
float bottomV1 = 0.0f / 32.0f; // Start at pixel 0
|
||||||
|
float bottomV2 = 1.0f / 32.0f; // End at pixel 1
|
||||||
|
|
||||||
|
// Top face UV (edge along shoulders)
|
||||||
|
float topU1 = 1.0f / 64.0f; // Start at pixel 1
|
||||||
|
float topU2 = 11.0f / 64.0f; // End at pixel 11
|
||||||
|
float topV1 = 17.0f / 32.0f; // Start at pixel 17
|
||||||
|
float topV2 = 18.0f / 32.0f; // End at pixel 18
|
||||||
|
|
||||||
|
// FRONT FACE
|
||||||
|
renderCapeQuad(vertexConsumer, matrixStack,
|
||||||
|
x2, y2, z2, x1, y1, z2,
|
||||||
|
frontU1, frontV1, frontU2, frontV2,
|
||||||
|
light, overlay,
|
||||||
|
0.0f, 0.0f, 1.0f, false);
|
||||||
|
|
||||||
|
// BACK FACE
|
||||||
|
renderCapeQuad(vertexConsumer, matrixStack,
|
||||||
|
x1, y2, z1, x2, y1, z1,
|
||||||
|
backU1, backV1, backU2, backV2,
|
||||||
|
light, overlay,
|
||||||
|
0.0f, 0.0f, 1.0f, false);
|
||||||
|
|
||||||
|
// LEFT SIDE
|
||||||
|
renderCapeQuad(vertexConsumer, matrixStack,
|
||||||
|
x2, y2, z1, x2, y1, z2,
|
||||||
|
0.0f, frontV1, 1.0f / 64.0f, frontV2,
|
||||||
|
light, overlay,
|
||||||
|
1.0f, 0.0f, 0.0f, false);
|
||||||
|
|
||||||
|
// RIGHT SIDE
|
||||||
|
renderCapeQuad(vertexConsumer, matrixStack,
|
||||||
|
x1, y2, z2, x1, y1, z1,
|
||||||
|
frontU2, frontV1, frontU2 + 1.0f / 64.0f, frontV2,
|
||||||
|
light, overlay,
|
||||||
|
-1.0f, 0.0f, 0.0f, false);
|
||||||
|
|
||||||
|
matrixStack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
public void render(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light,
|
public void render(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light,
|
||||||
PlayerEntityRenderState playerEntityRenderState, float f, float g) {
|
PlayerEntityRenderState playerEntityRenderState, float f, float g) {
|
||||||
if (!playerEntityRenderState.invisible && playerEntityRenderState.capeVisible) {
|
if (!playerEntityRenderState.invisible && playerEntityRenderState.capeVisible) {
|
||||||
@@ -67,12 +213,15 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
|||||||
if (customCape != null
|
if (customCape != null
|
||||||
&& !this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.WINGS)) {
|
&& !this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.WINGS)) {
|
||||||
matrixStack.push();
|
matrixStack.push();
|
||||||
|
|
||||||
|
// Position cape at player's shoulders
|
||||||
|
matrixStack.translate(0.0f, -0.25f, 0.0f);
|
||||||
|
|
||||||
if (this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.HUMANOID)) {
|
if (this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.HUMANOID)) {
|
||||||
matrixStack.translate(0.0F, -0.053125F, 0.06875F);
|
matrixStack.translate(0.0F, -0.053125F, 0.06875F);
|
||||||
}
|
}
|
||||||
|
|
||||||
int minBrightness = 7;
|
int minBrightness = 7;
|
||||||
|
|
||||||
int blockLight = (light >> 4) & 0xF;
|
int blockLight = (light >> 4) & 0xF;
|
||||||
int skyLight = (light >> 20) & 0xF;
|
int skyLight = (light >> 20) & 0xF;
|
||||||
|
|
||||||
@@ -85,12 +234,13 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
|||||||
|
|
||||||
VertexConsumer vertexConsumer = vertexConsumerProvider
|
VertexConsumer vertexConsumer = vertexConsumerProvider
|
||||||
.getBuffer(RenderLayer.getEntitySolid(customCape));
|
.getBuffer(RenderLayer.getEntitySolid(customCape));
|
||||||
((PlayerEntityModel) this.getContextModel()).copyTransforms(this.model);
|
|
||||||
this.model.setAngles(playerEntityRenderState);
|
// Render the cape manually
|
||||||
this.model.render(matrixStack, vertexConsumer, light, OverlayTexture.DEFAULT_UV);
|
renderCape(matrixStack, vertexConsumer, playerEntityRenderState, light, OverlayTexture.DEFAULT_UV);
|
||||||
|
|
||||||
matrixStack.pop();
|
matrixStack.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,6 @@ public abstract class PlayerEntityRendererMixin
|
|||||||
@Inject(method = "<init>", at = @At("TAIL"))
|
@Inject(method = "<init>", at = @At("TAIL"))
|
||||||
private void addCustomFeatureRenderer(EntityRendererFactory.Context ctx, boolean slim, CallbackInfo ci) {
|
private void addCustomFeatureRenderer(EntityRendererFactory.Context ctx, boolean slim, CallbackInfo ci) {
|
||||||
this.addFeature(new HatFeatureRenderer(this));
|
this.addFeature(new HatFeatureRenderer(this));
|
||||||
this.addFeature(new CloakFeatureRenderer(this, ctx.getEntityModels(), ctx.getEquipmentModelLoader()));
|
this.addFeature(new CloakFeatureRenderer(this, ctx.getEquipmentModelLoader()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 148 KiB |
Reference in New Issue
Block a user