ModelPart.java

net.minecraft.client.model.geom.ModelPart

信息

  • 全限定名:net.minecraft.client.model.geom.ModelPart
  • 类型:public final class
  • 包:net.minecraft.client.model.geom
  • 源码路径:src/main/java/net/minecraft/client/model/geom/ModelPart.java
  • 起始行号:L28
  • 职责:

    TODO

字段/常量

  • DEFAULT_SCALE

    • 类型: float
    • 修饰符: public static final
    • 源码定位: L29
    • 说明:

      TODO

  • x

    • 类型: float
    • 修饰符: public
    • 源码定位: L30
    • 说明:

      TODO

  • y

    • 类型: float
    • 修饰符: public
    • 源码定位: L31
    • 说明:

      TODO

  • z

    • 类型: float
    • 修饰符: public
    • 源码定位: L32
    • 说明:

      TODO

  • xRot

    • 类型: float
    • 修饰符: public
    • 源码定位: L33
    • 说明:

      TODO

  • yRot

    • 类型: float
    • 修饰符: public
    • 源码定位: L34
    • 说明:

      TODO

  • zRot

    • 类型: float
    • 修饰符: public
    • 源码定位: L35
    • 说明:

      TODO

  • xScale

    • 类型: float
    • 修饰符: public
    • 源码定位: L36
    • 说明:

      TODO

  • yScale

    • 类型: float
    • 修饰符: public
    • 源码定位: L37
    • 说明:

      TODO

  • zScale

    • 类型: float
    • 修饰符: public
    • 源码定位: L38
    • 说明:

      TODO

  • visible

    • 类型: boolean
    • 修饰符: public
    • 源码定位: L39
    • 说明:

      TODO

  • skipDraw

    • 类型: boolean
    • 修饰符: public
    • 源码定位: L40
    • 说明:

      TODO

  • cubes

    • 类型: List<ModelPart.Cube>
    • 修饰符: private final
    • 源码定位: L41
    • 说明:

      TODO

  • children

    • 类型: Map<String,ModelPart>
    • 修饰符: private final
    • 源码定位: L42
    • 说明:

      TODO

  • initialPose

    • 类型: PartPose
    • 修饰符: private
    • 源码定位: L43
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.model.geom.ModelPart.Cube

    • 类型: class
    • 修饰符: public static
    • 源码定位: L234
    • 说明:

      TODO

  • net.minecraft.client.model.geom.ModelPart.Polygon

    • 类型: record
    • 修饰符: public
    • 源码定位: L349
    • 说明:

      TODO

  • net.minecraft.client.model.geom.ModelPart.Vertex

    • 类型: record
    • 修饰符: public
    • 源码定位: L375
    • 说明:

      TODO

  • net.minecraft.client.model.geom.ModelPart.Visitor

    • 类型: interface
    • 修饰符: public
    • 源码定位: L397
    • 说明:

      TODO

构造器

public ModelPart(List<ModelPart.Cube> cubes, Map<String,ModelPart> children) @ L45

  • 构造器名:ModelPart
  • 源码定位:L45
  • 修饰符:public

参数:

  • cubes: List<ModelPart.Cube>
  • children: Map<String,ModelPart>

说明:

TODO

方法

下面的方法块按源码顺序生成。

public PartPose storePose() @ L50

  • 方法名:storePose
  • 源码定位:L50
  • 返回类型:PartPose
  • 修饰符:public

参数:

说明:

TODO

public PartPose getInitialPose() @ L54

  • 方法名:getInitialPose
  • 源码定位:L54
  • 返回类型:PartPose
  • 修饰符:public

参数:

说明:

TODO

public void setInitialPose(PartPose initialPose) @ L58

  • 方法名:setInitialPose
  • 源码定位:L58
  • 返回类型:void
  • 修饰符:public

参数:

  • initialPose: PartPose

说明:

TODO

public void resetPose() @ L62

  • 方法名:resetPose
  • 源码定位:L62
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void loadPose(PartPose pose) @ L66

  • 方法名:loadPose
  • 源码定位:L66
  • 返回类型:void
  • 修饰符:public

