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:
parent
0f48e851a3
commit
c23ea1e733
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"parent": "composite_model_test:block/composite_block"
|
||||
}
|
Loading…
Reference in New Issue