Model system fixes:

- Add "origin" key to determine what origin to use. This will default to the existing (broken) behaviour to avoid breaking changes.
- Fix interaction of transforms with variant transforms (transformation ordering).
- Fix OBJ loader ignoring "diffuseLighting" attribute from the json.
  This attribute will continue not being used if "ambientToFullbright" is on (default) to avoid breaking changes.
This commit is contained in:
David Quintana 2020-05-15 19:10:23 +02:00
parent 0f48e851a3
commit c23ea1e733
9 changed files with 286 additions and 24 deletions

View File

@ -89,37 +89,36 @@ public interface IForgeTransformationMatrix
}
/**
* convert transformation from assuming center-block system to corner-block system
* convert transformation from assuming center-block system to opposing-corner-block system
*/
default TransformationMatrix blockCenterToCorner()
{
TransformationMatrix transform = getTransformaion();
if (transform.isIdentity()) return TransformationMatrix.identity();
Matrix4f ret = transform.getMatrix();
Matrix4f tmp = Matrix4f.makeTranslate(.5f, .5f, .5f);
ret.multiplyBackward(tmp);
tmp.setIdentity();
tmp.setTranslation(-.5f, -.5f, -.5f);
ret.mul(tmp);
return new TransformationMatrix(ret);
return applyOrigin(new Vector3f(.5f, .5f, .5f));
}
/**
* convert transformation from assuming corner-block system to center-block system
* convert transformation from assuming opposing-corner-block system to center-block system
*/
default TransformationMatrix blockCornerToCenter()
{
return applyOrigin(new Vector3f(-.5f, -.5f, -.5f));
}
/**
* Apply this transformation to a different origin.
* Can be used for switching between coordinate systems.
* Parameter is relative to the current origin.
*/
default TransformationMatrix applyOrigin(Vector3f origin) {
TransformationMatrix transform = getTransformaion();
if (transform.isIdentity()) return TransformationMatrix.identity();
Matrix4f ret = transform.getMatrix();
Matrix4f tmp = Matrix4f.makeTranslate(-.5f, -.5f, -.5f);
Matrix4f tmp = Matrix4f.makeTranslate(origin.getX(), origin.getY(), origin.getZ());
ret.multiplyBackward(tmp);
tmp.setIdentity();
tmp.setTranslation(.5f, .5f, .5f);
tmp.setTranslation(-origin.getX(), -origin.getY(), -origin.getZ());
ret.mul(tmp);
return new TransformationMatrix(ret);
}
}

View File

@ -219,15 +219,15 @@ public class ModelLoaderRegistry
if(transform.has("rotation")) k--;
if(transform.has("scale")) k--;
if(transform.has("post-rotation")) k--;
if(transform.has("origin")) k--;
if(k > 0)
{
throw new JsonParseException("transform: allowed keys: 'thirdperson', 'firstperson', 'gui', 'head', 'matrix', 'translation', 'rotation', 'scale', 'post-rotation'");
throw new JsonParseException("transform: allowed keys: 'thirdperson', 'firstperson', 'gui', 'head', 'matrix', 'translation', 'rotation', 'scale', 'post-rotation', 'origin'");
}
TransformationMatrix base = TransformationMatrix.identity();
if(!transform.entrySet().isEmpty())
{
base = context.deserialize(transform, TransformationMatrix.class);
base = base.blockCenterToCorner();
}
IModelTransform state = new SimpleModelTransform(Maps.immutableEnumMap(transforms), base);
return Optional.of(state);
@ -249,7 +249,7 @@ public class ModelLoaderRegistry
IModelGeometry<?> customModel = blockModel.customData.getCustomGeometry();
IModelTransform customModelState = blockModel.customData.getCustomModelState();
if (customModelState != null)
modelTransform = new ModelTransformComposition(customModelState, modelTransform, modelTransform.isUvLock());
modelTransform = new ModelTransformComposition(modelTransform, customModelState, modelTransform.isUvLock());
if (customModel != null)
model = customModel.bake(blockModel.customData, modelBakery, spriteGetter, modelTransform, blockModel.getOverrides(modelBakery, otherModel, spriteGetter), modelLocation);

View File

@ -373,6 +373,10 @@ public class OBJModel implements IMultipartModelGeometry<OBJModel>
uv2 = new Vec2f((fakeLight << 4) / 32767.0f, (fakeLight << 4) / 32767.0f);
builder.setApplyDiffuseLighting(fakeLight == 0);
}
else
{
builder.setApplyDiffuseLighting(diffuseLighting);
}
boolean hasTransform = !transform.isIdentity();
// The incoming transform is referenced on the center of the block, but our coords are referenced on the corner