参数:

  • pose: PartPose

说明:

TODO

public boolean hasChild(String name) @ L78

  • 方法名:hasChild
  • 源码定位:L78
  • 返回类型:boolean
  • 修饰符:public

参数:

  • name: String

说明:

TODO

public ModelPart getChild(String name) @ L82

  • 方法名:getChild
  • 源码定位:L82
  • 返回类型:ModelPart
  • 修饰符:public

参数:

  • name: String

说明:

TODO

public void setPos(float x, float y, float z) @ L91

  • 方法名:setPos
  • 源码定位:L91
  • 返回类型:void
  • 修饰符:public

参数:

  • x: float
  • y: float
  • z: float

说明:

TODO

public void setRotation(float xRot, float yRot, float zRot) @ L97

  • 方法名:setRotation
  • 源码定位:L97
  • 返回类型:void
  • 修饰符:public

参数:

  • xRot: float
  • yRot: float
  • zRot: float

说明:

TODO

public void render(PoseStack poseStack, VertexConsumer buffer, int lightCoords, int overlayCoords) @ L103

  • 方法名:render
  • 源码定位:L103
  • 返回类型:void
  • 修饰符:public

参数:

  • poseStack: PoseStack
  • buffer: VertexConsumer
  • lightCoords: int
  • overlayCoords: int

说明:

TODO

public void render(PoseStack poseStack, VertexConsumer buffer, int lightCoords, int overlayCoords, int color) @ L107

  • 方法名:render
  • 源码定位:L107
  • 返回类型:void
  • 修饰符:public

参数:

  • poseStack: PoseStack
  • buffer: VertexConsumer
  • lightCoords: int
  • overlayCoords: int
  • color: int

说明:

TODO

public void rotateBy(Quaternionf rotation) @ L125

  • 方法名:rotateBy
  • 源码定位:L125
  • 返回类型:void
  • 修饰符:public

参数:

  • rotation: Quaternionf

说明:

TODO

public void getExtentsForGui(PoseStack poseStack, Consumer<Vector3fc> output) @ L132

  • 方法名:getExtentsForGui
  • 源码定位:L132
  • 返回类型:void
  • 修饰符:public

参数:

  • poseStack: PoseStack
  • output: Consumer

说明:

TODO

public void visit(PoseStack poseStack, ModelPart.Visitor visitor) @ L146

  • 方法名:visit
  • 源码定位:L146
  • 返回类型:void
  • 修饰符:public

参数:

  • poseStack: PoseStack
  • visitor: ModelPart.Visitor

说明:

TODO

private void visit(PoseStack poseStack, ModelPart.Visitor visitor, String path) @ L150

  • 方法名:visit
  • 源码定位:L150
  • 返回类型:void
  • 修饰符:private

参数:

  • poseStack: PoseStack
  • visitor: ModelPart.Visitor
  • path: String

说明:

TODO

public void translateAndRotate(PoseStack poseStack) @ L166

  • 方法名:translateAndRotate
  • 源码定位:L166
  • 返回类型:void
  • 修饰符:public

参数:

  • poseStack: PoseStack

说明:

TODO

private void compile(PoseStack.Pose pose, VertexConsumer builder, int lightCoords, int overlayCoords, int color) @ L177

  • 方法名:compile
  • 源码定位:L177
  • 返回类型:void
  • 修饰符:private

参数:

  • pose: PoseStack.Pose
  • builder: VertexConsumer
  • lightCoords: int
  • overlayCoords: int
  • color: int

说明:

TODO

public ModelPart.Cube getRandomCube(RandomSource random) @ L183

  • 方法名:getRandomCube
  • 源码定位:L183
  • 返回类型:ModelPart.Cube
  • 修饰符:public

参数:

  • random: RandomSource

说明:

TODO

