Repository: MinecraftForge/MinecraftForge (language: java)

Issue:
Fast Graphics doesn’t adjust RenderTypes when they are done in json
<!-- Thank you for reporting! -->

<!-- For support with crashes and issues, please create a post on the forum instead: -->
<!-- https://www.minecraftforge.net/forum/forum/18-support-bug-reports/ -->

**Minecraft Version:** 1.20.1-1.21.x

**Forge Version:** all for all those versions

**Logs:** {Link(s) to GitHub Gist with full latest.log and/or crash report} N/A

**Steps to Reproduce:**
 1. Make a custom block give it a cutout render type
 2. Load into game on fancy and view that you can see through it
 3. Change graphics to fast you can still see through the block

**Description of issue:**
Vanilla when going on fast graphics makes stuff like leaves not able to be seen through.  If you use the json render type in forge tho this isn’t respected causing performance issues.





Discussion / hints:
Yup, makes sense. I just checked ItemBlockRenderTypes.java (a class that has barely changed over the updates) and it looks like the render cutout variable is only actually marked for blocks that extend `LeavesBlock`. Actually, `IForgeBakedModel.getRenderTypes` delegates to this method `ItemBlockRenderTypes.getRenderLayers` which dictates this behavior. Although it is possible in theory for an implementation of baked model to not delegate to this method at all.

The problem with this is that there are several blocks that need the cutout render type even if we are in fast graphics. Iron bars, Glass blocks, even tripwires all rely on the cutout render type. It would be very strange if they suddenly started rendering like solid blocks if the graphics settings was set to fast.

I guess we could solve this by extending the model JSON even further to allow for render types when on fast or fancy. What do you think?
Is there any other block besides leaves that have this behavior?
None. You can check ItemBlockRenderType for yourself. At the top of the class are the list of vanilla blocks that do not use the solid render type.
Maybe we add an option for it then in json and just make it blank as default then it existing would be the value, then add it into the leaves model generator method
That can be arranged yeah. Though with regards to the patch, it would probably be best if we continue to let the LeavesBlock check occur before we try to get the render type from the model, since it's been that way for years now.
Sounds good
Ugh, honestly it might take a little bit before I will make the PR on this. Solving the problem in runtime isn't the issue, but it's making changes to the data generators. Forge's own model generators (which are deprecated now since Minecraft has its own) have methods that take an extra string and/or have a different name (i.e. `doorBlockWithRenderType`) to account for this.

For now we should get the latest Forge recommended builds out and then we can worry about this.
By the way, I'm working on this now. But I figured I should mention that I found an interesting workaround... by simply not declaring any render types in your leaves model.json. If there are no render types it defaults to vanilla's `ItemBlockRenderTypes` class which accounts for leaves in fast graphics.

What a time to be alive.

Fix patch:
diff --git a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch
index f81a36e73f0..696d269c653 100644
--- a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch
+++ b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch
@@ -52,7 +52,7 @@
      public static RenderType getRenderType(ItemStack p_109280_, boolean p_109281_) {
          Item item = p_109280_.getItem();
          if (item instanceof BlockItem) {
-@@ -390,11 +_,74 @@
+@@ -390,11 +_,79 @@
      }
  
      public static RenderType getRenderLayer(FluidState p_109288_) {
@@ -65,6 +65,11 @@
          renderCutout = p_109292_;
 +    }
 +
++    /** Forge: Check if we are running in {@linkplain net.minecraft.client.Minecraft#useFancyGraphics() fancy graphics} to account for fast graphics render types */
++    public static boolean isFancy() {
++        return renderCutout;
++    }
++
 +    private static final net.minecraftforge.client.ChunkRenderTypeSet CUTOUT_MIPPED = net.minecraftforge.client.ChunkRenderTypeSet.of(RenderType.cutoutMipped());
 +    private static final net.minecraftforge.client.ChunkRenderTypeSet SOLID = net.minecraftforge.client.ChunkRenderTypeSet.of(RenderType.solid());
 +    private static final Map<net.minecraft.core.Holder.Reference<Block>, net.minecraftforge.client.ChunkRenderTypeSet> BLOCK_RENDER_TYPES = Util.make(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(TYPE_BY_BLOCK.size(), 0.5F), map -> {
@@ -81,7 +86,7 @@
 +    });
 +
 +    /** @deprecated Use {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)}. */
-+    @Deprecated(since = "1.19")
++    @Deprecated(since = "1.21.4", forRemoval = true)
 +    public static net.minecraftforge.client.ChunkRenderTypeSet getRenderLayers(BlockState state) {
 +       Block block = state.getBlock();
 +       if (block instanceof LeavesBlock) {
@@ -92,20 +97,20 @@
 +    }
 +
 +    /** @deprecated Set your render type in your block model's JSON (eg. {@code "render_type": "cutout"}) or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */
-+    @Deprecated(since = "1.19")
++    @Deprecated(since = "1.21.4", forRemoval = true)
 +    public static void setRenderLayer(Block block, RenderType type) {
 +       com.google.common.base.Preconditions.checkArgument(type.getChunkLayerId() >= 0, "The argument must be a valid chunk render type returned by RenderType#chunkBufferLayers().");
 +       setRenderLayer(block, net.minecraftforge.client.ChunkRenderTypeSet.of(type));
 +    }
 +
 +    /** @deprecated Set your render type in your block model's JSON (eg. {@code "render_type": "cutout"}) or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */
-+    @Deprecated(since = "1.19")
++    @Deprecated(since = "1.21.4", forRemoval = true)
 +    public static synchronized void setRenderLayer(Block block, java.util.function.Predicate<RenderType> predicate) {
 +       setRenderLayer(block, createSetFromPredicate(predicate));
 +    }
 +
 +    /** @deprecated Set your render type in your block model's JSON (eg. {@code "render_type": "cutout"}) or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */
-+    @Deprecated(since = "1.19")
++    @Deprecated(since = "1.21.4", forRemoval = true)
 +    public static synchronized void setRenderLayer(Block block, net.minecraftforge.client.ChunkRenderTypeSet layers) {
 +       checkClientLoading();
 +       BLOCK_RENDER_TYPES.put(net.minecraftforge.registries.ForgeRegistries.BLOCKS.getDelegateOrThrow(block), layers);
diff --git a/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch b/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch
index e417bfbbbb1..40f0fbd94cf 100644
--- a/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch
+++ b/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch
@@ -1,74 +1,142 @@
 --- a/net/minecraft/client/resources/model/SimpleBakedModel.java
 +++ b/net/minecraft/client/resources/model/SimpleBakedModel.java
-@@ -26,6 +_,15 @@
+@@ -26,7 +_,32 @@
      protected final TextureAtlasSprite particleIcon;
      protected final ItemTransforms transforms;
      protected final ItemOverrides overrides;
+-
++    /** Forge: Block render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} */
 +    protected final net.minecraftforge.client.ChunkRenderTypeSet blockRenderTypes;
++    /** Forge: Block render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} */
++    protected final net.minecraftforge.client.ChunkRenderTypeSet blockRenderTypesFast;
++    /** Forge: Item render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} */
 +    protected final List<net.minecraft.client.renderer.RenderType> itemRenderTypes;
++    /** Forge: Item render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} */
++    protected final List<net.minecraft.client.renderer.RenderType> itemRenderTypesFast;
++    /** Forge: Item render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FABULOUS fabulous graphics} */
 +    protected final List<net.minecraft.client.renderer.RenderType> fabulousItemRenderTypes;
++    /** Forge: If this model's {@linkplain #blockRenderTypes block render types} are rendering cutout, to account for older leaves model JSONs */
++    protected final boolean isRenderingCutout;
 +
-+    /** @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, ItemOverrides, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup} **/
++    /** @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, ItemOverrides, net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup} **/
 +    @Deprecated
 +    public SimpleBakedModel(List<BakedQuad> p_119489_, Map<Direction, List<BakedQuad>> p_119490_, boolean p_119491_, boolean p_119492_, boolean p_119493_, TextureAtlasSprite p_119494_, ItemTransforms p_119495_, ItemOverrides p_119496_) {
 +        this(p_119489_, p_119490_, p_119491_, p_119492_, p_119493_, p_119494_, p_119495_, p_119496_, net.minecraftforge.client.RenderTypeGroup.EMPTY);
 +    }
- 
++
++    /** @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, ItemOverrides, net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup for fast graphics} **/
++    @Deprecated(forRemoval = true, since = "1.21.4")
++    public SimpleBakedModel(List<BakedQuad> p_119489_, Map<Direction, List<BakedQuad>> p_119490_, boolean p_119491_, boolean p_119492_, boolean p_119493_, TextureAtlasSprite p_119494_, ItemTransforms p_119495_, ItemOverrides p_119496_, net.minecraftforge.client.RenderTypeGroup renderTypes) {
++        this(p_119489_, p_119490_, p_119491_, p_119492_, p_119493_, p_119494_, p_119495_, p_119496_, renderTypes, net.minecraftforge.client.RenderTypeGroup.EMPTY);
++    }
++
++    /** Constructor with {@link net.minecraftforge.client.RenderTypeGroup RenderTypeGroup} for fancy and fast graphics. Preferred over {@link net.minecraft.client.renderer.ItemBlockRenderTypes#setRenderLayer(net.minecraft.world.level.block.Block, net.minecraft.client.renderer.RenderType) ItemBlockRenderTypes.setRenderLayer(Block, RenderType)}. */
      public SimpleBakedModel(
          List<BakedQuad> p_119489_,
-@@ -35,7 +_,8 @@
+         Map<Direction, List<BakedQuad>> p_119490_,
+@@ -35,7 +_,9 @@
          boolean p_119493_,
          TextureAtlasSprite p_119494_,
          ItemTransforms p_119495_,
 -        ItemOverrides p_119496_
 +        ItemOverrides p_119496_,
-+        net.minecraftforge.client.RenderTypeGroup renderTypes
++        net.minecraftforge.client.RenderTypeGroup renderTypes,
++        net.minecraftforge.client.RenderTypeGroup renderTypesFast
      ) {
          this.unculledFaces = p_119489_;
          this.culledFaces = p_119490_;
-@@ -45,6 +_,9 @@
+@@ -45,6 +_,15 @@
          this.particleIcon = p_119494_;
          this.transforms = p_119495_;
          this.overrides = p_119496_;
-+        this.blockRenderTypes = !renderTypes.isEmpty() ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypes.block()) : null;
-+        this.itemRenderTypes = !renderTypes.isEmpty() ? List.of(renderTypes.entity()) : null;
-+        this.fabulousItemRenderTypes = !renderTypes.isEmpty() ? List.of(renderTypes.entityFabulous()) : null;
++
++        boolean hasRenderTypes = renderTypes != null && !renderTypes.isEmpty();
++        boolean hasRenderTypesFast = renderTypesFast != null && !renderTypesFast.isEmpty();
++        this.blockRenderTypes = hasRenderTypes ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypes.block()) : null;
++        this.blockRenderTypesFast = hasRenderTypesFast ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypesFast.block()) : null;
++        this.itemRenderTypes = hasRenderTypes ? List.of(renderTypes.entity()) : null;
++        this.itemRenderTypesFast = hasRenderTypesFast ? List.of(renderTypesFast.entity()) : null;
++        this.fabulousItemRenderTypes = hasRenderTypes ? List.of(renderTypes.entityFabulous()) : null;
++        this.isRenderingCutout = hasRenderTypes && (renderTypes.block() == net.minecraft.client.renderer.RenderType.cutout() || renderTypes.block() == net.minecraft.client.renderer.RenderType.cutoutMipped());
      }
  
      @Override
