From 434c1ec4f89d04e364787424705b47fe07f800b0 Mon Sep 17 00:00:00 2001 From: Dennis C Date: Wed, 22 Mar 2023 11:09:41 +0100 Subject: [PATCH] Fix JSON model root transforms (#9410) --- .../client/model/CompositeModel.java | 3 +- .../client/model/ElementsModel.java | 14 ++++----- .../client/model/ItemLayerModel.java | 2 +- .../model/geometry/UnbakedGeometryHelper.java | 30 +++++++++++++++++++ .../common/util/TransformationHelper.java | 11 ++----- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/main/java/net/minecraftforge/client/model/CompositeModel.java b/src/main/java/net/minecraftforge/client/model/CompositeModel.java index 5063a38ecb..7438f51fc5 100644 --- a/src/main/java/net/minecraftforge/client/model/CompositeModel.java +++ b/src/main/java/net/minecraftforge/client/model/CompositeModel.java @@ -45,6 +45,7 @@ import net.minecraftforge.client.model.data.ModelProperty; import net.minecraftforge.client.model.geometry.IGeometryBakingContext; import net.minecraftforge.client.model.geometry.IGeometryLoader; import net.minecraftforge.client.model.geometry.IUnbakedGeometry; +import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper; import net.minecraftforge.common.util.ConcatenatedListView; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -88,7 +89,7 @@ public class CompositeModel implements IUnbakedGeometry var rootTransform = context.getRootTransform(); if (!rootTransform.isIdentity()) - modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked()); + modelState = UnbakedGeometryHelper.composeRootTransformIntoModelState(modelState, rootTransform); var bakedPartsBuilder = ImmutableMap.builder(); for (var entry : children.entrySet()) diff --git a/src/main/java/net/minecraftforge/client/model/ElementsModel.java b/src/main/java/net/minecraftforge/client/model/ElementsModel.java index 3eacfee0cd..3401feec26 100644 --- a/src/main/java/net/minecraftforge/client/model/ElementsModel.java +++ b/src/main/java/net/minecraftforge/client/model/ElementsModel.java @@ -5,32 +5,26 @@ package net.minecraftforge.client.model; -import com.google.common.collect.Sets; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import com.mojang.datafixers.util.Pair; import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import java.util.Set; import java.util.function.Function; import net.minecraft.client.renderer.block.model.BlockElement; -import net.minecraft.client.renderer.block.model.BlockElementFace; import net.minecraft.client.renderer.block.model.BlockModel; -import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.GsonHelper; import net.minecraftforge.client.model.geometry.IGeometryBakingContext; import net.minecraftforge.client.model.geometry.IGeometryLoader; import net.minecraftforge.client.model.geometry.SimpleUnbakedGeometry; +import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -64,8 +58,10 @@ public class ElementsModel extends SimpleUnbakedGeometry // If there is a root transform, undo the ModelState transform, apply it, then re-apply the ModelState transform. // This is necessary because of things like UV locking, which should only respond to the ModelState, and as such // that is the only transform that should be applied during face bake. - var postTransform = context.getRootTransform().isIdentity() ? QuadTransformers.empty() : - QuadTransformers.applying(modelState.getRotation().compose(context.getRootTransform()).compose(modelState.getRotation().inverse())); + var postTransform = QuadTransformers.empty(); + var rootTransform = context.getRootTransform(); + if (!rootTransform.isIdentity()) + postTransform = UnbakedGeometryHelper.applyRootTransform(modelState, rootTransform); for (BlockElement element : elements) { diff --git a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java index 4216a472c3..29740b73d7 100644 --- a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java +++ b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java @@ -72,7 +72,7 @@ public class ItemLayerModel implements IUnbakedGeometry ); var rootTransform = context.getRootTransform(); if (!rootTransform.isIdentity()) - modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked()); + modelState = UnbakedGeometryHelper.composeRootTransformIntoModelState(modelState, rootTransform); var normalRenderTypes = new RenderTypeGroup(RenderType.translucent(), ForgeRenderTypes.ITEM_UNSORTED_TRANSLUCENT.get()); CompositeModel.Baked.Builder builder = CompositeModel.Baked.builder(context, particle, overrides, context.getTransforms()); diff --git a/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java b/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java index a82682d23f..862cb9d060 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java @@ -29,6 +29,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraftforge.client.model.ElementsModel; import net.minecraftforge.client.model.ForgeFaceData; import net.minecraftforge.client.model.IModelBuilder; +import net.minecraftforge.client.model.IQuadTransformer; +import net.minecraftforge.client.model.QuadTransformers; import net.minecraftforge.client.model.SimpleModelState; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -268,4 +270,32 @@ public class UnbakedGeometryHelper { return FACE_BAKERY.bakeQuad(element.from, element.to, face, sprite, direction, state, element.rotation, element.shade, modelLocation); } + + /** + * Create an {@link IQuadTransformer} to apply a {@link Transformation} that undoes the {@link ModelState} + * transform (blockstate transform), applies the given root transform and then re-applies the + * blockstate transform. + * + * @return an {@code IQuadTransformer} that applies the root transform to a baked quad that already has the + * transformation of the given {@code ModelState} applied to it + */ + public static IQuadTransformer applyRootTransform(ModelState modelState, Transformation rootTransform) + { + // Move the origin of the ModelState transform and its inverse from the negative corner to the block center + // to replicate the way the ModelState transform is applied in the FaceBakery by moving the vertices such that + // the negative corner acts as the block center + Transformation transform = modelState.getRotation().applyOrigin(new Vector3f(.5F, .5F, .5F)); + return QuadTransformers.applying(transform.compose(rootTransform).compose(transform.inverse())); + } + + /** + * {@return a {@link ModelState} that combines the existing model state and the {@linkplain Transformation root transform}} + */ + public static ModelState composeRootTransformIntoModelState(ModelState modelState, Transformation rootTransform) + { + // Move the origin of the root transform as if the negative corner were the block center to match the way the + // ModelState transform is applied in the FaceBakery by moving the vertices to be centered on that corner + rootTransform = rootTransform.applyOrigin(new Vector3f(-.5F, -.5F, -.5F)); + return new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked()); + } } \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/common/util/TransformationHelper.java b/src/main/java/net/minecraftforge/common/util/TransformationHelper.java index a2b162fc65..7c2607f395 100644 --- a/src/main/java/net/minecraftforge/common/util/TransformationHelper.java +++ b/src/main/java/net/minecraftforge/common/util/TransformationHelper.java @@ -212,16 +212,9 @@ public final class TransformationHelper elements.remove("origin"); } if (!elements.isEmpty()) throw new JsonParseException("TRSR: can either have single 'matrix' key, or a combination of 'translation', 'rotation' OR 'left_rotation', 'scale', 'post-rotation' (legacy) OR 'right_rotation', 'origin'. Found: " + String.join(", ", elements)); - Transformation matrix = new Transformation(translation, leftRot, scale, rightRot); - // Use a different origin if needed. - if (!TransformOrigin.CENTER.getVector().equals(origin)) - { - Vector3f originFromCenter = new Vector3f(origin); - originFromCenter.sub(TransformOrigin.CENTER.getVector()); - matrix = matrix.applyOrigin(originFromCenter); - } - return matrix; + Transformation matrix = new Transformation(translation, leftRot, scale, rightRot); + return matrix.applyOrigin(new Vector3f(origin)); } private static Vector3f parseOrigin(JsonObject obj) {