public boolean isEmpty() @ L187

  • 方法名:isEmpty
  • 源码定位:L187
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public void offsetPos(Vector3f offset) @ L191

  • 方法名:offsetPos
  • 源码定位:L191
  • 返回类型:void
  • 修饰符:public

参数:

  • offset: Vector3f

说明:

TODO

public void offsetRotation(Vector3f offset) @ L197

  • 方法名:offsetRotation
  • 源码定位:L197
  • 返回类型:void
  • 修饰符:public

参数:

  • offset: Vector3f

说明:

TODO

public void offsetScale(Vector3f offset) @ L203

  • 方法名:offsetScale
  • 源码定位:L203
  • 返回类型:void
  • 修饰符:public

参数:

  • offset: Vector3f

说明:

TODO

public List<ModelPart> getAllParts() @ L209

  • 方法名:getAllParts
  • 源码定位:L209
  • 返回类型:List
  • 修饰符:public

参数:

说明:

TODO

public Function<String,ModelPart> createPartLookup() @ L216

  • 方法名:createPartLookup
  • 源码定位:L216
  • 返回类型:Function<String,ModelPart>
  • 修饰符:public

参数:

说明:

TODO

private void addAllChildren(BiConsumer<String,ModelPart> output) @ L223

  • 方法名:addAllChildren
  • 源码定位:L223
  • 返回类型:void
  • 修饰符:private

