diff --git a/rainbow/src/main/java/org/geysermc/rainbow/mapping/geometry/GeometryMapper.java b/rainbow/src/main/java/org/geysermc/rainbow/mapping/geometry/GeometryMapper.java index 2095477..5bed958 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/mapping/geometry/GeometryMapper.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/mapping/geometry/GeometryMapper.java @@ -41,7 +41,6 @@ public class GeometryMapper { SimpleUnbakedGeometry geometry = (SimpleUnbakedGeometry) top; for (BlockElement element : geometry.elements()) { - // TODO the origin here is wrong, some models seem to be mirrored weirdly in blockbench BedrockGeometry.Cube cube = mapBlockElement(element, textures).build(); bone.withCube(cube); min.min(cube.origin()); @@ -57,9 +56,25 @@ public class GeometryMapper { return builder.withBone(bone).build(); } + // After hours of painfully suffering and 40 test builds of Rainbow, I finally got the right formula together and somehow made this mess of a code + // work properly, or at least, I think it is. I physically jumped in the air and cheered as I saw my models convert properly. + // Now, make sure you are ready to witness my deformed creation private static BedrockGeometry.Cube.Builder mapBlockElement(BlockElement element, StitchedTextures textures) { - // The centre of the model is back by 8 in the X and Z direction on Java, so move the origin of the cube and the pivot like that - BedrockGeometry.Cube.Builder builder = BedrockGeometry.cube(element.from().sub(CENTRE_OFFSET, new Vector3f()), element.to().sub(element.from(), new Vector3f())); + // For some reason the X axis is inverted on bedrock (thanks Blockbench!!) + + // The centre of the model is back by 8 in the X and Z direction on bedrock, so start by move the from and to points of the cube, and later the pivot, like that + Vector3f from = element.from().sub(CENTRE_OFFSET, new Vector3f()); + Vector3f to = element.to().sub(CENTRE_OFFSET, new Vector3f()); + + // Bedrock wants the origin to be the smallest X/Y/Z of the cube, so we do a min here + Vector3f origin = from.min(to, new Vector3f()); + // Bedrock also wants a cube size instead of a second cube, so calculate the max and subtract the min/origin + Vector3fc size = from.max(to, new Vector3f()).sub(origin); + + // The X-axis is inverted for some reason on bedrock, so we have to do this (thanks Blockbench!!) + origin.x = -(origin.x + size.x()); + + BedrockGeometry.Cube.Builder builder = BedrockGeometry.cube(origin, size); for (Map.Entry faceEntry : element.faces().entrySet()) { Direction direction = faceEntry.getKey(); @@ -82,8 +97,8 @@ public class GeometryMapper { uvSize = new Vector2f(uvs.maxU() - uvs.minU(), uvs.maxV() - uvs.minV()); } - // If the texture was stitched (which it should have been, unless it doesn't exist), s UV values on Java are always in the [0;16] range, adjust the values properly to the texture size, - // and offset the UVs by the texture's starting UV + // UV values on Java are always in the [0;16] range, so if the texture was stitched (which it should have been, unless it doesn't exist), + // adjust the values properly to the texture size, and offset the UVs by the texture's starting UV textures.getSprite(face.texture()).ifPresent(sprite -> { float widthMultiplier = sprite.contents().width() / 16.0F; float heightMultiplier = sprite.contents().height() / 16.0F; @@ -97,12 +112,15 @@ public class GeometryMapper { BlockElementRotation rotation = element.rotation(); if (rotation != null) { // MC multiplies model origin by 0.0625 when loading rotation origin - builder.withPivot(rotation.origin().div(0.0625F, new Vector3f()).sub(CENTRE_OFFSET)); + // Same as above for inverting the X axis (thanks again Blockbench!!) + builder.withPivot(rotation.origin().div(0.0625F, new Vector3f()).sub(CENTRE_OFFSET).mul(-1.0F, 1.0F, 1.0F)); + + // Same as above but for some reason the Z axis too (thanks again, so much, Blockbench!!!) Vector3f bedrockRotation = switch (rotation.axis()) { - case X -> new Vector3f(rotation.angle(), 0.0F, 0.0F); + case X -> new Vector3f(-rotation.angle(), 0.0F, 0.0F); case Y -> new Vector3f(0.0F, rotation.angle(), 0.0F); - case Z -> new Vector3f(0.0F, 0.0F, rotation.angle()); + case Z -> new Vector3f(0.0F, 0.0F, -rotation.angle()); }; builder.withRotation(bedrockRotation); } diff --git a/rainbow/src/main/java/org/geysermc/rainbow/pack/geometry/BedrockGeometry.java b/rainbow/src/main/java/org/geysermc/rainbow/pack/geometry/BedrockGeometry.java index e63a430..244b502 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/pack/geometry/BedrockGeometry.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/pack/geometry/BedrockGeometry.java @@ -2,6 +2,7 @@ package org.geysermc.rainbow.pack.geometry; import com.mojang.math.Quadrant; import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.Direction; import org.geysermc.rainbow.CodecUtil; @@ -141,8 +142,8 @@ public record BedrockGeometry(BedrockVersion formatVersion, List defaultToZeroCodec(String name) { + return CodecUtil.VECTOR3F_CODEC.optionalFieldOf(name).xmap(optional -> optional.orElse(VECTOR3F_ZERO), + vector -> vector.length() == 0.0F ? Optional.empty() : Optional.of(vector)); + } }