-@@ -87,6 +_,25 @@
+@@ -87,6 +_,38 @@
          return this.overrides;
      }
  
++    private static final net.minecraftforge.client.ChunkRenderTypeSet SOLID_BLOCK = net.minecraftforge.client.ChunkRenderTypeSet.of(net.minecraft.client.renderer.RenderType.solid());
++    private static final List<net.minecraft.client.renderer.RenderType> SOLID_BLOCK_ITEM = List.of(net.minecraft.client.renderer.RenderType.solid());
++
 +    @Override
 +    public net.minecraftforge.client.ChunkRenderTypeSet getRenderTypes(BlockState state, RandomSource rand, net.minecraftforge.client.model.data.ModelData data) {
-+       return blockRenderTypes != null ? blockRenderTypes : BakedModel.super.getRenderTypes(state, rand, data);
++        if (!net.minecraft.client.renderer.ItemBlockRenderTypes.isFancy()) {
++            if (blockRenderTypesFast != null)
++                return blockRenderTypesFast;
++            if (isRenderingCutout && state.getBlock() instanceof net.minecraft.world.level.block.LeavesBlock)
++                return SOLID_BLOCK;
++        }
++        return blockRenderTypes != null ? blockRenderTypes : BakedModel.super.getRenderTypes(state, rand, data);
 +    }
 +
 +    @Override
 +    public List<net.minecraft.client.renderer.RenderType> getRenderTypes(net.minecraft.world.item.ItemStack itemStack, boolean fabulous) {
-+       if (!fabulous) {
-+          if (itemRenderTypes != null) {
-+              return itemRenderTypes;
-+          }
-+       } else {
-+          if (fabulousItemRenderTypes != null) {
-+              return fabulousItemRenderTypes;
-+          }
-+       }
-+       return BakedModel.super.getRenderTypes(itemStack, fabulous);
++        if (!fabulous) {
++            if (!net.minecraft.client.renderer.ItemBlockRenderTypes.isFancy()) {
++                if (itemRenderTypesFast != null)
++                    return itemRenderTypesFast;
++                if (isRenderingCutout && itemStack.getItem() instanceof net.minecraft.world.item.BlockItem blockItem && blockItem.getBlock() instanceof net.minecraft.world.level.block.LeavesBlock)
++                    return SOLID_BLOCK_ITEM;
++            }
++            if (itemRenderTypes != null)
++                return itemRenderTypes;
++        } else {
++            if (fabulousItemRenderTypes != null)
++                return fabulousItemRenderTypes;
++        }
++        return BakedModel.super.getRenderTypes(itemStack, fabulous);
 +    }
 +
      @OnlyIn(Dist.CLIENT)
      public static class Builder {
          private final List<BakedQuad> unculledFaces = Lists.newArrayList();
-@@ -133,12 +_,18 @@
+@@ -133,12 +_,49 @@
              return this;
          }
  
 +        private net.minecraftforge.client.RenderTypeGroup renderTypes = net.minecraftforge.client.RenderTypeGroup.EMPTY;
++        private net.minecraftforge.client.RenderTypeGroup renderTypesFast = net.minecraftforge.client.RenderTypeGroup.EMPTY;
++
++        /**
++         * Sets the render type to be used for this model, and will be used for any graphics setting.
++         * <p>
++         * If you need to set a specific render type for
++         * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}, consider using
++         * {@link #renderTypes(net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup)
++         * renderTypes(RenderTypeGroup, RenderTypeGroup)} instead which allows choosing render types for both fancy and
++         * fast graphics.
++         *
++         * @apiNote If this model is for {@linkplain net.minecraft.world.level.block.LeavesBlock leaves} and if the
++         * given render type is either {@linkplain net.minecraft.client.renderer.RenderType#cutout() cutout} or
++         * {@linkplain net.minecraft.client.renderer.RenderType#cutoutMipped() cutout mipped}, it will be overridden
++         * with {@linkplain net.minecraft.client.renderer.RenderType#solid() solid} when fast graphics is enabled.
++         * @see #renderTypes(net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup)
++         * renderTypes(RenderTypeGroup, RenderTypeGroup)
++         */
 +        public SimpleBakedModel.Builder renderTypes(net.minecraftforge.client.RenderTypeGroup renderTypes) {
++            return this.renderTypes(renderTypes, net.minecraftforge.client.RenderTypeGroup.EMPTY);
++        }
++
++        /**
++         * Sets the render types to be used for this model: one for
++         * {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} and one for
++         * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}.
++         *
++         * @see #renderTypes(net.minecraftforge.client.RenderTypeGroup)
++         */
++        public SimpleBakedModel.Builder renderTypes(net.minecraftforge.client.RenderTypeGroup renderTypes, net.minecraftforge.client.RenderTypeGroup renderTypesFast) {
 +            this.renderTypes = renderTypes;
++            this.renderTypesFast = renderTypesFast;
 +            return this;
 +        }
 +
@@ -78,7 +146,8 @@
              } else {
                  return new SimpleBakedModel(
 -                    this.unculledFaces, this.culledFaces, this.hasAmbientOcclusion, this.usesBlockLight, this.isGui3d, this.particleIcon, this.transforms, this.overrides
-+                    this.unculledFaces, this.culledFaces, this.hasAmbientOcclusion, this.usesBlockLight, this.isGui3d, this.particleIcon, this.transforms, this.overrides, this.renderTypes
++                    // Forge: Account for render types in model JSONs
++                    this.unculledFaces, this.culledFaces, this.hasAmbientOcclusion, this.usesBlockLight, this.isGui3d, this.particleIcon, this.transforms, this.overrides, this.renderTypes, this.renderTypesFast
                  );
              }
          }
diff --git a/src/main/java/net/minecraftforge/client/model/CompositeModel.java b/src/main/java/net/minecraftforge/client/model/CompositeModel.java
index 3212c4fa06e..2e24a67eefc 100644
--- a/src/main/java/net/minecraftforge/client/model/CompositeModel.java
+++ b/src/main/java/net/minecraftforge/client/model/CompositeModel.java
@@ -243,6 +243,7 @@ public static class Builder
             private final ItemTransforms transforms;
             private TextureAtlasSprite particle;
             private RenderTypeGroup lastRenderTypes = RenderTypeGroup.EMPTY;