View File

@ -20,17 +20,13 @@
package net.minecraftforge.common.model;
import java.lang.reflect.Type;
import java.util.EnumMap;
import java.util.Map;
import com.google.gson.*;
import net.minecraft.client.renderer.*;
import net.minecraft.util.math.MathHelper;
import com.google.common.collect.Maps;
import net.minecraft.client.renderer.model.ItemTransformVec3f;
import net.minecraft.util.Direction;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@ -132,6 +128,10 @@ public final class TransformationHelper
public static class Deserializer implements JsonDeserializer<TransformationMatrix>
{
private static final Vector3f ORIGIN_CORNER = new Vector3f();
private static final Vector3f ORIGIN_OPPOSING_CORNER = new Vector3f(1f, 1f, 1f);
private static final Vector3f ORIGIN_CENTER = new Vector3f(.5f, .5f, .5f);
@Override
public TransformationMatrix deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
@ -170,6 +170,9 @@ public final class TransformationHelper
Quaternion leftRot = null;
Vector3f scale = null;
Quaternion rightRot = null;
// TODO: Default origin is opposing corner, due to a mistake.
// This should probably be replaced with center in future versions.
Vector3f origin = ORIGIN_OPPOSING_CORNER;
if (obj.has("translation"))
{
translation = new Vector3f(parseFloatArray(obj.get("translation"), 3, "Translation"));
@ -205,8 +208,59 @@ public final class TransformationHelper
rightRot = parseRotation(obj.get("post-rotation"));
obj.remove("post-rotation");
}
if (!obj.entrySet().isEmpty()) throw new JsonParseException("TRSR: can either have single 'matrix' key, or a combination of 'translation', 'rotation', 'scale', 'post-rotation'");
return new TransformationMatrix(translation, leftRot, scale, rightRot);
if (obj.has("origin"))
{
origin = parseOrigin(obj);
obj.remove("origin");
}
if (!obj.entrySet().isEmpty()) throw new JsonParseException("TRSR: can either have single 'matrix' key, or a combination of 'translation', 'rotation', 'scale', 'post-rotation', 'origin'");
TransformationMatrix matrix = new TransformationMatrix(translation, leftRot, scale, rightRot);
// Use a different origin if needed.
if (!ORIGIN_CENTER.equals(origin))
{
Vector3f originFromCenter = origin.copy();
originFromCenter.sub(ORIGIN_CENTER);
matrix = matrix.applyOrigin(originFromCenter);
}
return matrix;
}
private static Vector3f parseOrigin(JsonObject obj) {
Vector3f origin = null;
// Two types supported: string ("center", "corner") and array ([x, y, z])
JsonElement originElement = obj.get("origin");
if (originElement.isJsonArray())
{
origin = new Vector3f(parseFloatArray(originElement, 3, "Origin"));
}
else if (originElement.isJsonPrimitive())
{
String originString = originElement.getAsString();
if ("center".equals(originString))
{
origin = ORIGIN_CENTER;
}
else if ("corner".equals(originString))
{
origin = ORIGIN_CORNER;
}
else if ("opposing-corner".equals(originString))
{
// This option can be used to not break models that were written with this origin once the default is changed
origin = ORIGIN_OPPOSING_CORNER;
}
else
{
throw new JsonParseException("Origin: expected one of 'center', 'corner', 'opposing-corner'");
}
}
else
{
throw new JsonParseException("Origin: expected an array or one of 'center', 'corner', 'opposing-corner'");
}
return origin;
}
public static Matrix4f parseMatrix(JsonElement e)

View File

@ -0,0 +1,106 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.debug.client.model;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.BlockItem;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nullable;
@Mod(CompositeModelTest.MODID)
public class CompositeModelTest
{
public static final String MODID = "composite_model_test";
public static final DeferredRegister<Block> BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, MODID);
public static final DeferredRegister<Item> ITEMS = new DeferredRegister<>(ForgeRegistries.ITEMS, MODID);
public static RegistryObject<Block> composite_block = BLOCKS.register("composite_block", () ->
new Block(Block.Properties.create(Material.WOOD).hardnessAndResistance(10)) {
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{
builder.add(BlockStateProperties.HORIZONTAL_FACING);
}
@Nullable
@Override
public BlockState getStateForPlacement(BlockItemUseContext context)
{
return getDefaultState().with(
BlockStateProperties.HORIZONTAL_FACING, context.getPlacementHorizontalFacing()
);
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return VoxelShapes.or(
makeCuboidShape(5.6, 5.6, 5.6, 10.4, 10.4, 10.4),
makeCuboidShape(0, 0, 0, 4.8, 4.8, 4.8),
makeCuboidShape(11.2, 0, 0, 16, 4.8, 4.8),
makeCuboidShape(0, 0, 11.2, 4.8, 4.8, 16),
makeCuboidShape(11.2, 0, 11.2, 16, 4.8, 16),
makeCuboidShape(0, 11.2, 0, 4.8, 16, 4.8),
makeCuboidShape(11.2, 11.2, 0, 16, 16, 4.8),
makeCuboidShape(0, 11.2, 11.2, 4.8, 16, 16),
makeCuboidShape(11.2, 11.2, 11.2, 16, 16, 16)
);
}
}
);
public static RegistryObject<Item> composite_item = ITEMS.register("composite_block", () ->
new BlockItem(composite_block.get(), new Item.Properties().group(ItemGroup.MISC)) {
@Override
public boolean canEquip(ItemStack stack, EquipmentSlotType armorType, Entity entity)
{
return armorType == EquipmentSlotType.HEAD;
}
}
);
public CompositeModelTest()
{
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
BLOCKS.register(modEventBus);
ITEMS.register(modEventBus);
}
}

