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.feature.FeatureRenderer;
|
||||
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.state.PlayerEntityRenderState;
|
||||
import net.minecraft.client.util.SkinTextures;
|
||||
@@ -28,14 +24,11 @@ import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
||||
private final BipedEntityModel<PlayerEntityRenderState> model;
|
||||
private final EquipmentModelLoader equipmentModelLoader;
|
||||
|
||||
public CloakFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context,
|
||||
LoadedEntityModels modelLoader, EquipmentModelLoader equipmentModelLoader) {
|
||||
EquipmentModelLoader equipmentModelLoader) {
|
||||
super(context);
|
||||
this.model = new PlayerCapeModel<PlayerEntityRenderState>(
|
||||
modelLoader.getModelPart(EntityModelLayers.PLAYER_CAPE));
|
||||
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,
|
||||
PlayerEntityRenderState playerEntityRenderState, float f, float g) {
|
||||
if (!playerEntityRenderState.invisible && playerEntityRenderState.capeVisible) {
|
||||
@@ -67,12 +213,15 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
||||
if (customCape != null
|
||||
&& !this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.WINGS)) {
|
||||
matrixStack.push();
|
||||
|
||||
// Position cape at player's shoulders
|
||||
matrixStack.translate(0.0f, -0.25f, 0.0f);
|
||||
|
||||
if (this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.HUMANOID)) {
|
||||
matrixStack.translate(0.0F, -0.053125F, 0.06875F);
|
||||
}
|
||||
|
||||
int minBrightness = 7;
|
||||
|
||||
int blockLight = (light >> 4) & 0xF;
|
||||
int skyLight = (light >> 20) & 0xF;
|
||||
|
||||
@@ -85,12 +234,13 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
||||
|
||||
VertexConsumer vertexConsumer = vertexConsumerProvider
|
||||
.getBuffer(RenderLayer.getEntitySolid(customCape));
|
||||
((PlayerEntityModel) this.getContextModel()).copyTransforms(this.model);
|
||||
this.model.setAngles(playerEntityRenderState);
|
||||
this.model.render(matrixStack, vertexConsumer, light, OverlayTexture.DEFAULT_UV);
|
||||
|
||||
// Render the cape manually
|
||||
renderCape(matrixStack, vertexConsumer, playerEntityRenderState, light, OverlayTexture.DEFAULT_UV);
|
||||
|
||||
matrixStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,6 @@ public abstract class PlayerEntityRendererMixin
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void addCustomFeatureRenderer(EntityRendererFactory.Context ctx, boolean slim, CallbackInfo ci) {
|
||||
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