+            private RenderTypeGroup lastRenderTypesFast = RenderTypeGroup.EMPTY;
 
             private Builder(boolean isAmbientOcclusion, boolean isGui3d, boolean isSideLit, TextureAtlasSprite particle, ItemOverrides overrides, ItemTransforms transforms)
             {
@@ -256,27 +257,38 @@ private Builder(boolean isAmbientOcclusion, boolean isGui3d, boolean isSideLit,
 
             public void addLayer(BakedModel model)
             {
-                flushQuads(null);
+                flushQuads(RenderTypeGroup.EMPTY, RenderTypeGroup.EMPTY);
                 children.add(model);
             }
 
             private void addLayer(RenderTypeGroup renderTypes, List<BakedQuad> quads)
             {
-                var modelBuilder = IModelBuilder.of(isAmbientOcclusion, isSideLit, isGui3d, transforms, overrides, particle, renderTypes);
+                this.addLayer(renderTypes, RenderTypeGroup.EMPTY, quads);
+            }
+
+            private void addLayer(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast, List<BakedQuad> quads)
+            {
+                var modelBuilder = IModelBuilder.of(isAmbientOcclusion, isSideLit, isGui3d, transforms, overrides, particle, renderTypes, renderTypesFast);
                 quads.forEach(modelBuilder::addUnculledFace);
                 children.add(modelBuilder.build());
             }
 
             private void flushQuads(RenderTypeGroup renderTypes)
+            {
+                this.flushQuads(renderTypes, RenderTypeGroup.EMPTY);
+            }
+
+            private void flushQuads(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast)
             {
                 if (!Objects.equals(renderTypes, lastRenderTypes))
                 {
                     if (!quads.isEmpty())
                     {
-                        addLayer(lastRenderTypes, quads);
+                        addLayer(lastRenderTypes, lastRenderTypesFast, quads);
                         quads.clear();
                     }
                     lastRenderTypes = renderTypes;
+                    lastRenderTypesFast = renderTypesFast;
                 }
             }
 
@@ -288,14 +300,24 @@ public Builder setParticle(TextureAtlasSprite particleSprite)
 
             public Builder addQuads(RenderTypeGroup renderTypes, BakedQuad... quadsToAdd)
             {
-                flushQuads(renderTypes);
+                return this.addQuads(renderTypes, RenderTypeGroup.EMPTY, quadsToAdd);
+            }
+
+            public Builder addQuads(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast, BakedQuad... quadsToAdd)
+            {
+                flushQuads(renderTypes, renderTypesFast);
                 Collections.addAll(quads, quadsToAdd);
                 return this;
             }
 
             public Builder addQuads(RenderTypeGroup renderTypes, Collection<BakedQuad> quadsToAdd)
             {
-                flushQuads(renderTypes);
+                return this.addQuads(renderTypes, RenderTypeGroup.EMPTY, quadsToAdd);
+            }
+
+            public Builder addQuads(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast, Collection<BakedQuad> quadsToAdd)
+            {
+                flushQuads(renderTypes, renderTypesFast);
                 quads.addAll(quadsToAdd);
                 return this;
             }
@@ -304,7 +326,7 @@ public BakedModel build()
             {
                 if (!quads.isEmpty())
                 {
-                    addLayer(lastRenderTypes, quads);
+                    addLayer(lastRenderTypes, lastRenderTypesFast, quads);
                 }
                 var childrenBuilder = ImmutableMap.<String, BakedModel>builder();
                 var itemPassesBuilder = ImmutableList.<BakedModel>builder();
diff --git a/src/main/java/net/minecraftforge/client/model/EmptyModel.java b/src/main/java/net/minecraftforge/client/model/EmptyModel.java
index 100cc97232b..32c8ccd5126 100644
--- a/src/main/java/net/minecraftforge/client/model/EmptyModel.java
+++ b/src/main/java/net/minecraftforge/client/model/EmptyModel.java
@@ -63,7 +63,7 @@ private static class Baked extends SimpleBakedModel
 
         public Baked()
         {
-            super(List.of(), Map.of(), false, false, false, UnitTextureAtlasSprite.INSTANCE, ItemTransforms.NO_TRANSFORMS, ItemOverrides.EMPTY, RenderTypeGroup.EMPTY);
+            super(List.of(), Map.of(), false, false, false, UnitTextureAtlasSprite.INSTANCE, ItemTransforms.NO_TRANSFORMS, ItemOverrides.EMPTY, RenderTypeGroup.EMPTY, RenderTypeGroup.EMPTY);
         }
 
         @Override
diff --git a/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java b/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java
index 59999748d94..41991f9c4a7 100644
--- a/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java
+++ b/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java
@@ -73,6 +73,12 @@ public BlockModel deserialize(JsonElement element, Type targetType, JsonDeserial
             model.customData.setRenderTypeHint(ResourceLocation.parse(renderTypeHintName));
         }
 
+        if (jsonobject.has("render_type_fast"))
+        {
+            var renderTypeHintName = GsonHelper.getAsString(jsonobject, "render_type_fast");
+            model.customData.setRenderTypeFastHint(ResourceLocation.parse(renderTypeHintName));
+        }
+
         if (jsonobject.has("visibility"))
         {
             JsonObject visibility = GsonHelper.getAsJsonObject(jsonobject, "visibility");
diff --git a/src/main/java/net/minecraftforge/client/model/IModelBuilder.java b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java
index ccb06792f5b..b2fee31a4c4 100644
--- a/src/main/java/net/minecraftforge/client/model/IModelBuilder.java
+++ b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java
@@ -34,6 +34,19 @@ static IModelBuilder<?> of(boolean hasAmbientOcclusion, boolean usesBlockLight,
         return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, overrides, particle, renderTypes);
     }
 
+    static IModelBuilder<?> of(
+        boolean hasAmbientOcclusion,
+        boolean usesBlockLight,
+        boolean isGui3d,
+        ItemTransforms transforms,
+        ItemOverrides overrides,
+        TextureAtlasSprite particle,
+        RenderTypeGroup renderTypes,
+        RenderTypeGroup renderTypesFast
+    ){
+        return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, overrides, particle, renderTypes, renderTypesFast);
+    }
+
     /**
      * Creates a new model builder that collects quads to the provided list, returning
      * {@linkplain EmptyModel#BAKED an empty model} if you call {@link #build()}.
@@ -53,13 +66,22 @@ class Simple implements IModelBuilder<Simple>
     {
         private final SimpleBakedModel.Builder builder;
         private final RenderTypeGroup renderTypes;
+        private final RenderTypeGroup renderTypesFast;
 
         private Simple(boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d,
                        ItemTransforms transforms, ItemOverrides overrides, TextureAtlasSprite particle,
                        RenderTypeGroup renderTypes)
+        {
+            this(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, overrides, particle, renderTypes, RenderTypeGroup.EMPTY);
+        }
+
+        private Simple(boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d,
+                       ItemTransforms transforms, ItemOverrides overrides, TextureAtlasSprite particle,
+                       RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast)
         {
             this.builder = new SimpleBakedModel.Builder(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, overrides).particle(particle);
             this.renderTypes = renderTypes;
+            this.renderTypesFast = renderTypesFast;
         }
 
         @Override
@@ -80,7 +102,7 @@ public Simple addUnculledFace(BakedQuad quad)
         @Override
         public BakedModel build()
         {
-            return builder.renderTypes(renderTypes).build();
+            return builder.renderTypes(renderTypes, renderTypesFast).build();
         }
     }
 
diff --git a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java
index a80cd90ce43..32cc555e1d3 100644
--- a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java
+++ b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java
@@ -43,11 +43,17 @@ public class ItemLayerModel implements IUnbakedGeometry<ItemLayerModel>
     @Nullable
     private ImmutableList<Material> textures;
     private final Int2ObjectMap<ResourceLocation> renderTypeNames;
+    private final Int2ObjectMap<ResourceLocation> renderTypeFastNames;
 
     private ItemLayerModel(@Nullable ImmutableList<Material> textures, Int2ObjectMap<ResourceLocation> renderTypeNames)
     {
+        this(textures, renderTypeNames, new Int2ObjectOpenHashMap<>());
+    }
+
+    private ItemLayerModel(@Nullable ImmutableList<Material> textures, Int2ObjectMap<ResourceLocation> renderTypeNames, Int2ObjectMap<ResourceLocation> renderTypeFastNames) {
         this.textures = textures;
         this.renderTypeNames = renderTypeNames;
+        this.renderTypeFastNames = renderTypeFastNames;
     }
 
     @Override
@@ -79,7 +85,9 @@ public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Functio
             var quads = UnbakedGeometryHelper.bakeElements(unbaked, $ -> sprite, modelState);
             var renderTypeName = renderTypeNames.get(i);
             var renderTypes = renderTypeName != null ? context.getRenderType(renderTypeName) : null;
-            builder.addQuads(renderTypes != null ? renderTypes : normalRenderTypes, quads);
+            var renderTypeFastName = renderTypeFastNames.get(i);
+            var renderTypesFast = renderTypeFastName != null ? context.getRenderType(renderTypeFastName) : null;
+            builder.addQuads(renderTypes != null ? renderTypes : normalRenderTypes, renderTypesFast != null ? renderTypesFast : RenderTypeGroup.EMPTY, quads);
         }
 
         return builder.build();
@@ -105,10 +113,27 @@ public ItemLayerModel read(JsonObject jsonObject, JsonDeserializationContext des
                 }
             }
 
-            return new ItemLayerModel(null, renderTypeNames);
+            var renderTypeFastNames = new Int2ObjectOpenHashMap<ResourceLocation>();
+            if (jsonObject.has("render_types_fast")) {
+                var renderTypes = jsonObject.getAsJsonObject("render_types_fast");
+                for (var entry : renderTypes.entrySet()) {
+                    var renderType = ResourceLocation.parse(entry.getKey());
+                    for (var layer : entry.getValue().getAsJsonArray())
+                        if (renderTypeFastNames.put(layer.getAsInt(), renderType) != null)
+                            throw new JsonParseException("Registered duplicate render type for layer " + layer);
+                }
+            }
+
+            return new ItemLayerModel(null, renderTypeNames, renderTypeFastNames);
         }
 
         protected void readLayerData(JsonObject jsonObject, String name, Int2ObjectOpenHashMap<ResourceLocation> renderTypeNames, Int2ObjectMap<ForgeFaceData> layerData, boolean logWarning)
+        {
+            this.readLayerData(jsonObject, name, renderTypeNames, new Int2ObjectOpenHashMap<>(), layerData, logWarning);
+        }
+
+        @Deprecated(forRemoval = true, since = "1.21.4")
+        protected void readLayerData(JsonObject jsonObject, String name, Int2ObjectOpenHashMap<ResourceLocation> renderTypeNames, Int2ObjectOpenHashMap<ResourceLocation> renderTypeFastNames, Int2ObjectMap<ForgeFaceData> layerData, boolean logWarning)
         {
             if (!jsonObject.has(name))
             {
diff --git a/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java b/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java
index e3e7d64fded..30a144047f6 100644
--- a/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java
+++ b/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java
@@ -250,6 +250,42 @@ public void axisBlockWithRenderType(RotatedPillarBlock block, ResourceLocation s
             models().cubeColumnHorizontal(name(block) + "_horizontal", side, end).renderType(renderType));
     }
 
+    public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, String renderType, String renderTypeFast) {
+        axisBlockWithRenderTypeAndFast(block, blockTexture(block), renderType, renderTypeFast);
+    }
+
+    public void logBlockWithRenderTypeAndFast(RotatedPillarBlock block, String renderType, String renderTypeFast) {
+        axisBlockWithRenderTypeAndFast(block, blockTexture(block), extend(blockTexture(block), "_top"), renderType, renderTypeFast);
+    }
+
+    public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation baseName, String renderType, String renderTypeFast) {
+        axisBlockWithRenderTypeAndFast(block, extend(baseName, "_side"), extend(baseName, "_end"), renderType, renderTypeFast);
+    }
+
+    public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation side, ResourceLocation end, String renderType, String renderTypeFast) {
+        axisBlock(block,
+            models().cubeColumn(name(block), side, end).renderType(renderType, renderTypeFast),
+            models().cubeColumnHorizontal(name(block) + "_horizontal", side, end).renderType(renderType, renderTypeFast));
+    }
+
+    public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        axisBlockWithRenderTypeAndFast(block, blockTexture(block), renderType, renderTypeFast);
+    }
+
+    public void logBlockWithRenderType(RotatedPillarBlock block, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        axisBlockWithRenderTypeAndFast(block, blockTexture(block), extend(blockTexture(block), "_top"), renderType, renderTypeFast);
+    }
+
+    public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation baseName, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        axisBlockWithRenderTypeAndFast(block, extend(baseName, "_side"), extend(baseName, "_end"), renderType, renderTypeFast);
+    }
+
+    public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation side, ResourceLocation end, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        axisBlock(block,
+            models().cubeColumn(name(block), side, end).renderType(renderType, renderTypeFast),
+            models().cubeColumnHorizontal(name(block) + "_horizontal", side, end).renderType(renderType, renderTypeFast));
+    }
+
     public void axisBlock(RotatedPillarBlock block, ModelFile vertical, ModelFile horizontal) {
         getVariantBuilder(block)
             .partialState().with(RotatedPillarBlock.AXIS, Axis.Y)
@@ -381,6 +417,38 @@ public void stairsBlockWithRenderType(StairBlock block, String name, ResourceLoc
         stairsBlockInternalWithRenderType(block, name + "_stairs", side, bottom, top, renderType);
     }
 
+    public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation texture, String renderType, String renderTypeFast) {
+        stairsBlockWithRenderTypeAndFast(block, texture, texture, texture, renderType, renderTypeFast);
+    }
+
+    public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) {
+        stairsBlockWithRenderTypeAndFast(block, name, texture, texture, texture, renderType, renderTypeFast);
+    }
+
+    public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) {
+        stairsBlockInternalWithRenderTypeAndFast(block, key(block).toString(), side, bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) {
+        stairsBlockInternalWithRenderTypeAndFast(block, name + "_stairs", side, bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        stairsBlockWithRenderTypeAndFast(block, texture, texture, texture, renderType, renderTypeFast);
+    }
+
+    public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        stairsBlockWithRenderTypeAndFast(block, name, texture, texture, texture, renderType, renderTypeFast);
+    }
+
+    public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        stairsBlockInternalWithRenderTypeAndFast(block, key(block).toString(), side, bottom, top, renderType, renderTypeFast);
+    }
+
+    public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        stairsBlockInternalWithRenderTypeAndFast(block, name + "_stairs", side, bottom, top, renderType, renderTypeFast);
+    }
+
     private void stairsBlockInternal(StairBlock block, String baseName, ResourceLocation side, ResourceLocation bottom, ResourceLocation top) {
         ModelFile stairs = models().stairs(baseName, side, bottom, top);
         ModelFile stairsInner = models().stairsInner(baseName + "_inner", side, bottom, top);
@@ -395,6 +463,13 @@ private void stairsBlockInternalWithRenderType(StairBlock block, String baseName
         stairsBlock(block, stairs, stairsInner, stairsOuter);
     }
 
+    private void stairsBlockInternalWithRenderTypeAndFast(StairBlock block, String baseName, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        ModelFile stairs = models().stairs(baseName, side, bottom, top).renderType(renderType, renderTypeFast);
+        ModelFile stairsInner = models().stairsInner(baseName + "_inner", side, bottom, top).renderType(renderType, renderTypeFast);
+        ModelFile stairsOuter = models().stairsOuter(baseName + "_outer", side, bottom, top).renderType(renderType, renderTypeFast);
+        stairsBlock(block, stairs, stairsInner, stairsOuter);
+    }
+
     public void stairsBlock(StairBlock block, ModelFile stairs, ModelFile stairsInner, ModelFile stairsOuter) {
         getVariantBuilder(block)
             .forAllStatesExcept(state -> {
@@ -532,6 +607,32 @@ public void fenceBlockWithRenderType(FenceBlock block, String name, ResourceLoca
             models().fenceSide(name + "_fence_side", texture).renderType(renderType));
     }
 
+    public void fenceBlockWithRenderTypeAndFast(FenceBlock block, ResourceLocation texture, String renderType, String renderTypeFast) {
+        String baseName = key(block).toString();
+        fourWayBlock(block,
+            models().fencePost(baseName + "_post", texture).renderType(renderType, renderTypeFast),
+            models().fenceSide(baseName + "_side", texture).renderType(renderType, renderTypeFast));
+    }
+
+    public void fenceBlockWithRenderTypeAndFast(FenceBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) {
+        fourWayBlock(block,
+            models().fencePost(name + "_fence_post", texture).renderType(renderType, renderTypeFast),
+            models().fenceSide(name + "_fence_side", texture).renderType(renderType, renderTypeFast));
+    }
+
+    public void fenceBlockWithRenderTypeAndFast(FenceBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        String baseName = key(block).toString();
+        fourWayBlock(block,
+            models().fencePost(baseName + "_post", texture).renderType(renderType, renderTypeFast),
+            models().fenceSide(baseName + "_side", texture).renderType(renderType, renderTypeFast));
+    }
+
+    public void fenceBlockWithRenderTypeAndFast(FenceBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        fourWayBlock(block,
+            models().fencePost(name + "_fence_post", texture).renderType(renderType, renderTypeFast),
+            models().fenceSide(name + "_fence_side", texture).renderType(renderType, renderTypeFast));
+    }
+
     public void fenceGateBlock(FenceGateBlock block, ResourceLocation texture) {
         fenceGateBlockInternal(block, key(block).toString(), texture);
     }
@@ -556,6 +657,22 @@ public void fenceGateBlockWithRenderType(FenceGateBlock block, String name, Reso
         fenceGateBlockInternalWithRenderType(block, name + "_fence_gate", texture, renderType);
     }
 
+    public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, ResourceLocation texture, String renderType, String renderTypeFast) {
+        fenceGateBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) {
+        fenceGateBlockInternalWithRenderTypeAndFast(block, name + "_fence_gate", texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        fenceGateBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, renderType, renderTypeFast);
+    }
+
+    public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        fenceGateBlockInternalWithRenderTypeAndFast(block, name + "_fence_gate", texture, renderType, renderTypeFast);
+    }
+
     private void fenceGateBlockInternal(FenceGateBlock block, String baseName, ResourceLocation texture) {
         ModelFile gate = models().fenceGate(baseName, texture);
         ModelFile gateOpen = models().fenceGateOpen(baseName + "_open", texture);
@@ -572,6 +689,14 @@ private void fenceGateBlockInternalWithRenderType(FenceGateBlock block, String b
         fenceGateBlock(block, gate, gateOpen, gateWall, gateWallOpen);
     }
 
+    private void fenceGateBlockInternalWithRenderTypeAndFast(FenceGateBlock block, String baseName, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        ModelFile gate = models().fenceGate(baseName, texture).renderType(renderType, renderTypeFast);
+        ModelFile gateOpen = models().fenceGateOpen(baseName + "_open", texture).renderType(renderType, renderTypeFast);
+        ModelFile gateWall = models().fenceGateWall(baseName + "_wall", texture).renderType(renderType, renderTypeFast);
+        ModelFile gateWallOpen = models().fenceGateWallOpen(baseName + "_wall_open", texture).renderType(renderType, renderTypeFast);
+        fenceGateBlock(block, gate, gateOpen, gateWall, gateWallOpen);
+    }
+
     public void fenceGateBlock(FenceGateBlock block, ModelFile gate, ModelFile gateOpen, ModelFile gateWall, ModelFile gateWallOpen) {
         getVariantBuilder(block).forAllStatesExcept(state -> {
             ModelFile model = gate;
@@ -613,6 +738,22 @@ public void wallBlockWithRenderType(WallBlock block, String name, ResourceLocati
         wallBlockInternalWithRenderType(block, name + "_wall", texture, renderType);
     }
 
+    public void wallBlockWithRenderTypeAndFast(WallBlock block, ResourceLocation texture, String renderType, String renderTypeFast) {
+        wallBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void wallBlockWithRenderTypeAndFast(WallBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) {
+        wallBlockInternalWithRenderTypeAndFast(block, name + "_wall", texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void wallBlockWithRenderTypeAndFast(WallBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        wallBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, renderType, renderTypeFast);
+    }
+
+    public void wallBlockWithRenderTypeAndFast(WallBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        wallBlockInternalWithRenderTypeAndFast(block, name + "_wall", texture, renderType, renderTypeFast);
+    }
+
     private void wallBlockInternal(WallBlock block, String baseName, ResourceLocation texture) {
         wallBlock(block, models().wallPost(baseName + "_post", texture),
             models().wallSide(baseName + "_side", texture),
@@ -625,6 +766,12 @@ private void wallBlockInternalWithRenderType(WallBlock block, String baseName, R
             models().wallSideTall(baseName + "_side_tall", texture).renderType(renderType));
     }
 
+    private void wallBlockInternalWithRenderTypeAndFast(WallBlock block, String baseName, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        wallBlock(block, models().wallPost(baseName + "_post", texture).renderType(renderType, renderTypeFast),
+            models().wallSide(baseName + "_side", texture).renderType(renderType, renderTypeFast),
+            models().wallSideTall(baseName + "_side_tall", texture).renderType(renderType, renderTypeFast));
+    }
+
     public static final ImmutableMap<Direction, Property<WallSide>> WALL_PROPS = ImmutableMap.<Direction, Property<WallSide>>builder()
             .put(Direction.EAST,  BlockStateProperties.EAST_WALL)
             .put(Direction.NORTH, BlockStateProperties.NORTH_WALL)
@@ -677,6 +824,22 @@ public void paneBlockWithRenderType(IronBarsBlock block, String name, ResourceLo
         paneBlockInternalWithRenderType(block, name + "_pane", pane, edge, renderType);
     }
 
+    public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, ResourceLocation pane, ResourceLocation edge, String renderType, String renderTypeFast) {
+        paneBlockInternalWithRenderTypeAndFast(block, key(block).toString(), pane, edge, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, String name, ResourceLocation pane, ResourceLocation edge, String renderType, String renderTypeFast) {
+        paneBlockInternalWithRenderTypeAndFast(block, name + "_pane", pane, edge, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, ResourceLocation pane, ResourceLocation edge, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        paneBlockInternalWithRenderTypeAndFast(block, key(block).toString(), pane, edge, renderType, renderTypeFast);
+    }
+
+    public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, String name, ResourceLocation pane, ResourceLocation edge, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        paneBlockInternalWithRenderTypeAndFast(block, name + "_pane", pane, edge, renderType, renderTypeFast);
+    }
+
     private void paneBlockInternal(IronBarsBlock block, String baseName, ResourceLocation pane, ResourceLocation edge) {
         ModelFile post = models().panePost(baseName + "_post", pane, edge);
         ModelFile side = models().paneSide(baseName + "_side", pane, edge);
@@ -695,6 +858,15 @@ private void paneBlockInternalWithRenderType(IronBarsBlock block, String baseNam
         paneBlock(block, post, side, sideAlt, noSide, noSideAlt);
     }
 
+    private void paneBlockInternalWithRenderTypeAndFast(IronBarsBlock block, String baseName, ResourceLocation pane, ResourceLocation edge, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        ModelFile post = models().panePost(baseName + "_post", pane, edge).renderType(renderType, renderTypeFast);
+        ModelFile side = models().paneSide(baseName + "_side", pane, edge).renderType(renderType, renderTypeFast);
+        ModelFile sideAlt = models().paneSideAlt(baseName + "_side_alt", pane, edge).renderType(renderType, renderTypeFast);
+        ModelFile noSide = models().paneNoSide(baseName + "_noside", pane).renderType(renderType, renderTypeFast);
+        ModelFile noSideAlt = models().paneNoSideAlt(baseName + "_noside_alt", pane).renderType(renderType, renderTypeFast);
+        paneBlock(block, post, side, sideAlt, noSide, noSideAlt);
+    }
+
     public void paneBlock(IronBarsBlock block, ModelFile post, ModelFile side, ModelFile sideAlt, ModelFile noSide, ModelFile noSideAlt) {
         MultiPartBlockStateBuilder builder = getMultipartBuilder(block)
             .part().modelFile(post).addModel().end();
@@ -734,6 +906,22 @@ public void doorBlockWithRenderType(DoorBlock block, String name, ResourceLocati
         doorBlockInternalWithRenderType(block, name + "_door", bottom, top, renderType);
     }
 
+    public void doorBlockWithRenderTypeAndFast(DoorBlock block, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) {
+        doorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void doorBlockWithRenderTypeAndFast(DoorBlock block, String name, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) {
+        doorBlockInternalWithRenderTypeAndFast(block, name + "_door", bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void doorBlockWithRenderTypeAndFast(DoorBlock block, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        doorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), bottom, top, renderType, renderTypeFast);
+    }
+
+    public void doorBlockWithRenderTypeAndFast(DoorBlock block, String name, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        doorBlockInternalWithRenderTypeAndFast(block, name + "_door", bottom, top, renderType, renderTypeFast);
+    }
+
     private void doorBlockInternal(DoorBlock block, String baseName, ResourceLocation bottom, ResourceLocation top) {
         ModelFile bottomLeft = models().doorBottomLeft(baseName + "_bottom_left", bottom, top);
         ModelFile bottomLeftOpen = models().doorBottomLeftOpen(baseName + "_bottom_left_open", bottom, top);
@@ -758,6 +946,18 @@ private void doorBlockInternalWithRenderType(DoorBlock block, String baseName, R
         doorBlock(block, bottomLeft, bottomLeftOpen, bottomRight, bottomRightOpen, topLeft, topLeftOpen, topRight, topRightOpen);
     }
 
+    private void doorBlockInternalWithRenderTypeAndFast(DoorBlock block, String baseName, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        ModelFile bottomLeft = models().doorBottomLeft(baseName + "_bottom_left", bottom, top).renderType(renderType, renderTypeFast);
+        ModelFile bottomLeftOpen = models().doorBottomLeftOpen(baseName + "_bottom_left_open", bottom, top).renderType(renderType, renderTypeFast);
+        ModelFile bottomRight = models().doorBottomRight(baseName + "_bottom_right", bottom, top).renderType(renderType, renderTypeFast);
+        ModelFile bottomRightOpen = models().doorBottomRightOpen(baseName + "_bottom_right_open", bottom, top).renderType(renderType, renderTypeFast);
+        ModelFile topLeft = models().doorTopLeft(baseName + "_top_left", bottom, top).renderType(renderType, renderTypeFast);
+        ModelFile topLeftOpen = models().doorTopLeftOpen(baseName + "_top_left_open", bottom, top).renderType(renderType, renderTypeFast);
+        ModelFile topRight = models().doorTopRight(baseName + "_top_right", bottom, top).renderType(renderType, renderTypeFast);
+        ModelFile topRightOpen = models().doorTopRightOpen(baseName + "_top_right_open", bottom, top).renderType(renderType, renderTypeFast);
+        doorBlock(block, bottomLeft, bottomLeftOpen, bottomRight, bottomRightOpen, topLeft, topLeftOpen, topRight, topRightOpen);
+    }
+
     public void doorBlock(DoorBlock block, ModelFile bottomLeft, ModelFile bottomLeftOpen, ModelFile bottomRight, ModelFile bottomRightOpen, ModelFile topLeft, ModelFile topLeftOpen, ModelFile topRight, ModelFile topRightOpen) {
         getVariantBuilder(block).forAllStatesExcept(state -> {
             int yRot = ((int) state.getValue(DoorBlock.FACING).toYRot()) + 90;
@@ -824,6 +1024,22 @@ public void trapdoorBlockWithRenderType(TrapDoorBlock block, String name, Resour
         trapdoorBlockInternalWithRenderType(block, name + "_trapdoor", texture, orientable, renderType);
     }
 
+    public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, ResourceLocation texture, boolean orientable, String renderType, String renderTypeFast) {
+        trapdoorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, orientable, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, String name, ResourceLocation texture, boolean orientable, String renderType, String renderTypeFast) {
+        trapdoorBlockInternalWithRenderTypeAndFast(block, name + "_trapdoor", texture, orientable, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
+    }
+
+    public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, ResourceLocation texture, boolean orientable, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        trapdoorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, orientable, renderType, renderTypeFast);
+    }
+
+    public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, String name, ResourceLocation texture, boolean orientable, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        trapdoorBlockInternalWithRenderTypeAndFast(block, name + "_trapdoor", texture, orientable, renderType, renderTypeFast);
+    }
+
     private void trapdoorBlockInternal(TrapDoorBlock block, String baseName, ResourceLocation texture, boolean orientable) {
         ModelFile bottom = orientable ? models().trapdoorOrientableBottom(baseName + "_bottom", texture) : models().trapdoorBottom(baseName + "_bottom", texture);
         ModelFile top = orientable ? models().trapdoorOrientableTop(baseName + "_top", texture) : models().trapdoorTop(baseName + "_top", texture);
@@ -838,6 +1054,13 @@ private void trapdoorBlockInternalWithRenderType(TrapDoorBlock block, String bas
         trapdoorBlock(block, bottom, top, open, orientable);
     }
 
+    private void trapdoorBlockInternalWithRenderTypeAndFast(TrapDoorBlock block, String baseName, ResourceLocation texture, boolean orientable, ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        ModelFile bottom = orientable ? models().trapdoorOrientableBottom(baseName + "_bottom", texture).renderType(renderType, renderTypeFast) : models().trapdoorBottom(baseName + "_bottom", texture).renderType(renderType, renderTypeFast);
+        ModelFile top = orientable ? models().trapdoorOrientableTop(baseName + "_top", texture).renderType(renderType, renderTypeFast) : models().trapdoorTop(baseName + "_top", texture).renderType(renderType, renderTypeFast);
+        ModelFile open = orientable ? models().trapdoorOrientableOpen(baseName + "_open", texture).renderType(renderType, renderTypeFast) : models().trapdoorOpen(baseName + "_open", texture).renderType(renderType, renderTypeFast);
+        trapdoorBlock(block, bottom, top, open, orientable);
+    }
+
     public void trapdoorBlock(TrapDoorBlock block, ModelFile bottom, ModelFile top, ModelFile open, boolean orientable) {
         getVariantBuilder(block).forAllStatesExcept(state -> {
             int xRot = 0;
diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java
index f6b45c4f54f..15b5cac15b8 100644
--- a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java
+++ b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java
@@ -60,6 +60,7 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
     protected final ExistingFileHelper existingFileHelper;
 
     protected String renderType = null;
+    protected String renderTypeFast = null;
     protected boolean ambientOcclusion = true;
     protected GuiLight guiLight = null;
 
@@ -149,12 +150,17 @@ public T texture(String key, ResourceLocation texture) {
     }
 
     /**
-     * Set the render type for this model.
+     * Set the render type for this model. Any render types to be used must be registered via
+     * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}.
+     * <p>
+     * Consider using {@linkplain #renderType(String, String)} if you need to set a render type for
+     * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}.
      *
-     * @param renderType the render type. Must be registered via
-     *                   {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent}
+     * @param renderType the render type
      * @return this builder
-     * @throws NullPointerException  if {@code renderType} is {@code null}
+     *
+     * @throws NullPointerException if {@code renderType} is {@code null}
+     * @see #renderType(String, String)
      */
     public T renderType(String renderType) {
         Preconditions.checkNotNull(renderType, "Render type must not be null");
@@ -162,16 +168,55 @@ public T renderType(String renderType) {
     }
 
     /**
-     * Set the render type for this model.
+     * Set the render types for this model. Any render types to be used must be registered via
+     * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}.
+     *
+     * @param renderType     the render type for {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics}
+     * @param renderTypeFast the render type for {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}
+     * @return this builder
+     *
+     * @throws NullPointerException if {@code renderType} is {@code null}
+     */
+    public T renderType(String renderType, String renderTypeFast) {
+        Preconditions.checkNotNull(renderType, "Render type must not be null");
+        return renderType(ResourceLocation.parse(renderType), ResourceLocation.parse(renderTypeFast));
+    }
+
+    /**
+     * Set the render type for this model. Any render types to be used must be registered via
+     * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}.
+     * <p>
+     * Consider using {@linkplain #renderType(ResourceLocation, ResourceLocation)} if you need to set a render type for
+     * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}.
      *
-     * @param renderType the render type. Must be registered via
-     *                   {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent}
+     * @param renderType the render type
      * @return this builder
-     * @throws NullPointerException  if {@code renderType} is {@code null}
+     *
+     * @throws NullPointerException if {@code renderType} is {@code null}
+     * @see #renderType(ResourceLocation, ResourceLocation)
      */
     public T renderType(ResourceLocation renderType) {
         Preconditions.checkNotNull(renderType, "Render type must not be null");
         this.renderType = renderType.toString();
+        this.renderTypeFast = null;
+        return self();
+    }
+
+    /**
+     * Set the render types for this model. Any render types to be used must be registered via
+     * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}.
+     *
+     * @param renderType     the render type for {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics}
+     * @param renderTypeFast the render type for {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}
+     * @return this builder
+     *
+     * @throws NullPointerException if {@code renderType} is {@code null}
+     */
+    public T renderType(ResourceLocation renderType, ResourceLocation renderTypeFast) {
+        Preconditions.checkNotNull(renderType, "Render type must not be null");
+        Preconditions.checkNotNull(renderTypeFast, "Fast graphics render type must not be null");
+        this.renderType = renderType.toString();
+        this.renderTypeFast = renderType.toString();
         return self();
     }
 
diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java b/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java
index 41e7053463e..78b9b60ddf0 100644
--- a/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java
+++ b/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java
@@ -366,7 +366,8 @@ public T carpet(String name, ResourceLocation wool) {
     }
 
     public T leaves(String name, ResourceLocation texture) {
-        return singleTexture(name, BLOCK_FOLDER + "/leaves", "all", texture);
+        return singleTexture(name, BLOCK_FOLDER + "/leaves", "all", texture)
+            .renderType("cutout_mipped", "solid");
     }
 
     /**
diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java
index 12aedcfb378..cad4440e4de 100644
--- a/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java
+++ b/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java
@@ -34,6 +34,7 @@ public static <T extends ModelBuilder<T>> ItemLayerModelBuilder<T> begin(T paren
 
     private final Int2ObjectMap<ForgeFaceData> faceData = new Int2ObjectOpenHashMap<>();
     private final Map<ResourceLocation, IntSet> renderTypes = new LinkedHashMap<>();
+    private final Map<ResourceLocation, IntSet> renderTypesFast = new LinkedHashMap<>();
     private final IntSet layersWithRenderTypes = new IntOpenHashSet();
 
     protected ItemLayerModelBuilder(T parent, ExistingFileHelper existingFileHelper)
@@ -116,6 +117,23 @@ public ItemLayerModelBuilder<T> renderType(String renderType, int... layers)
         return renderType(asLoc, layers);
     }
 
+    public ItemLayerModelBuilder<T> renderType(String renderType, String renderTypeFast, int... layers)
+    {
+        Preconditions.checkNotNull(renderType, "Render type must not be null");
+        Preconditions.checkNotNull(renderTypeFast, "Fast graphics render type must not be null");
+        ResourceLocation asLoc;
+        if (renderType.contains(":"))
+            asLoc = ResourceLocation.parse(renderType);
+        else
+            asLoc = parent.getLocation().withPath(renderType);
+        ResourceLocation asLocFast;
+        if (renderTypeFast.contains(":"))
+            asLocFast = ResourceLocation.parse(renderTypeFast);
+        else
+            asLocFast = parent.getLocation().withPath(renderTypeFast);
+        return renderType(asLoc, asLocFast, layers);
+    }
+
     /**
      * Set the render type for a set of layers.
      *
@@ -145,6 +163,25 @@ public ItemLayerModelBuilder<T> renderType(ResourceLocation renderType, int... l
         return this;
     }
 
+    public ItemLayerModelBuilder<T> renderType(ResourceLocation renderType, ResourceLocation renderTypeFast, int... layers)
+    {
+        Preconditions.checkNotNull(renderType, "Render type must not be null");
+        Preconditions.checkNotNull(renderTypeFast, "Fast graphics render type must not be null");
+        Preconditions.checkNotNull(layers, "Layers must not be null");
+        Preconditions.checkArgument(layers.length > 0, "At least one layer must be specified");
+        Preconditions.checkArgument(Arrays.stream(layers).allMatch(i -> i >= 0), "All layers must be >= 0");
+        var alreadyAssigned = Arrays.stream(layers).filter(layersWithRenderTypes::contains).toArray();
+        Preconditions.checkArgument(alreadyAssigned.length == 0, "Attempted to re-assign layer render types: " + Arrays.toString(alreadyAssigned));
+        var renderTypeLayers = renderTypes.computeIfAbsent(renderType, $ -> new IntOpenHashSet());
+        var renderTypeFastLayers = renderTypesFast.computeIfAbsent(renderType, $ -> new IntOpenHashSet());
+        Arrays.stream(layers).forEach(layer -> {
+            renderTypeLayers.add(layer);
+            renderTypeFastLayers.add(layer);
+            layersWithRenderTypes.add(layer);
+        });
+        return this;
+    }
+
     @Override
     public JsonObject toJson(JsonObject json)
     {
@@ -171,6 +208,14 @@ public JsonObject toJson(JsonObject json)
         });
         json.add("render_types", renderTypes);
 
+        JsonObject renderTypesFast = new JsonObject();
+        this.renderTypesFast.forEach((renderTypeFast, layers) -> {
+            JsonArray array = new JsonArray();
+            layers.intStream().sorted().forEach(array::add);
+            renderTypesFast.add(renderTypeFast.toString(), array);
+        });
+        json.add("render_types_fast", renderTypesFast);
+
         return json;
     }
 }
diff --git a/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java b/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java
index 99b560c0852..fd4169d6531 100644
--- a/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java
+++ b/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java
@@ -41,6 +41,8 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext
     private Transformation rootTransform;
     @Nullable
     private ResourceLocation renderTypeHint;
+    @Nullable
+    private ResourceLocation renderTypeFastHint;
     private boolean gui3d = true;
 
     @ApiStatus.Internal
@@ -137,11 +139,25 @@ public ResourceLocation getRenderTypeHint()
         return owner.parent != null ? owner.parent.customData.getRenderTypeHint() : null;
     }
 
+    @Nullable
+    @Override
+    public ResourceLocation getRenderTypeFastHint()
+    {
+        if (renderTypeFastHint != null)
+            return renderTypeFastHint;
+        return owner.parent != null ? owner.parent.customData.getRenderTypeFastHint() : null;
+    }
+
     public void setRenderTypeHint(ResourceLocation renderTypeHint)
     {
         this.renderTypeHint = renderTypeHint;
     }
 
+    public void setRenderTypeFastHint(ResourceLocation renderTypeFastHint)
+    {
+        this.renderTypeFastHint = renderTypeFastHint;
+    }
+
     public void setGui3d(boolean gui3d)
     {
         this.gui3d = gui3d;
@@ -153,6 +169,7 @@ public void copyFrom(BlockGeometryBakingContext other)
         this.rootTransform = other.rootTransform;
         this.visibilityData.copyFrom(other.visibilityData);
         this.renderTypeHint = other.renderTypeHint;
+        this.renderTypeFastHint = other.renderTypeFastHint;
         this.gui3d = other.gui3d;
     }
 
diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java b/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java
index 8df243e43d5..c453e573699 100644
--- a/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java
+++ b/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java
@@ -75,6 +75,13 @@ public interface IGeometryBakingContext
     @Nullable
     ResourceLocation getRenderTypeHint();
 
+    /**
+     * @return a hint of the {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} render type this model
+     * should use. Custom loaders may ignore this.
+     */
+    @Nullable
+    default ResourceLocation getRenderTypeFastHint() { return null; }
+
     /**
      * Queries the visibility of a component of this model.
      *
@@ -91,4 +98,20 @@ default RenderTypeGroup getRenderType(ResourceLocation name)
     {
         return NamedRenderTypeManager.get(name);
     }
+
+    /**
+     * {@return a {@link RenderTypeGroup} from the {@link #getRenderTypeHint()}, or the empty group if not found.}
+     */
+    default RenderTypeGroup getRenderType() {
+        var hint = getRenderTypeHint();
+        return hint == null ? RenderTypeGroup.EMPTY : getRenderType(hint);
+    }
+
+    /**
+     * {@return a {@link RenderTypeGroup} from the {@link #getRenderTypeHint()}, or the empty group if not found.}
+     */
+    default RenderTypeGroup getRenderTypeFast() {
+        var hint = getRenderTypeFastHint();
+        return hint == null ? RenderTypeGroup.EMPTY : getRenderType(hint);
+    }
 }
diff --git a/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java b/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java
index cf79fb240d0..bc85c50130c 100644
--- a/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java
+++ b/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java
@@ -28,10 +28,8 @@ public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Functio
     {
         TextureAtlasSprite particle = spriteGetter.apply(context.getMaterial("particle"));
 
-        var renderTypeHint = context.getRenderTypeHint();
-        var renderTypes = renderTypeHint != null ? context.getRenderType(renderTypeHint) : RenderTypeGroup.EMPTY;
         IModelBuilder<?> builder = IModelBuilder.of(context.useAmbientOcclusion(), context.useBlockLight(), context.isGui3d(),
-                context.getTransforms(), overrides, particle, renderTypes);
+                context.getTransforms(), overrides, particle, context.getRenderType(), context.getRenderTypeFast());
 
         addQuads(context, builder, baker, spriteGetter, modelState);
 
diff --git a/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java b/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java
index 208caae29fc..96020d9d400 100644
--- a/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java
+++ b/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java
@@ -54,6 +54,8 @@ public static StandaloneGeometryBakingContext create(ResourceLocation modelName,
     private final Transformation rootTransform;
     @Nullable
     private final ResourceLocation renderTypeHint;
+    @Nullable
+    private final ResourceLocation renderTypeFastHint;
     private final BiPredicate<String, Boolean> visibilityTest;
 
     private StandaloneGeometryBakingContext(ResourceLocation modelName, Predicate<String> materialCheck,
@@ -62,6 +64,18 @@ private StandaloneGeometryBakingContext(ResourceLocation modelName, Predicate<St
                                             ItemTransforms transforms, Transformation rootTransform,
                                             @Nullable ResourceLocation renderTypeHint,
                                             BiPredicate<String, Boolean> visibilityTest)
+    {
+        this(modelName, materialCheck, materialLookup, isGui3d, useBlockLight, useAmbientOcclusion,
+                transforms, rootTransform, renderTypeHint, null, visibilityTest);
+    }
+
+    private StandaloneGeometryBakingContext(ResourceLocation modelName, Predicate<String> materialCheck,
+                                            Function<String, Material> materialLookup, boolean isGui3d,
+                                            boolean useBlockLight, boolean useAmbientOcclusion,
+                                            ItemTransforms transforms, Transformation rootTransform,
+                                            @Nullable ResourceLocation renderTypeHint,
+                                            @Nullable ResourceLocation renderTypeFastHint,
+                                            BiPredicate<String, Boolean> visibilityTest)
     {
         this.modelName = modelName;
         this.materialCheck = materialCheck;
@@ -72,6 +86,7 @@ private StandaloneGeometryBakingContext(ResourceLocation modelName, Predicate<St
         this.transforms = transforms;
         this.rootTransform = rootTransform;
         this.renderTypeHint = renderTypeHint;
+        this.renderTypeFastHint = renderTypeFastHint;
         this.visibilityTest = visibilityTest;
     }
 
@@ -130,6 +145,12 @@ public ResourceLocation getRenderTypeHint()
         return renderTypeHint;
     }
 
+    @Nullable
+    @Override
+    public ResourceLocation getRenderTypeFastHint() {
+        return renderTypeFastHint;
+    }
+
     @Override
     public boolean isComponentVisible(String component, boolean fallback)
     {
@@ -158,6 +179,8 @@ public static final class Builder
         private Transformation rootTransform = Transformation.identity();
         @Nullable
         private ResourceLocation renderTypeHint;
+        @Nullable
+        private ResourceLocation renderTypeFastHint;
         private BiPredicate<String, Boolean> visibilityTest = (c, def) -> def;
 
         private Builder()
@@ -174,6 +197,7 @@ private Builder(IGeometryBakingContext parent)
             this.transforms = parent.getTransforms();
             this.rootTransform = parent.getRootTransform();
             this.renderTypeHint = parent.getRenderTypeHint();
+            this.renderTypeFastHint = parent.getRenderTypeFastHint();
             this.visibilityTest = parent::isComponentVisible;
         }
 
@@ -229,6 +253,14 @@ public Builder withRootTransform(Transformation rootTransform)
         public Builder withRenderTypeHint(ResourceLocation renderTypeHint)
         {
             this.renderTypeHint = renderTypeHint;
+            this.renderTypeFastHint = null;
+            return this;
+        }
+
+        public Builder withRenderTypeHint(ResourceLocation renderTypeHint, ResourceLocation renderTypeFastHint)
+        {
+            this.renderTypeHint = renderTypeHint;
+            this.renderTypeFastHint = renderTypeFastHint;
             return this;
         }
 
@@ -240,7 +272,7 @@ public Builder withVisibleComponents(Object2BooleanMap<String> parts)
 
         public StandaloneGeometryBakingContext build(ResourceLocation modelName)
         {
-            return new StandaloneGeometryBakingContext(modelName, materialCheck, materialLookup, isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, visibilityTest);
+            return new StandaloneGeometryBakingContext(modelName, materialCheck, materialLookup, isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, renderTypeFastHint, visibilityTest);
         }
     }
 }


Test patch:
diff --git a/src/test/generated/model_render_type/assets/model_render_type/blockstates/old_leaves.json b/src/test/generated/model_render_type/assets/model_render_type/blockstates/old_leaves.json
new file mode 100644
index 00000000000..f182f534620
--- /dev/null
+++ b/src/test/generated/model_render_type/assets/model_render_type/blockstates/old_leaves.json
@@ -0,0 +1,7 @@
+{
+  "variants": {
+    "": {
+      "model": "model_render_type:block/old_leaves"
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/test/generated/model_render_type/assets/model_render_type/models/block/old_leaves.json b/src/test/generated/model_render_type/assets/model_render_type/models/block/old_leaves.json
new file mode 100644
index 00000000000..362976935c6
--- /dev/null
+++ b/src/test/generated/model_render_type/assets/model_render_type/models/block/old_leaves.json
@@ -0,0 +1,7 @@
+{
+  "parent": "minecraft:block/leaves",
+  "render_type": "minecraft:cutout_mipped",
+  "textures": {
+    "all": "minecraft:block/oak_leaves"
+  }
+}
\ No newline at end of file
diff --git a/src/test/generated/model_render_type/assets/model_render_type/models/item/old_leaves.json b/src/test/generated/model_render_type/assets/model_render_type/models/item/old_leaves.json
new file mode 100644
index 00000000000..806af91bda5
--- /dev/null
+++ b/src/test/generated/model_render_type/assets/model_render_type/models/item/old_leaves.json
@@ -0,0 +1,3 @@
+{
+  "parent": "model_render_type:block/old_leaves"
+}
\ No newline at end of file
diff --git a/src/test/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java b/src/test/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java
new file mode 100644
index 00000000000..f0475b718ac
--- /dev/null
+++ b/src/test/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) Forge Development LLC and contributors
+ * SPDX-License-Identifier: LGPL-2.1-only
+ */
+
+package net.minecraftforge.debug.client;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.ItemBlockRenderTypes;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.gametest.framework.GameTest;
+import net.minecraft.gametest.framework.GameTestHelper;
+import net.minecraft.world.item.BlockItem;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.LeavesBlock;
+import net.minecraft.world.level.block.SoundType;
+import net.minecraft.world.level.block.state.BlockBehaviour;
+import net.minecraft.world.level.material.MapColor;
+import net.minecraft.world.level.material.PushReaction;
+import net.minecraftforge.client.model.data.ModelData;
+import net.minecraftforge.client.model.generators.BlockStateProvider;
+import net.minecraftforge.client.model.generators.ItemModelProvider;
+import net.minecraftforge.data.event.GatherDataEvent;
+import net.minecraftforge.eventbus.api.SubscribeEvent;
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
+import net.minecraftforge.gametest.GameTestHolder;
+import net.minecraftforge.registries.DeferredRegister;
+import net.minecraftforge.registries.RegistryObject;
+import net.minecraftforge.test.BaseTestMod;
+
+@Mod(ModelRenderLayerTest.MODID)
+@GameTestHolder("forge." + ModelRenderLayerTest.MODID)
+public class ModelRenderLayerTest extends BaseTestMod {
+    public static final String MODID = "model_render_type";
+
+    private static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(Registries.BLOCK, MODID);
+
+    private static final String OLD_LEAVES_NAME = "old_leaves";
+    private static final BlockBehaviour.StatePredicate FALSE = (state, level, pos) -> false;
+    public static final RegistryObject<LeavesBlock> OLD_LEAVES = BLOCKS.register(OLD_LEAVES_NAME,
+        () -> new LeavesBlock(
+            BlockBehaviour.Properties.of()
+                .mapColor(MapColor.PLANT)
+                .strength(0.2F)
+                .randomTicks()
+                .sound(SoundType.GRASS)
+                .noOcclusion()
+                .isSuffocating(FALSE)
+                .isViewBlocking(FALSE)
+                .ignitedByLava()
+                .pushReaction(PushReaction.DESTROY)
+                .isRedstoneConductor(FALSE)
+        )
+    );
+
+    private static final DeferredRegister<Item> ITEMS = DeferredRegister.create(Registries.ITEM, MODID);
+    public static final RegistryObject<BlockItem> OLD_LEAVES_ITEM = ITEMS.register(OLD_LEAVES_NAME, () -> new BlockItem(OLD_LEAVES.get(), new Item.Properties()));
+
+    public ModelRenderLayerTest(FMLJavaModLoadingContext context) {
+        super(context);
+        testItem(lookup -> new ItemStack(OLD_LEAVES_ITEM.get()));
+    }
+
+    @SubscribeEvent
+    public void runData(GatherDataEvent event) {
+        event.getGenerator().addProvider(event.includeClient(), new BlockStates(event));
+        event.getGenerator().addProvider(event.includeClient(), new ItemModels(event));
+    }
+
+    @GameTest(template = "forge:empty3x3x3")
+    public static void old_leaves_render_type(GameTestHelper helper) {
+        var manager = Minecraft.getInstance().getModelManager();
+
+        var state = OLD_LEAVES.get().defaultBlockState();
+        var model = manager.getBlockModelShaper().getBlockModel(state);
+        var random = helper.getLevel().random;
+        boolean originalRenderState = ItemBlockRenderTypes.isFancy();
+        helper.addCleanup(passed -> ItemBlockRenderTypes.setFancy(originalRenderState));
+
+        ItemBlockRenderTypes.setFancy(true);
+        var layer = model.getRenderTypes(state, random, ModelData.EMPTY);
+        helper.assertTrue(layer.contains(RenderType.cutoutMipped()), "Block model does not contain the correct render type for fancy graphics. Expected: cutout_mipped");
+
+        ItemBlockRenderTypes.setFancy(false);
+        layer = model.getRenderTypes(state, random, ModelData.EMPTY);
+        helper.assertTrue(layer.contains(RenderType.solid()), "Block model does not contain the correct render type for fast graphics. Expected: solid");
+
+        helper.succeed();
+    }
+
+    public static class BlockStates extends BlockStateProvider {
+        public BlockStates(GatherDataEvent event) {
+            super(event.getGenerator().getPackOutput(), MODID, event.getExistingFileHelper());
+        }
+
+        @Override
+        protected void registerStatesAndModels() {
+            this.simpleBlock(
+                OLD_LEAVES.get(),
+                this.models()
+                    .leaves(OLD_LEAVES_NAME, blockTexture(Blocks.OAK_LEAVES))
+                    // only define the single render type. this test checks if "solid" is implicitly the fast graphics render type
+                    .renderType("cutout_mipped")
+            );
+        }
+
+    }
+    private static class ItemModels extends ItemModelProvider {
+        public ItemModels(GatherDataEvent event) {
+            super(event.getGenerator().getPackOutput(), MODID, event.getExistingFileHelper());
+        }
+
+        @Override
+        protected void registerModels() {
+            this.withExistingParent(OLD_LEAVES_NAME, OLD_LEAVES.getKey().location().withPrefix(BLOCK_FOLDER + '/'));
+        }
+    }
+}