View File

@ -65,6 +65,8 @@ loaderVersion="[28,)"
modId="custom_plant_type_test"
[[mods]]
modId="chunk_data_event_save_null_world_test"
[[mods]]
modId="composite_model_test"
[[dependencies.global_loot_test]]
modId="forge"
mandatory=true

View File

@ -0,0 +1,8 @@
{
"variants": {
"facing=east": { "model": "composite_model_test:block/composite_block", "y": 90 },
"facing=west": { "model": "composite_model_test:block/composite_block", "y": 270 },
"facing=north": { "model": "composite_model_test:block/composite_block", "y": 0 },
"facing=south": { "model": "composite_model_test:block/composite_block", "y": 180 }
}
}

View File

@ -0,0 +1,86 @@
{
"loader": "forge:composite",
"_comment": "This should show a block with 9 different small blocks in it (8 in the corners, 1 in the center)",
"parts": {
"offset_from_opposing_corner": {
"_comment": "No rotation, using offset from opposing corner (default) origin",
"parent": "minecraft:block/dirt",
"transform": {
"scale": [0.3, 0.3, 0.3],
"translation": [0, -0.7, 0]
}
},
"offset_from_opposing_corner_with_post_rotation": {
"_comment": "Post-rotation and translation from opposing corner origin",
"parent": "minecraft:block/stone",
"transform": {
"post-rotation": [{"y": 180}],
"scale": [0.3, 0.3, 0.3],
"translation": [-1, -0.7, -0.3],
"origin": "opposing-corner"
}
},
"corner": {
"_comment": "Scale with corner origin",
"parent": "minecraft:block/obsidian",
"transform": {
"scale": [0.3, 0.3, 0.3],
"origin": "corner"
}
},
"rotation_and_offset_from_corner": {
"_comment": "Rotation over corner origin and translation",
"parent": "minecraft:block/diamond_block",
"transform": {
"rotation": [{"y": 270}],
"scale": [0.3, 0.3, 0.3],
"translation": [1, 0, 0],
"origin": "corner"
}
},
"offset_from_manual_corner": {
"_comment": "Translation from a manually-defined corner origin",
"parent": "minecraft:block/end_stone",
"transform": {
"scale": [0.3, 0.3, 0.3],
"translation": [0, 0.7, 0],
"origin": [0, 0, 0]
}
},
"offset_and_post_rotation_from_manual_center": {
"_comment": "Post-rotation and translation from a manually-defined center origin",
"parent": "minecraft:block/ice",
"transform": {
"scale": [0.3, 0.3, 0.3],
"translation": [-0.35, 0.35, 0.35],
"post-rotation": [{"y": 270}],
"origin": [0.5, 0.5, 0.5]
}
},
"offset_from_custom_origin": {
"_comment": "Translation from a manually-defined custom origin",
"parent": "minecraft:block/gold_ore",
"transform": {
"scale": [0.3, 0.3, 0.3],
"translation": [0, 0.7, 0],
"origin": [1, 0, 0]
}
},
"only_scale": {
"_comment": "No custom translations, rotations, or origins",
"parent": "minecraft:block/prismarine_bricks",
"transform": {
"scale": [0.3, 0.3, 0.3]
}
},
"upside_down_anvil": {
"_comment": "Rotation and no translation, over center origin",
"parent": "minecraft:block/anvil",
"transform": {
"rotation": [{"x": 180}],
"scale": [0.3, 0.3, 0.3],
"origin": "center"
}
}
}
}

View File

@ -0,0 +1,3 @@
{
"parent": "composite_model_test:block/composite_block"
}