- 62
- 1
- 9
Здравствуйте! Хотел сделать броню и все вроде шло достаточно не плохо , но после того как я отрисовал броню и зашел в игру я заметил что броня поломана , имеет какието артефакты и дырки(фото как это выглядит отправил) , можете подсказать как это пофиксить?


ObjArmorRenderer:
package com.example.examplemod.client.renderer.armor;
import com.example.examplemod.Items.ItemArmorObj;
import com.google.common.collect.ImmutableMap;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import org.joml.Vector3f;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class ObjArmorRenderer extends HumanoidModel<LivingEntity> {
private static final Map<String, ObjModel> MODEL_CACHE = new HashMap<>();
private static final Vector3f DEFAULT_TEXCOORD = new Vector3f(0, 0, 0);
private static final Vector3f DEFAULT_NORMAL = new Vector3f(0, 1, 0);
private final ModelPart root;
private ObjModel currentModel;
private ResourceLocation textureLocation;
private ItemArmorObj currentArmorItem;
private static final Map<Item, Map<String, ModelPart>> PART_MAP_CACHE = new HashMap<>();
public ObjArmorRenderer(ModelPart root) {
super(root);
this.root = root;
}
private Map<String, ModelPart> getPartMap(ItemArmorObj item) {
return PART_MAP_CACHE.computeIfAbsent(item, key ->
ImmutableMap.<String, ModelPart>builder()
.put(item.Head(), this.root.getChild("head"))
.put(item.Body(), this.root.getChild("body"))
.put(item.RightArm(), this.root.getChild("right_arm"))
.put(item.LeftArm(), this.root.getChild("left_arm"))
.put(item.RightLeg(), this.root.getChild("right_leg"))
.put(item.LeftLeg(), this.root.getChild("left_leg"))
.build()
);
}
@Override
public void setupAnim(LivingEntity entity, float limbSwing, float limbSwingAmount,
float ageInTicks, float netHeadYaw, float headPitch) {
if (currentArmorItem == null) return;
super.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch);
Map<String, ModelPart> partMap = getPartMap(currentArmorItem);
partMap.get(currentArmorItem.Head()).copyFrom(this.head);
partMap.get(currentArmorItem.Body()).copyFrom(this.body);
partMap.get(currentArmorItem.RightArm()).copyFrom(this.rightArm);
partMap.get(currentArmorItem.LeftArm()).copyFrom(this.leftArm);
partMap.get(currentArmorItem.RightLeg()).copyFrom(this.rightLeg);
partMap.get(currentArmorItem.LeftLeg()).copyFrom(this.leftLeg);
}
public void prepForRender(LivingEntity entity, ItemStack stack) {
if (!(stack.getItem() instanceof ItemArmorObj armor)) return;
this.currentArmorItem = armor;
this.setupAnim(
entity,
entity.walkAnimation.position(),
entity.walkAnimation.speed(),
entity.tickCount,
entity.yHeadRot,
entity.getXRot()
);
String modelPath = armor.getModelPath();
this.textureLocation = ResourceLocation.fromNamespaceAndPath(
armor.getCreatorModId(stack),
modelPath.replace("models/armor/", "textures/armor/").replace(".obj", ".png")
);
ResourceLocation modelLocation = ResourceLocation.fromNamespaceAndPath(
armor.getCreatorModId(stack),
modelPath
);
this.currentModel = MODEL_CACHE.computeIfAbsent(modelLocation.toString(), k -> {
try {
return loadModel(modelLocation);
} catch (IOException e) {
e.printStackTrace();
return null;
}
});
}
@Override
public void renderToBuffer(
PoseStack poseStack,
VertexConsumer vertexConsumer,
int packedLight,
int packedOverlay,
float red,
float green,
float blue,
float alpha
) {
if (currentModel == null || currentArmorItem == null || textureLocation == null) return;
VertexConsumer consumer =
Minecraft.getInstance()
.renderBuffers()
.bufferSource()
.getBuffer(RenderType.entityCutout(textureLocation));
Map<String, ModelPart> partMap = getPartMap(currentArmorItem);
for (Map.Entry<String, ModelPart> entry : partMap.entrySet()) {
List<ObjModel.Triangle> tris = currentModel.groups.get(entry.getKey());
if (tris == null || tris.isEmpty()) continue;
renderGroup(
entry.getValue(),
entry.getKey(),
tris,
poseStack,
consumer,
packedLight,
packedOverlay,
red, green, blue, alpha
);
}
}
private void renderGroup(
ModelPart part,
String group,
List<ObjModel.Triangle> tris,
PoseStack poseStack,
VertexConsumer consumer,
int light,
int overlay,
float r, float g, float b, float a
) {
poseStack.pushPose();
part.translateAndRotate(poseStack);
poseStack.scale(1.1F, 1.1F, 1.1F);
poseStack.mulPose(Axis.YP.rotationDegrees(180.0F));
poseStack.mulPose(Axis.XP.rotationDegrees(180.0F));
poseStack.translate(0.0F, -1.4F, 0.0F);
if (group.equals(currentArmorItem.RightArm())) poseStack.translate(-0.25F, 0, 0);
else if (group.equals(currentArmorItem.LeftArm())) poseStack.translate(0.25F, 0, 0);
else if (group.equals(currentArmorItem.RightLeg())) poseStack.translate(-0.1F, 0.75F, 0);
else if (group.equals(currentArmorItem.LeftLeg())) poseStack.translate(0.1F, 0.75F, 0);
PoseStack.Pose pose = poseStack.last();
for (ObjModel.Triangle t : tris) {
for (int i = 0; i < 3; i++) {
Vector3f v = t.vertices[i];
Vector3f uv = t.texCoords[i];
consumer.vertex(pose.pose(), v.x(), v.y(), v.z())
.color(r, g, b, a)
.uv(uv.x(), 1.0F - uv.y())
.overlayCoords(overlay)
.uv2(light)
.normal(pose.normal(), 0.0F, 1.0F, 0.0F)
.endVertex();
}
}
poseStack.popPose();
}
private ObjModel loadModel(ResourceLocation loc) throws IOException {
ObjModel model = new ObjModel();
Resource res = Minecraft.getInstance()
.getResourceManager()
.getResource(loc)
.orElseThrow();
try (BufferedReader br = new BufferedReader(new InputStreamReader(res.open()))) {
String group = "default";
String line;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.isEmpty() || line.startsWith("#")) continue;
String[] p = line.split("\\s+");
switch (p[0]) {
case "v" -> model.vertices.add(new Vector3f(
Float.parseFloat(p[1]),
Float.parseFloat(p[2]),
Float.parseFloat(p[3])
));
case "vt" -> model.texCoords.add(new Vector3f(
Float.parseFloat(p[1]),
Float.parseFloat(p[2]),
0
));
case "vn" -> model.normals.add(new Vector3f(
Float.parseFloat(p[1]),
Float.parseFloat(p[2]),
Float.parseFloat(p[3])
));
case "g", "o" -> group = p[1];
case "f" -> parseFace(model, group, p);
}
}
}
return model;
}
private void parseFace(ObjModel model, String group, String[] parts) {
List<ObjModel.Triangle> list =
model.groups.computeIfAbsent(group, k -> new ArrayList<>());
int[][] idx = new int[parts.length - 1][3];
for (int i = 1; i < parts.length; i++) {
String[] f = parts[i].split("/");
idx[i - 1][0] = Integer.parseInt(f[0]) - 1;
idx[i - 1][1] = f.length > 1 && !f[1].isEmpty() ? Integer.parseInt(f[1]) - 1 : -1;
}
for (int i = 1; i < idx.length - 1; i++) {
ObjModel.Triangle t = new ObjModel.Triangle();
t.vertices[0] = new Vector3f(model.vertices.get(idx[0][0]));
t.vertices[1] = new Vector3f(model.vertices.get(idx[i][0]));
t.vertices[2] = new Vector3f(model.vertices.get(idx[i + 1][0]));
t.texCoords[0] = idx[0][1] >= 0 ? new Vector3f(model.texCoords.get(idx[0][1])) : DEFAULT_TEXCOORD;
t.texCoords[1] = idx[i][1] >= 0 ? new Vector3f(model.texCoords.get(idx[i][1])) : DEFAULT_TEXCOORD;
t.texCoords[2] = idx[i + 1][1] >= 0 ? new Vector3f(model.texCoords.get(idx[i + 1][1])) : DEFAULT_TEXCOORD;
list.add(t);
}
}
private static class ObjModel {
List<Vector3f> vertices = new ArrayList<>();
List<Vector3f> texCoords = new ArrayList<>();
List<Vector3f> normals = new ArrayList<>();
Map<String, List<Triangle>> groups = new HashMap<>();
static class Triangle {
Vector3f[] vertices = new Vector3f[3];
Vector3f[] texCoords = new Vector3f[3];
}
}
}


