Refactoring cloak physics
This commit is contained in:
+161
-60
@@ -29,6 +29,7 @@ import net.minecraft.component.type.EquippableComponent;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.equipment.EquipmentAsset;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.RotationAxis;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
@@ -43,6 +44,8 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
||||
private final EquipmentModelLoader equipmentModelLoader;
|
||||
private static final int PARTS = 24;
|
||||
private final float[] segmentValues = new float[PARTS];
|
||||
private static final int H_PARTS = 6;
|
||||
private float horizontalCurve = 0.0f;
|
||||
|
||||
private static final float TEX_W = 176f;
|
||||
private static final float TEX_H = 138f;
|
||||
@@ -150,118 +153,214 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
||||
|
||||
private void renderCape(MatrixStack.Entry entry, VertexConsumer vertexConsumer,
|
||||
PlayerEntityRenderState playerState, int light, int overlay) {
|
||||
|
||||
float capeWidth = 10.0f / 16.0f;
|
||||
float capeHeight = 16.0f / 16.0f;
|
||||
float capeDepth = 1.0f / 16.0f;
|
||||
float capePartHeight = capeHeight / PARTS;
|
||||
|
||||
float x1 = -capeWidth / 2.0f;
|
||||
float x2 = capeWidth / 2.0f;
|
||||
|
||||
final float frontU1 = FRONT_RECT.u1();
|
||||
final float frontU2 = FRONT_RECT.u2();
|
||||
final float frontV1 = FRONT_RECT.v1();
|
||||
final float frontV2 = FRONT_RECT.v2();
|
||||
final float frontPartV = (frontV2 - frontV1) / PARTS;
|
||||
|
||||
final float backU1 = BACK_RECT.u1();
|
||||
final float backU2 = BACK_RECT.u2();
|
||||
final float backV1 = BACK_RECT.v1();
|
||||
final float backV2 = BACK_RECT.v2();
|
||||
final float backPartV = (backV2 - backV1) / PARTS;
|
||||
|
||||
final float leftU1 = LEFT_EDGE_RECT.u1();
|
||||
final float leftU2 = LEFT_EDGE_RECT.u2();
|
||||
final float leftV1 = LEFT_EDGE_RECT.v1();
|
||||
final float leftV2 = LEFT_EDGE_RECT.v2();
|
||||
final float leftPartV = (leftV2 - leftV1) / PARTS;
|
||||
|
||||
final float rightU1 = RIGHT_EDGE_RECT.u1();
|
||||
final float rightU2 = RIGHT_EDGE_RECT.u2();
|
||||
final float rightV1 = RIGHT_EDGE_RECT.v1();
|
||||
final float rightV2 = RIGHT_EDGE_RECT.v2();
|
||||
final float rightPartV = (rightV2 - rightV1) / PARTS;
|
||||
|
||||
final float topU1 = TOP_RECT.u1();
|
||||
final float topU2 = TOP_RECT.u2();
|
||||
final float topV1 = TOP_RECT.v1();
|
||||
final float topV2 = TOP_RECT.v2();
|
||||
|
||||
final float bottomU1 = BOTTOM_RECT.u1();
|
||||
final float bottomU2 = BOTTOM_RECT.u2();
|
||||
final float bottomV1 = BOTTOM_RECT.v1();
|
||||
final float bottomV2 = BOTTOM_RECT.v2();
|
||||
|
||||
float curY = 0.0f;
|
||||
float curZ = 0.0f;
|
||||
// =============================
|
||||
// 1. Spine
|
||||
// =============================
|
||||
|
||||
float[] spineY = new float[PARTS + 1];
|
||||
float[] spineZ = new float[PARTS + 1];
|
||||
|
||||
float partHeight = capeHeight / PARTS;
|
||||
|
||||
for (int i = 0; i < PARTS; i++) {
|
||||
float angle = (2.0f - segmentValues[i]) * ((float) Math.PI / 2f);
|
||||
float dirY = -(float) Math.cos(angle);
|
||||
float dirZ = (float) Math.sin(angle);
|
||||
|
||||
// 1. Thickness at the START of this segment (Must match PREVIOUS segment's end)
|
||||
float prevAngle = (i > 0) ? (2.0f - segmentValues[i - 1]) * ((float) Math.PI / 2f) : angle;
|
||||
float startAvgAngle = (angle + prevAngle) / 2.0f;
|
||||
float thickYStart = (float) Math.sin(startAvgAngle) * capeDepth;
|
||||
float thickZStart = (float) Math.cos(startAvgAngle) * capeDepth;
|
||||
spineY[i + 1] = spineY[i] + dirY * partHeight;
|
||||
spineZ[i + 1] = spineZ[i] + dirZ * partHeight;
|
||||
}
|
||||
|
||||
// 2. Thickness at the END of this segment (Must match NEXT segment's start)
|
||||
float nextAngle = (i < PARTS - 1) ? (2.0f - segmentValues[i + 1]) * ((float) Math.PI / 2f) : angle;
|
||||
float endAvgAngle = (angle + nextAngle) / 2.0f;
|
||||
float thickYEnd = (float) Math.sin(endAvgAngle) * capeDepth;
|
||||
float thickZEnd = (float) Math.cos(endAvgAngle) * capeDepth;
|
||||
// =============================
|
||||
// 2. Grid
|
||||
// =============================
|
||||
|
||||
float nextY = curY + dirY * capePartHeight;
|
||||
float nextZ = curZ + dirZ * capePartHeight;
|
||||
Vec3d[][] inner = new Vec3d[H_PARTS + 1][PARTS + 1];
|
||||
Vec3d[][] outer = new Vec3d[H_PARTS + 1][PARTS + 1];
|
||||
|
||||
// Inner Vertices (The spine of the cape)
|
||||
Vec3d innerTopLeft = new Vec3d(x2, curY, curZ);
|
||||
Vec3d innerTopRight = new Vec3d(x1, curY, curZ);
|
||||
Vec3d innerBotLeft = new Vec3d(x2, nextY, nextZ);
|
||||
Vec3d innerBotRight = new Vec3d(x1, nextY, nextZ);
|
||||
for (int x = 0; x <= H_PARTS; x++) {
|
||||
|
||||
// Outer Vertices (Offset by the specific joint thickness)
|
||||
Vec3d outerTopLeft = new Vec3d(x2, curY - thickYStart, curZ - thickZStart);
|
||||
Vec3d outerTopRight = new Vec3d(x1, curY - thickYStart, curZ - thickZStart);
|
||||
Vec3d outerBotLeft = new Vec3d(x2, nextY - thickYEnd, nextZ - thickZEnd);
|
||||
Vec3d outerBotRight = new Vec3d(x1, nextY - thickYEnd, nextZ - thickZEnd);
|
||||
float t = (float) x / H_PARTS;
|
||||
float xPos = -capeWidth / 2.0f + capeWidth * t;
|
||||
|
||||
// FRONT (facing camera)
|
||||
this.renderCapeQuad(vertexConsumer, entry,
|
||||
outerBotRight, outerBotLeft, outerTopLeft, outerTopRight,
|
||||
frontU2, frontV1 + (frontPartV * i), frontU1, frontV1 + (frontPartV * (i + 1)),
|
||||
light, overlay, 0, 0, 1, false);
|
||||
float centered = t - 0.5f;
|
||||
float curveFactor = centered * 2.0f;
|
||||
float falloff = Math.abs(curveFactor);
|
||||
float zCurve = curveFactor * falloff * horizontalCurve * 0.3f;
|
||||
|
||||
// BACK (Facing player)
|
||||
this.renderCapeQuad(vertexConsumer, entry,
|
||||
innerBotLeft, innerBotRight, innerTopRight, innerTopLeft,
|
||||
backU2, backV1 + (backPartV * i), backU1, backV1 + (backPartV * (i + 1)),
|
||||
light, overlay, 0, 0, -1, false);
|
||||
for (int i = 0; i <= PARTS; i++) {
|
||||
|
||||
// LEFT EDGE
|
||||
this.renderCapeQuad(vertexConsumer, entry,
|
||||
innerBotLeft, outerBotLeft, outerTopLeft, innerTopLeft,
|
||||
leftU1, leftV1 + (leftPartV * i), leftU2, leftV1 + (leftPartV * (i + 1)),
|
||||
float y = spineY[i];
|
||||
float z = spineZ[i];
|
||||
|
||||
int idx = Math.min(i, PARTS - 1);
|
||||
float angle = (2.0f - segmentValues[idx]) * ((float) Math.PI / 2f);
|
||||
|
||||
float thickY = (float) Math.sin(angle) * capeDepth;
|
||||
float thickZ = (float) Math.cos(angle) * capeDepth;
|
||||
|
||||
inner[x][i] = new Vec3d(xPos, y, z + zCurve);
|
||||
outer[x][i] = new Vec3d(xPos, y - thickY, z - thickZ + zCurve);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================
|
||||
// 3. Front + Back
|
||||
// =============================
|
||||
|
||||
for (int x = 0; x < H_PARTS; x++) {
|
||||
|
||||
float uStart = frontU1 + (frontU2 - frontU1) * ((float) x / H_PARTS);
|
||||
float uEnd = frontU1 + (frontU2 - frontU1) * ((float) (x + 1) / H_PARTS);
|
||||
|
||||
float buStart = backU1 + (backU2 - backU1) * ((float) x / H_PARTS);
|
||||
float buEnd = backU1 + (backU2 - backU1) * ((float) (x + 1) / H_PARTS);
|
||||
|
||||
for (int i = 0; i < PARTS; i++) {
|
||||
|
||||
float vStart = frontV1 + frontPartV * i;
|
||||
float vEnd = frontV1 + frontPartV * (i + 1);
|
||||
|
||||
float bvStart = backV1 + backPartV * i;
|
||||
float bvEnd = backV1 + backPartV * (i + 1);
|
||||
|
||||
Vec3d innerTL = inner[x + 1][i];
|
||||
Vec3d innerTR = inner[x][i];
|
||||
Vec3d innerBL = inner[x + 1][i + 1];
|
||||
Vec3d innerBR = inner[x][i + 1];
|
||||
|
||||
Vec3d outerTL = outer[x + 1][i];
|
||||
Vec3d outerTR = outer[x][i];
|
||||
Vec3d outerBL = outer[x + 1][i + 1];
|
||||
Vec3d outerBR = outer[x][i + 1];
|
||||
|
||||
// FRONT
|
||||
renderCapeQuad(vertexConsumer, entry,
|
||||
outerBR, outerBL, outerTL, outerTR,
|
||||
uEnd, vStart, uStart, vEnd,
|
||||
light, overlay, 0, 0, 1, false);
|
||||
|
||||
// BACK
|
||||
renderCapeQuad(vertexConsumer, entry,
|
||||
innerBL, innerBR, innerTR, innerTL,
|
||||
buEnd, bvStart, buStart, bvEnd,
|
||||
light, overlay, 0, 0, -1, false);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================
|
||||
// 4. LEFT SIDE (x = 0)
|
||||
// =============================
|
||||
|
||||
for (int i = 0; i < PARTS; i++) {
|
||||
|
||||
Vec3d innerTop = inner[0][i];
|
||||
Vec3d innerBot = inner[0][i + 1];
|
||||
Vec3d outerTop = outer[0][i];
|
||||
Vec3d outerBot = outer[0][i + 1];
|
||||
|
||||
renderCapeQuad(vertexConsumer, entry,
|
||||
innerBot, outerBot, outerTop, innerTop,
|
||||
leftU1, leftV1 + leftPartV * i,
|
||||
leftU2, leftV1 + leftPartV * (i + 1),
|
||||
light, overlay, 1, 0, 0, false);
|
||||
}
|
||||
|
||||
// RIGHT EDGE
|
||||
this.renderCapeQuad(vertexConsumer, entry,
|
||||
outerBotRight, innerBotRight, innerTopRight, outerTopRight,
|
||||
rightU1, rightV1 + (rightPartV * i), rightU2, rightV1 + (rightPartV * (i + 1)),
|
||||
// =============================
|
||||
// 5. RIGHT SIDE (x = H_PARTS)
|
||||
// =============================
|
||||
|
||||
for (int i = 0; i < PARTS; i++) {
|
||||
|
||||
Vec3d innerTop = inner[H_PARTS][i];
|
||||
Vec3d innerBot = inner[H_PARTS][i + 1];
|
||||
Vec3d outerTop = outer[H_PARTS][i];
|
||||
Vec3d outerBot = outer[H_PARTS][i + 1];
|
||||
|
||||
renderCapeQuad(vertexConsumer, entry,
|
||||
outerBot, innerBot, innerTop, outerTop,
|
||||
rightU1, rightV1 + rightPartV * i,
|
||||
rightU2, rightV1 + rightPartV * (i + 1),
|
||||
light, overlay, -1, 0, 0, false);
|
||||
}
|
||||
|
||||
// TOP FACE (Only on first segment)
|
||||
if (i == 0) {
|
||||
this.renderCapeQuad(vertexConsumer, entry,
|
||||
outerTopLeft, outerTopRight, innerTopRight, innerTopLeft,
|
||||
topU1, topV1, topU2, topV2, light, overlay, 0, 1, 0, false);
|
||||
}
|
||||
// =============================
|
||||
// 6. TOP (i = 0)
|
||||
// =============================
|
||||
|
||||
// BOTTOM FACE (Only on last segment)
|
||||
if (i == PARTS - 1) {
|
||||
this.renderCapeQuad(vertexConsumer, entry,
|
||||
innerBotLeft, innerBotRight, outerBotRight, outerBotLeft,
|
||||
bottomU1, bottomV1, bottomU2, bottomV2, light, overlay, 0, -1, 0, false);
|
||||
}
|
||||
for (int x = 0; x < H_PARTS; x++) {
|
||||
|
||||
curY = nextY;
|
||||
curZ = nextZ;
|
||||
Vec3d outerL = outer[x][0];
|
||||
Vec3d outerR = outer[x + 1][0];
|
||||
Vec3d innerR = inner[x + 1][0];
|
||||
Vec3d innerL = inner[x][0];
|
||||
|
||||
float uStart = topU1 + (topU2 - topU1) * ((float) x / H_PARTS);
|
||||
float uEnd = topU1 + (topU2 - topU1) * ((float) (x + 1) / H_PARTS);
|
||||
|
||||
renderCapeQuad(vertexConsumer, entry,
|
||||
outerL, outerR, innerR, innerL,
|
||||
uStart, topV1, uEnd, topV2,
|
||||
light, overlay, 0, 1, 0, false);
|
||||
}
|
||||
|
||||
// =============================
|
||||
// 7. BOTTOM (i = PARTS)
|
||||
// =============================
|
||||
|
||||
for (int x = 0; x < H_PARTS; x++) {
|
||||
|
||||
Vec3d innerL = inner[x][PARTS];
|
||||
Vec3d innerR = inner[x + 1][PARTS];
|
||||
Vec3d outerR = outer[x + 1][PARTS];
|
||||
Vec3d outerL = outer[x][PARTS];
|
||||
|
||||
float uStart = bottomU1 + (bottomU2 - bottomU1) * ((float) x / H_PARTS);
|
||||
float uEnd = bottomU1 + (bottomU2 - bottomU1) * ((float) (x + 1) / H_PARTS);
|
||||
|
||||
renderCapeQuad(vertexConsumer, entry,
|
||||
innerL, innerR, outerR, outerL,
|
||||
uStart, bottomV1, uEnd, bottomV2,
|
||||
light, overlay, 0, -1, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,6 +435,8 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
||||
|
||||
final int l = light;
|
||||
|
||||
horizontalCurve = MathHelper.clamp(state.field_53537 / 150.0f, -1.0f, 1.0f);
|
||||
|
||||
queue.submitCustom(matrices, ShaderUtils.getRenderLayer(customCape), (entry, vertexConsumer) -> {
|
||||
renderCape(entry, vertexConsumer, state, l, OverlayTexture.DEFAULT_UV);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user