参数:

  • output: BiConsumer<String,ModelPart>

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public final class ModelPart {
    public static final float DEFAULT_SCALE = 1.0F;
    public float x;
    public float y;
    public float z;
    public float xRot;
    public float yRot;
    public float zRot;
    public float xScale = 1.0F;
    public float yScale = 1.0F;
    public float zScale = 1.0F;
    public boolean visible = true;
    public boolean skipDraw;
    private final List<ModelPart.Cube> cubes;
    private final Map<String, ModelPart> children;
    private PartPose initialPose = PartPose.ZERO;
 
    public ModelPart(List<ModelPart.Cube> cubes, Map<String, ModelPart> children) {
        this.cubes = cubes;
        this.children = children;
    }
 
    public PartPose storePose() {
        return PartPose.offsetAndRotation(this.x, this.y, this.z, this.xRot, this.yRot, this.zRot);
    }
 
    public PartPose getInitialPose() {
        return this.initialPose;
    }
 
    public void setInitialPose(PartPose initialPose) {
        this.initialPose = initialPose;
    }
 
    public void resetPose() {
        this.loadPose(this.initialPose);
    }
 
    public void loadPose(PartPose pose) {
        this.x = pose.x();
        this.y = pose.y();
        this.z = pose.z();
        this.xRot = pose.xRot();
        this.yRot = pose.yRot();
        this.zRot = pose.zRot();
        this.xScale = pose.xScale();
        this.yScale = pose.yScale();
        this.zScale = pose.zScale();
    }
 
    public boolean hasChild(String name) {
        return this.children.containsKey(name);
    }
 
    public ModelPart getChild(String name) {
        ModelPart result = this.children.get(name);
        if (result == null) {
            throw new NoSuchElementException("Can't find part " + name);
        } else {
            return result;
        }
    }
 
    public void setPos(float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
 
    public void setRotation(float xRot, float yRot, float zRot) {
        this.xRot = xRot;
        this.yRot = yRot;
        this.zRot = zRot;
    }
 
    public void render(PoseStack poseStack, VertexConsumer buffer, int lightCoords, int overlayCoords) {
        this.render(poseStack, buffer, lightCoords, overlayCoords, -1);
    }
 
    public void render(PoseStack poseStack, VertexConsumer buffer, int lightCoords, int overlayCoords, int color) {
        if (this.visible) {
            if (!this.cubes.isEmpty() || !this.children.isEmpty()) {
                poseStack.pushPose();
                this.translateAndRotate(poseStack);
                if (!this.skipDraw) {
                    this.compile(poseStack.last(), buffer, lightCoords, overlayCoords, color);
                }
 
                for (ModelPart child : this.children.values()) {
                    child.render(poseStack, buffer, lightCoords, overlayCoords, color);
                }
 
                poseStack.popPose();
            }
        }
    }
 
    public void rotateBy(Quaternionf rotation) {
        Matrix3f oldRotation = new Matrix3f().rotationZYX(this.zRot, this.yRot, this.xRot);
        Matrix3f newRotation = oldRotation.rotate(rotation);
        Vector3f newAngles = newRotation.getEulerAnglesZYX(new Vector3f());
        this.setRotation(newAngles.x, newAngles.y, newAngles.z);
    }
 
    public void getExtentsForGui(PoseStack poseStack, Consumer<Vector3fc> output) {
        this.visit(poseStack, (pose, partPath, cubeIndex, cube) -> {
            for (ModelPart.Polygon polygon : cube.polygons) {
                for (ModelPart.Vertex vertex : polygon.vertices()) {
                    float x = vertex.worldX();
                    float y = vertex.worldY();
                    float z = vertex.worldZ();
                    Vector3f pos = pose.pose().transformPosition(x, y, z, new Vector3f());
                    output.accept(pos);
                }
            }
        });
    }
 
    public void visit(PoseStack poseStack, ModelPart.Visitor visitor) {
        this.visit(poseStack, visitor, "");
    }
 
    private void visit(PoseStack poseStack, ModelPart.Visitor visitor, String path) {
        if (!this.cubes.isEmpty() || !this.children.isEmpty()) {
            poseStack.pushPose();
            this.translateAndRotate(poseStack);
            PoseStack.Pose pose = poseStack.last();
 
            for (int i = 0; i < this.cubes.size(); i++) {
                visitor.visit(pose, path, i, this.cubes.get(i));
            }
 
            String childPath = path + "/";
            this.children.forEach((name, child) -> child.visit(poseStack, visitor, childPath + name));
            poseStack.popPose();
        }
    }
 
    public void translateAndRotate(PoseStack poseStack) {
        poseStack.translate(this.x / 16.0F, this.y / 16.0F, this.z / 16.0F);
        if (this.xRot != 0.0F || this.yRot != 0.0F || this.zRot != 0.0F) {
            poseStack.mulPose(new Quaternionf().rotationZYX(this.zRot, this.yRot, this.xRot));
        }
 
        if (this.xScale != 1.0F || this.yScale != 1.0F || this.zScale != 1.0F) {
            poseStack.scale(this.xScale, this.yScale, this.zScale);
        }
    }
 
    private void compile(PoseStack.Pose pose, VertexConsumer builder, int lightCoords, int overlayCoords, int color) {
        for (ModelPart.Cube cube : this.cubes) {
            cube.compile(pose, builder, lightCoords, overlayCoords, color);
        }
    }
 
    public ModelPart.Cube getRandomCube(RandomSource random) {
        return Util.getRandom(this.cubes, random);
    }
 
    public boolean isEmpty() {
        return this.cubes.isEmpty();
    }
 
    public void offsetPos(Vector3f offset) {
        this.x = this.x + offset.x();
        this.y = this.y + offset.y();
        this.z = this.z + offset.z();
    }
 
    public void offsetRotation(Vector3f offset) {
        this.xRot = this.xRot + offset.x();
        this.yRot = this.yRot + offset.y();
        this.zRot = this.zRot + offset.z();
    }
 
    public void offsetScale(Vector3f offset) {
        this.xScale = this.xScale + offset.x();
        this.yScale = this.yScale + offset.y();
        this.zScale = this.zScale + offset.z();
    }
 
    public List<ModelPart> getAllParts() {
        List<ModelPart> allParts = new ArrayList<>();
        allParts.add(this);
        this.addAllChildren((name, part) -> allParts.add(part));
        return List.copyOf(allParts);
    }
 
    public Function<String, @Nullable ModelPart> createPartLookup() {
        Map<String, ModelPart> parts = new HashMap<>();
        parts.put("root", this);
        this.addAllChildren(parts::putIfAbsent);
        return parts::get;
    }
 
    private void addAllChildren(BiConsumer<String, ModelPart> output) {
        for (Entry<String, ModelPart> entry : this.children.entrySet()) {
            output.accept(entry.getKey(), entry.getValue());
        }
 
        for (ModelPart part : this.children.values()) {
            part.addAllChildren(output);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public static class Cube {
        public final ModelPart.Polygon[] polygons;
        public final float minX;
        public final float minY;
        public final float minZ;
        public final float maxX;
        public final float maxY;
        public final float maxZ;
 
        public Cube(
            int xTexOffs,
            int yTexOffs,
            float minX,
            float minY,
            float minZ,
            float width,
            float height,
            float depth,
            float growX,
            float growY,
            float growZ,
            boolean mirror,
            float xTexSize,
            float yTexSize,
            Set<Direction> visibleFaces
        ) {
            this.minX = minX;
            this.minY = minY;
            this.minZ = minZ;
            this.maxX = minX + width;
            this.maxY = minY + height;
            this.maxZ = minZ + depth;
            this.polygons = new ModelPart.Polygon[visibleFaces.size()];
            float maxX = minX + width;
            float maxY = minY + height;
            float maxZ = minZ + depth;
            minX -= growX;
            minY -= growY;
            minZ -= growZ;
            maxX += growX;
            maxY += growY;
            maxZ += growZ;
            if (mirror) {
                float tmp = maxX;
                maxX = minX;
                minX = tmp;
            }
 
            ModelPart.Vertex t0 = new ModelPart.Vertex(minX, minY, minZ, 0.0F, 0.0F);
            ModelPart.Vertex t1 = new ModelPart.Vertex(maxX, minY, minZ, 0.0F, 8.0F);
            ModelPart.Vertex t2 = new ModelPart.Vertex(maxX, maxY, minZ, 8.0F, 8.0F);
            ModelPart.Vertex t3 = new ModelPart.Vertex(minX, maxY, minZ, 8.0F, 0.0F);
            ModelPart.Vertex l0 = new ModelPart.Vertex(minX, minY, maxZ, 0.0F, 0.0F);
            ModelPart.Vertex l1 = new ModelPart.Vertex(maxX, minY, maxZ, 0.0F, 8.0F);
            ModelPart.Vertex l2 = new ModelPart.Vertex(maxX, maxY, maxZ, 8.0F, 8.0F);
            ModelPart.Vertex l3 = new ModelPart.Vertex(minX, maxY, maxZ, 8.0F, 0.0F);
            float u0 = xTexOffs;
            float u1 = xTexOffs + depth;
            float u2 = xTexOffs + depth + width;
            float u22 = xTexOffs + depth + width + width;
            float u3 = xTexOffs + depth + width + depth;
            float u4 = xTexOffs + depth + width + depth + width;
            float v0 = yTexOffs;
            float v1 = yTexOffs + depth;
            float v2 = yTexOffs + depth + height;
            int pos = 0;
            if (visibleFaces.contains(Direction.DOWN)) {
                this.polygons[pos++] = new ModelPart.Polygon(new ModelPart.Vertex[]{l1, l0, t0, t1}, u1, v0, u2, v1, xTexSize, yTexSize, mirror, Direction.DOWN);
            }
 
            if (visibleFaces.contains(Direction.UP)) {
                this.polygons[pos++] = new ModelPart.Polygon(new ModelPart.Vertex[]{t2, t3, l3, l2}, u2, v1, u22, v0, xTexSize, yTexSize, mirror, Direction.UP);
            }
 
            if (visibleFaces.contains(Direction.WEST)) {
                this.polygons[pos++] = new ModelPart.Polygon(new ModelPart.Vertex[]{t0, l0, l3, t3}, u0, v1, u1, v2, xTexSize, yTexSize, mirror, Direction.WEST);
            }
 
            if (visibleFaces.contains(Direction.NORTH)) {
                this.polygons[pos++] = new ModelPart.Polygon(
                    new ModelPart.Vertex[]{t1, t0, t3, t2}, u1, v1, u2, v2, xTexSize, yTexSize, mirror, Direction.NORTH
                );
            }
 
            if (visibleFaces.contains(Direction.EAST)) {
                this.polygons[pos++] = new ModelPart.Polygon(new ModelPart.Vertex[]{l1, t1, t2, l2}, u2, v1, u3, v2, xTexSize, yTexSize, mirror, Direction.EAST);
            }
 
            if (visibleFaces.contains(Direction.SOUTH)) {
                this.polygons[pos] = new ModelPart.Polygon(new ModelPart.Vertex[]{l0, l1, l2, l3}, u3, v1, u4, v2, xTexSize, yTexSize, mirror, Direction.SOUTH);
            }
        }
 
        public void compile(PoseStack.Pose pose, VertexConsumer builder, int lightCoords, int overlayCoords, int color) {
            Matrix4f matrix = pose.pose();
            Vector3f scratchVector = new Vector3f();
 
            for (ModelPart.Polygon polygon : this.polygons) {
                Vector3f normal = pose.transformNormal(polygon.normal, scratchVector);
                float nx = normal.x();
                float ny = normal.y();
                float nz = normal.z();
 
                for (ModelPart.Vertex vertex : polygon.vertices) {
                    float x = vertex.worldX();
                    float y = vertex.worldY();
                    float z = vertex.worldZ();
                    Vector3f pos = matrix.transformPosition(x, y, z, scratchVector);
                    builder.addVertex(pos.x(), pos.y(), pos.z(), color, vertex.u, vertex.v, overlayCoords, lightCoords, nx, ny, nz);
                }
            }
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record Polygon(ModelPart.Vertex[] vertices, Vector3fc normal) {
        public Polygon(ModelPart.Vertex[] vertices, float u0, float v0, float u1, float v1, float xTexSize, float yTexSize, boolean mirror, Direction facing) {
            this(vertices, (mirror ? mirrorFacing(facing) : facing).getUnitVec3f());
            float us = 0.0F / xTexSize;
            float vs = 0.0F / yTexSize;
            vertices[0] = vertices[0].remap(u1 / xTexSize - us, v0 / yTexSize + vs);
            vertices[1] = vertices[1].remap(u0 / xTexSize + us, v0 / yTexSize + vs);
            vertices[2] = vertices[2].remap(u0 / xTexSize + us, v1 / yTexSize - vs);
            vertices[3] = vertices[3].remap(u1 / xTexSize - us, v1 / yTexSize - vs);
            if (mirror) {
                int length = vertices.length;
 
                for (int i = 0; i < length / 2; i++) {
                    ModelPart.Vertex tmp = vertices[i];
                    vertices[i] = vertices[length - 1 - i];
                    vertices[length - 1 - i] = tmp;
                }
            }
        }
 
        private static Direction mirrorFacing(Direction facing) {
            return facing.getAxis() == Direction.Axis.X ? facing.getOpposite() : facing;
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record Vertex(float x, float y, float z, float u, float v) {
        public static final float SCALE_FACTOR = 16.0F;
 
        public ModelPart.Vertex remap(float u, float v) {
            return new ModelPart.Vertex(this.x, this.y, this.z, u, v);
        }
 
        public float worldX() {
            return this.x / 16.0F;
        }
 
        public float worldY() {
            return this.y / 16.0F;
        }
 
        public float worldZ() {
            return this.z / 16.0F;
        }
    }
 
    @FunctionalInterface
    @OnlyIn(Dist.CLIENT)
    public interface Visitor {
        void visit(final PoseStack.Pose pose, final String partPath, final int cubeIndex, final ModelPart.Cube cube);
    }
}

引用的其他类

  • PoseStack

    • 引用位置: 参数
  • VertexConsumer

    • 引用位置: 参数
  • PartPose

    • 引用位置: 参数/字段/方法调用/返回值
    • 关联成员: PartPose.offsetAndRotation()
  • RandomSource

    • 引用位置: 参数
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.getRandom()