ItemModelGenerator.java

net.minecraft.client.resources.model.cuboid.ItemModelGenerator

信息

  • 全限定名:net.minecraft.client.resources.model.cuboid.ItemModelGenerator
  • 类型:public class
  • 包:net.minecraft.client.resources.model.cuboid
  • 源码路径:src/main/java/net/minecraft/client/resources/model/cuboid/ItemModelGenerator.java
  • 起始行号:L26
  • 实现:UnbakedModel
  • 职责:

    TODO

字段/常量

  • GENERATED_ITEM_MODEL_ID

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

      TODO

  • LAYERS

    • 类型: List<String>
    • 修饰符: public static final
    • 源码定位: L28
    • 说明:

      TODO

  • MIN_Z

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

      TODO

  • MAX_Z

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

      TODO

  • TEXTURE_SLOTS

    • 类型: TextureSlots.Data
    • 修饰符: private static final
    • 源码定位: L31
    • 说明:

      TODO

  • SOUTH_FACE_UVS

    • 类型: CuboidFace.UVs
    • 修饰符: private static final
    • 源码定位: L32
    • 说明:

      TODO

  • NORTH_FACE_UVS

    • 类型: CuboidFace.UVs
    • 修饰符: private static final
    • 源码定位: L33
    • 说明:

      TODO

  • UV_SHRINK

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

      TODO

内部类/嵌套类型

  • net.minecraft.client.resources.model.cuboid.ItemModelGenerator.ItemLayerKey

    • 类型: record
    • 修饰符: private
    • 源码定位: L210
    • 说明:

      TODO

  • net.minecraft.client.resources.model.cuboid.ItemModelGenerator.SideDirection

    • 类型: enum
    • 修饰符: private static
    • 源码定位: L221
    • 说明:

      TODO

  • net.minecraft.client.resources.model.cuboid.ItemModelGenerator.SideFace

    • 类型: record
    • 修饰符: private
    • 源码定位: L243
    • 说明:

      TODO

构造器

方法

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

public TextureSlots.Data textureSlots() @ L36

  • 方法名:textureSlots
  • 源码定位:L36
  • 返回类型:TextureSlots.Data
  • 修饰符:public

参数:

说明:

TODO

public UnbakedGeometry geometry() @ L41

  • 方法名:geometry
  • 源码定位:L41
  • 返回类型:UnbakedGeometry
  • 修饰符:public

参数:

说明:

TODO

public UnbakedModel.GuiLight guiLight() @ L46

  • 方法名:guiLight
  • 源码定位:L46
  • 返回类型:UnbakedModel.GuiLight
  • 修饰符:public

参数:

说明:

TODO

private static QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName name) @ L51

  • 方法名:bake
  • 源码定位:L51
  • 返回类型:QuadCollection
  • 修饰符:private static

参数:

  • textureSlots: TextureSlots
  • modelBaker: ModelBaker
  • modelState: ModelState
  • name: ModelDebugName

说明:

TODO

private static void bakeExtrudedSprite(QuadCollection.Builder builder, ModelBaker.Interner interner, ModelState modelState, BakedQuad.MaterialInfo materialInfo) @ L83

  • 方法名:bakeExtrudedSprite
  • 源码定位:L83
  • 返回类型:void
  • 修饰符:private static

参数:

  • builder: QuadCollection.Builder
  • interner: ModelBaker.Interner
  • modelState: ModelState
  • materialInfo: BakedQuad.MaterialInfo

说明:

TODO

private static void bakeSideFaces(QuadCollection.Builder builder, ModelBaker.Interner interner, ModelState modelState, BakedQuad.MaterialInfo materialInfo) @ L93

  • 方法名:bakeSideFaces
  • 源码定位:L93
  • 返回类型:void
  • 修饰符:private static

参数:

  • builder: QuadCollection.Builder
  • interner: ModelBaker.Interner
  • modelState: ModelState
  • materialInfo: BakedQuad.MaterialInfo

说明:

TODO

private static Collection<ItemModelGenerator.SideFace> getSideFaces(SpriteContents sprite) @ L170

  • 方法名:getSideFaces
  • 源码定位:L170
  • 返回类型:Collection<ItemModelGenerator.SideFace>
  • 修饰符:private static

参数:

  • sprite: SpriteContents

说明:

TODO

private static void checkTransition(ItemModelGenerator.SideDirection facing, Set<ItemModelGenerator.SideFace> sideFaces, SpriteContents sprite, int frame, int x, int y, int width, int height) @ L190

  • 方法名:checkTransition
  • 源码定位:L190
  • 返回类型:void
  • 修饰符:private static

参数:

  • facing: ItemModelGenerator.SideDirection
  • sideFaces: Set<ItemModelGenerator.SideFace>
  • sprite: SpriteContents
  • frame: int
  • x: int
  • y: int
  • width: int
  • height: int

说明:

TODO

