mirror of
https://github.com/GeyserMC/Rainbow.git
synced 2025-12-19 14:59:16 +00:00
Improve 3D model conversion (close to perfection?)
This commit is contained in:
@@ -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<Direction, BlockElementFace> 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);
|
||||
}
|
||||
|
||||
@@ -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<GeometryDefinit
|
||||
Codec.STRING.fieldOf("name").forGetter(Bone::name),
|
||||
Codec.STRING.optionalFieldOf("parent").forGetter(Bone::parent),
|
||||
Codec.STRING.optionalFieldOf("binding").forGetter(Bone::binding),
|
||||
CodecUtil.VECTOR3F_CODEC.optionalFieldOf("pivot", VECTOR3F_ZERO).forGetter(Bone::pivot),
|
||||
CodecUtil.VECTOR3F_CODEC.optionalFieldOf("rotation", VECTOR3F_ZERO).forGetter(Bone::rotation),
|
||||
defaultToZeroCodec("pivot").forGetter(Bone::pivot),
|
||||
defaultToZeroCodec("rotation").forGetter(Bone::rotation),
|
||||
Codec.BOOL.optionalFieldOf("mirror", false).forGetter(Bone::mirror),
|
||||
Codec.FLOAT.optionalFieldOf("inflate", 0.0F).forGetter(Bone::inflate),
|
||||
Cube.CODEC.listOf().optionalFieldOf("cubes", List.of()).forGetter(Bone::cubes)
|
||||
@@ -216,8 +217,8 @@ public record BedrockGeometry(BedrockVersion formatVersion, List<GeometryDefinit
|
||||
instance.group(
|
||||
CodecUtil.VECTOR3F_CODEC.fieldOf("origin").forGetter(Cube::origin),
|
||||
CodecUtil.VECTOR3F_CODEC.fieldOf("size").forGetter(Cube::size),
|
||||
CodecUtil.VECTOR3F_CODEC.optionalFieldOf("rotation", VECTOR3F_ZERO).forGetter(Cube::rotation),
|
||||
CodecUtil.VECTOR3F_CODEC.optionalFieldOf("pivot", VECTOR3F_ZERO).forGetter(Cube::pivot),
|
||||
defaultToZeroCodec("rotation").forGetter(Cube::rotation),
|
||||
defaultToZeroCodec("pivot").forGetter(Cube::pivot),
|
||||
Codec.FLOAT.optionalFieldOf("inflate", 0.0F).forGetter(Cube::inflate),
|
||||
Codec.BOOL.optionalFieldOf("mirror", false).forGetter(Cube::mirror),
|
||||
FACE_MAP_CODEC.optionalFieldOf("uv", Map.of()).forGetter(Cube::faces)
|
||||
@@ -286,4 +287,9 @@ public record BedrockGeometry(BedrockVersion formatVersion, List<GeometryDefinit
|
||||
).apply(instance, Face::new)
|
||||
);
|
||||
}
|
||||
|
||||
private static MapCodec<Vector3fc> 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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user