private static boolean isTransparent(SpriteContents sprite, int frame, int x, int y, int width, int height) @ L205

  • 方法名:isTransparent
  • 源码定位:L205
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • sprite: SpriteContents
  • frame: int
  • x: int
  • y: int
  • width: int
  • height: int

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class ItemModelGenerator implements UnbakedModel {
    public static final Identifier GENERATED_ITEM_MODEL_ID = Identifier.withDefaultNamespace("builtin/generated");
    public static final List<String> LAYERS = List.of("layer0", "layer1", "layer2", "layer3", "layer4");
    private static final float MIN_Z = 7.5F;
    private static final float MAX_Z = 8.5F;
    private static final TextureSlots.Data TEXTURE_SLOTS = new TextureSlots.Data.Builder().addReference("particle", "layer0").build();
    private static final CuboidFace.UVs SOUTH_FACE_UVS = new CuboidFace.UVs(0.0F, 0.0F, 16.0F, 16.0F);
    private static final CuboidFace.UVs NORTH_FACE_UVS = new CuboidFace.UVs(16.0F, 0.0F, 0.0F, 16.0F);
    private static final float UV_SHRINK = 0.1F;
 
    @Override
    public TextureSlots.Data textureSlots() {
        return TEXTURE_SLOTS;
    }
 
    @Override
    public UnbakedGeometry geometry() {
        return ItemModelGenerator::bake;
    }
 
    @Override
    public UnbakedModel.@Nullable GuiLight guiLight() {
        return UnbakedModel.GuiLight.FRONT;
    }
 
    private static QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName name) {
        QuadCollection singleResult = null;
        QuadCollection.Builder builder = null;
 
        for (int layerIndex = 0; layerIndex < LAYERS.size(); layerIndex++) {
            String textureReference = LAYERS.get(layerIndex);
            Material material = textureSlots.getMaterial(textureReference);
            if (material == null) {
                break;
            }
 
            Material.Baked bakedMaterial = modelBaker.materials().get(material, name);
            QuadCollection bakedLayer = modelBaker.compute(new ItemModelGenerator.ItemLayerKey(bakedMaterial, modelState, layerIndex));
            if (builder != null) {
                builder.addAll(bakedLayer);
            } else if (singleResult != null) {
                builder = new QuadCollection.Builder();
                builder.addAll(singleResult);
                builder.addAll(bakedLayer);
                singleResult = null;
            } else {
                singleResult = bakedLayer;
            }
        }
 
        if (builder != null) {
            return builder.build();
        } else {
            return singleResult != null ? singleResult : QuadCollection.EMPTY;
        }
    }
 
    private static void bakeExtrudedSprite(
        QuadCollection.Builder builder, ModelBaker.Interner interner, ModelState modelState, BakedQuad.MaterialInfo materialInfo
    ) {
        Vector3f from = new Vector3f(0.0F, 0.0F, 7.5F);
        Vector3f to = new Vector3f(16.0F, 16.0F, 8.5F);
        builder.addUnculledFace(FaceBakery.bakeQuad(interner, from, to, SOUTH_FACE_UVS, Quadrant.R0, materialInfo, Direction.SOUTH, modelState, null));
        builder.addUnculledFace(FaceBakery.bakeQuad(interner, from, to, NORTH_FACE_UVS, Quadrant.R0, materialInfo, Direction.NORTH, modelState, null));
        bakeSideFaces(builder, interner, modelState, materialInfo);
    }
 
    private static void bakeSideFaces(QuadCollection.Builder builder, ModelBaker.Interner interner, ModelState modelState, BakedQuad.MaterialInfo materialInfo) {
        SpriteContents sprite = materialInfo.sprite().contents();
        float xScale = 16.0F / sprite.width();
        float yScale = 16.0F / sprite.height();
        Vector3f from = new Vector3f();
        Vector3f to = new Vector3f();
 
        for (ItemModelGenerator.SideFace sideFace : getSideFaces(sprite)) {
            float x = sideFace.x();
            float y = sideFace.y();
            ItemModelGenerator.SideDirection sideDirection = sideFace.facing();
            float u0 = x + 0.1F;
            float u1 = x + 1.0F - 0.1F;
            float v0;
            float v1;
            if (sideDirection.isHorizontal()) {
                v0 = y + 0.1F;
                v1 = y + 1.0F - 0.1F;
            } else {
                v0 = y + 1.0F - 0.1F;
                v1 = y + 0.1F;
            }
 
            float startX = x;
            float startY = y;
            float endX = x;
            float endY = y;
            switch (sideDirection) {
                case UP:
                    endX = x + 1.0F;
                    break;
                case DOWN:
                    endX = x + 1.0F;
                    startY = y + 1.0F;
                    endY = y + 1.0F;
                    break;
                case LEFT:
                    endY = y + 1.0F;
                    break;
                case RIGHT:
                    startX = x + 1.0F;
                    endX = x + 1.0F;
                    endY = y + 1.0F;
            }
 
            startX *= xScale;
            endX *= xScale;
            startY *= yScale;
            endY *= yScale;
            startY = 16.0F - startY;
            endY = 16.0F - endY;
            switch (sideDirection) {
                case UP:
                    from.set(startX, startY, 7.5F);
                    to.set(endX, startY, 8.5F);
                    break;
                case DOWN:
                    from.set(startX, endY, 7.5F);
                    to.set(endX, endY, 8.5F);
                    break;
                case LEFT:
                    from.set(startX, startY, 7.5F);
                    to.set(startX, endY, 8.5F);
                    break;
                case RIGHT:
                    from.set(endX, startY, 7.5F);
                    to.set(endX, endY, 8.5F);
                    break;
                default:
                    throw new UnsupportedOperationException();
            }
 
            CuboidFace.UVs uvs = new CuboidFace.UVs(u0 * xScale, v0 * yScale, u1 * xScale, v1 * yScale);
            builder.addUnculledFace(FaceBakery.bakeQuad(interner, from, to, uvs, Quadrant.R0, materialInfo, sideDirection.getDirection(), modelState, null));
        }
    }
 
    private static Collection<ItemModelGenerator.SideFace> getSideFaces(SpriteContents sprite) {
        int width = sprite.width();
        int height = sprite.height();
        Set<ItemModelGenerator.SideFace> sideFaces = new HashSet<>();
        sprite.getUniqueFrames().forEach(frame -> {
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    boolean thisOpaque = !isTransparent(sprite, frame, x, y, width, height);
                    if (thisOpaque) {
                        checkTransition(ItemModelGenerator.SideDirection.UP, sideFaces, sprite, frame, x, y, width, height);
                        checkTransition(ItemModelGenerator.SideDirection.DOWN, sideFaces, sprite, frame, x, y, width, height);
                        checkTransition(ItemModelGenerator.SideDirection.LEFT, sideFaces, sprite, frame, x, y, width, height);
                        checkTransition(ItemModelGenerator.SideDirection.RIGHT, sideFaces, sprite, frame, x, y, width, height);
                    }
                }
            }
        });
        return sideFaces;
    }
 
    private static void checkTransition(
        ItemModelGenerator.SideDirection facing,
        Set<ItemModelGenerator.SideFace> sideFaces,
        SpriteContents sprite,
        int frame,
        int x,
        int y,
        int width,
        int height
    ) {
        if (isTransparent(sprite, frame, x - facing.direction.getStepX(), y - facing.direction.getStepY(), width, height)) {
            sideFaces.add(new ItemModelGenerator.SideFace(facing, x, y));
        }
    }
 
    private static boolean isTransparent(SpriteContents sprite, int frame, int x, int y, int width, int height) {
        return x >= 0 && y >= 0 && x < width && y < height ? sprite.isTransparent(frame, x, y) : true;
    }
 
    @OnlyIn(Dist.CLIENT)
    private record ItemLayerKey(Material.Baked material, ModelState modelState, int layerIndex) implements ModelBaker.SharedOperationKey<QuadCollection> {
        public QuadCollection compute(ModelBaker modelBakery) {
            QuadCollection.Builder builder = new QuadCollection.Builder();
            BakedQuad.MaterialInfo materialInfo = modelBakery.interner()
                .materialInfo(BakedQuad.MaterialInfo.of(this.material, this.material.sprite().transparency(), this.layerIndex, true, 0));
            ItemModelGenerator.bakeExtrudedSprite(builder, modelBakery.interner(), this.modelState, materialInfo);
            return builder.build();
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private static enum SideDirection {
        UP(Direction.UP),
        DOWN(Direction.DOWN),
        LEFT(Direction.EAST),
        RIGHT(Direction.WEST);
 
        private final Direction direction;
 
        private SideDirection(Direction direction) {
            this.direction = direction;
        }
 
        public Direction getDirection() {
            return this.direction;
        }
 
        private boolean isHorizontal() {
            return this == DOWN || this == UP;
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private record SideFace(ItemModelGenerator.SideDirection facing, int x, int y) {
    }
}

引用的其他类

  • ModelState

    • 引用位置: 参数
  • SpriteContents

    • 引用位置: 参数
  • ModelBaker

    • 引用位置: 参数
  • ModelDebugName

    • 引用位置: 参数
  • UnbakedModel

    • 引用位置: 实现/返回值
  • CuboidFace

    • 引用位置: 字段/方法调用/构造调用
    • 关联成员: CuboidFace.UVs(), UVs()
  • FaceBakery

    • 引用位置: 方法调用
    • 关联成员: FaceBakery.bakeQuad()
  • BakedQuad

    • 引用位置: 参数/方法调用
    • 关联成员: BakedQuad.MaterialInfo.of()
  • QuadCollection

    • 引用位置: 参数/方法调用/构造调用/返回值
    • 关联成员: Builder(), QuadCollection.Builder()
  • UnbakedGeometry

    • 引用位置: 返回值
  • TextureSlots

    • 引用位置: 参数/字段/方法调用/构造调用/返回值
    • 关联成员: Builder(), TextureSlots.Data.Builder()
  • Identifier

    • 引用位置: 字段/方法调用
    • 关联成员: Identifier.withDefaultNamespace()