From 26d0f7282fcbe3175f9e75006b64590da4ba94c4 Mon Sep 17 00:00:00 2001 From: Martijn van den Brand Date: Fri, 23 Aug 2024 02:26:44 +0200 Subject: [PATCH] Fix issues with `QuadBakingVertexConsumer` and Forge's OBJ loader (#10065) --- .../client/model/obj/ObjModel.java | 2 +- .../pipeline/QuadBakingVertexConsumer.java | 18 ++--- .../debug/client/ObjModelTest.java | 74 ++++++++++++++++++ .../assets/minecraft/atlases/blocks.json | 8 ++ .../assets/obj_model_test/models/pyramid.json | 8 ++ .../assets/obj_model_test/models/pyramid.mtl | 4 + .../assets/obj_model_test/models/pyramid.obj | 36 +++++++++ .../obj_model_test/textures/pyramid.png | Bin 0 -> 1108 bytes 8 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 src/test/java/net/minecraftforge/debug/client/ObjModelTest.java create mode 100644 src/test/resources/obj_model_test/assets/minecraft/atlases/blocks.json create mode 100644 src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.json create mode 100644 src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.mtl create mode 100644 src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.obj create mode 100644 src/test/resources/obj_model_test/assets/obj_model_test/textures/pyramid.png diff --git a/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java b/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java index 5901efb8ad..c2bf5db5b0 100644 --- a/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java +++ b/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java @@ -490,7 +490,7 @@ public class ObjModel extends SimpleUnbakedGeometry } } - return Pair.of(quadBaker.getQuad(), cull); + return Pair.of(quadBaker.build(), cull); } public CompositeRenderable bakeRenderable(IGeometryBakingContext configuration) diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java b/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java index 94bfaa7efc..174adab668 100644 --- a/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java +++ b/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java @@ -33,11 +33,12 @@ public class QuadBakingVertexConsumer implements VertexConsumer for (var element : DefaultVertexFormat.BLOCK.getElements()) map.put(element, DefaultVertexFormat.BLOCK.getOffset(i++) / 4); // Int offset }); - private static final int QUAD_DATA_SIZE = IQuadTransformer.STRIDE * 4; + private static final int MAX_VERTICES = 4; + private static final int QUAD_DATA_SIZE = IQuadTransformer.STRIDE * MAX_VERTICES; private final Consumer quadConsumer; - int vertexIndex = 0; + int vertexIndex = -1; private int[] quadData = new int[QUAD_DATA_SIZE]; private int tintIndex; @@ -54,7 +55,8 @@ public class QuadBakingVertexConsumer implements VertexConsumer @Override public VertexConsumer addVertex(float x, float y, float z) { - endVertex(); + if (vertexIndex++ == MAX_VERTICES) + build(); int offset = vertexIndex * IQuadTransformer.STRIDE + IQuadTransformer.POSITION; quadData[offset] = Float.floatToRawIntBits((float) x); @@ -124,16 +126,14 @@ public class QuadBakingVertexConsumer implements VertexConsumer return this; } - private void endVertex() + public BakedQuad build() { - if (vertexIndex != 4) { - ++vertexIndex; - return; - } + BakedQuad quad = new BakedQuad(quadData, tintIndex, direction, sprite, shade, hasAmbientOcclusion); // We have a full quad, pass it to the consumer and reset - quadConsumer.accept(new BakedQuad(quadData, tintIndex, direction, sprite, shade, hasAmbientOcclusion)); + quadConsumer.accept(quad); vertexIndex = 0; quadData = new int[QUAD_DATA_SIZE]; + return quad; } public void setTintIndex(int tintIndex) diff --git a/src/test/java/net/minecraftforge/debug/client/ObjModelTest.java b/src/test/java/net/minecraftforge/debug/client/ObjModelTest.java new file mode 100644 index 0000000000..4b479ce722 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/client/ObjModelTest.java @@ -0,0 +1,74 @@ +package net.minecraftforge.debug.client; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.client.model.data.ModelData; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; + +/** + * Tests loading and rendering an obj-model using the using Forge's {@link net.minecraftforge.client.model.obj.ObjLoader}. + * When enabled, this will render a pyramid loaded from an obj model at coordinates 0,0,0. + */ +@Mod(ObjModelTest.MODID) +public class ObjModelTest { + private static final boolean ENABLED = true; + + public static final String MODID = "obj_model_test"; + private static final PoseStack POSE_STACK = new PoseStack(); + private static final ModelResourceLocation PYRAMID_MODEL_LOCATION = new ModelResourceLocation(ResourceLocation.fromNamespaceAndPath(MODID, "pyramid"), ""); + private static BakedModel pyramidModel; + + public ObjModelTest() { + if (ENABLED) { + FMLJavaModLoadingContext.get().getModEventBus().addListener(ObjModelTest::registerObjModel); + FMLJavaModLoadingContext.get().getModEventBus().addListener(ObjModelTest::collectObjModel); + MinecraftForge.EVENT_BUS.addListener(ObjModelTest::renderModel); + } + } + + public static void registerObjModel(ModelEvent.RegisterAdditional e) { + e.register(PYRAMID_MODEL_LOCATION); + } + + public static void collectObjModel(ModelEvent.BakingCompleted e) { + pyramidModel = e.getModels().get(PYRAMID_MODEL_LOCATION); + } + + public static void renderModel(RenderLevelStageEvent e) { + if (e.getStage() == RenderLevelStageEvent.Stage.AFTER_SOLID_BLOCKS) { + POSE_STACK.setIdentity(); + Vec3 camera = e.getCamera().getPosition(); + //noinspection removal + POSE_STACK.mulPose(e.getPoseStack()); + POSE_STACK.translate(0.5 - camera.x, 0.5 - camera.y, 0.5 - camera.z); + MultiBufferSource.BufferSource bufferSource = Minecraft.getInstance().renderBuffers().bufferSource(); + // Render the obj model + Minecraft.getInstance().getBlockRenderer().getModelRenderer().renderModel( + POSE_STACK.last(), + bufferSource.getBuffer(RenderType.solid()), + null, + pyramidModel, + 1, + 1, + 1, + LightTexture.FULL_BRIGHT, + OverlayTexture.NO_OVERLAY, + ModelData.EMPTY, + RenderType.solid() + ); + bufferSource.endBatch(); + } + } +} diff --git a/src/test/resources/obj_model_test/assets/minecraft/atlases/blocks.json b/src/test/resources/obj_model_test/assets/minecraft/atlases/blocks.json new file mode 100644 index 0000000000..7e6f3ae7a8 --- /dev/null +++ b/src/test/resources/obj_model_test/assets/minecraft/atlases/blocks.json @@ -0,0 +1,8 @@ +{ + "sources": [ + { + "type": "single", + "resource": "obj_model_test:pyramid" + } + ] +} diff --git a/src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.json b/src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.json new file mode 100644 index 0000000000..b90ab42ede --- /dev/null +++ b/src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.json @@ -0,0 +1,8 @@ +{ + "loader": "forge:obj", + "model": "obj_model_test:models/pyramid.obj", + "flip-v": true, + "detectCullableFaces": false, + "diffuseLighting": false, + "ambientToFullbright": true +} \ No newline at end of file diff --git a/src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.mtl b/src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.mtl new file mode 100644 index 0000000000..862e652bca --- /dev/null +++ b/src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.mtl @@ -0,0 +1,4 @@ +# Made in Blockbench 4.9.4 +newmtl m_d61f9499-1bf7-4e99-8524-c1ff74261694 +map_Kd obj_model_test:pyramid +newmtl none \ No newline at end of file diff --git a/src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.obj b/src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.obj new file mode 100644 index 0000000000..cda9a03cd6 --- /dev/null +++ b/src/test/resources/obj_model_test/assets/obj_model_test/models/pyramid.obj @@ -0,0 +1,36 @@ +# Made in Blockbench 4.9.4 +mtllib pyramid.mtl + +o pyramid +v 0 1 0 +v 0.5 0 0.5 +v 0.5 0 -0.5 +v -0.5 0 0.5 +v -0.5 0 -0.5 +vt 0.6875 0.25 +vt 0.6875 0 +vt 0.4375 0 +vt 0.4375 0.25 +vt 0.3780786804403148 0.5791233118566227 +vt 0.6062963195596852 0.6811855928167345 +vt 0.6062963195596851 0.375 +vt 0.003078680440314799 0.2041233118566227 +vt 0.23129631955968522 0.3061855928167345 +vt 0.23129631955968505 0 +vt 0.19057868044031478 0.3916233118566227 +vt 0.4187963195596852 0.4936855928167345 +vt 0.41879631955968505 0.1875 +vt 0.003078680440314799 0.6416233118566227 +vt 0.23129631955968522 0.7436855928167345 +vt 0.23129631955968505 0.4375 +vn 0 -1 0 +vn 0.8944271909999161 0.44721359549995804 0 +vn 0 0.44721359549995804 0.8944271909999161 +vn 0 0.44721359549995804 -0.8944271909999161 +vn -0.8944271909999161 0.44721359549995804 0 +usemtl m_d61f9499-1bf7-4e99-8524-c1ff74261694 +f 3/1/1 2/2/1 4/3/1 5/4/1 +f 2/5/2 3/6/2 1/7/2 +f 4/8/3 2/9/3 1/10/3 +f 3/11/4 5/12/4 1/13/4 +f 5/14/5 4/15/5 1/16/5 \ No newline at end of file diff --git a/src/test/resources/obj_model_test/assets/obj_model_test/textures/pyramid.png b/src/test/resources/obj_model_test/assets/obj_model_test/textures/pyramid.png new file mode 100644 index 0000000000000000000000000000000000000000..c5d8a446c1c188308e6d0d332d790b0b5bcee1c6 GIT binary patch literal 1108 zcmV-a1grarP)8Qv=T^8omh&5f+)B`dbj~)Dy|TyasXF^D^O8#gV1vYiYO>jB!}9TLS+gx z#@^lW?u=*N`TGB=AVqS}^S;kc?Cc&WAy2oLtIdBufA#r5;&tD>|F|0QZNYr|@=4_X z>8g=@v1g~Rl~PLmdH5;$vg-6?D*Afb!{a>4>)HrD0DALv_(;p4#ETGqx`H(To1cfE z4M6zm^WFe#eqMq!0O9AuTLZB9dGgu-grA?i8-UHvo0kS4{CrtAK>Iy?!q1!2C4kV& zF?s;F)|biZ3_$qh8EgPHzigu#fbh#@YydXD4m%rw@XOa}05-oay$wM4^;kCmn_s7` z1|atGm5WokCOg-{8SvO0>anMrW18Goy7hzvLbq8NCkl8cj?A5H~^_M zg6rm|et&*!PQM1mY6NQEKkEUIZUnCRVR?BYsPBm%K8J$v!`XWPOwampZHD%H`h*`= z(6@qJ&kBStC)fbko)x&($07P*(9qMt2w$Gq0GQ4SY<^rKPYD}B`0+&hdjK{+4N)6_ z@Z%G205(4@Q5t~o(;?OXY<`+V8-VcB6TAUR+59*2>#ffyzE3|C@plFy4Ul{I+WE<` zIzKs%{bP8Q{e1zU>CG=Kcuiyge$AKbuXAjJQo~mg1JJ%l@8V{$%3%mf-+V2~B_NkZ zC_Q`?V*pZbgjzOVOX3iiS|ijFzLFe(#ca0qd-T!O)qzT=5o+6fO|$_fFJCC7lv>{1 z@BF@4jZjNH;>Qo3Dv9z}WCjHXA|nITW>quR;!h?dF@9p7rC}4DI*y zYYtz9Zh(EmAL4pes6F&e-Uqrn3T@ zznj;;2Z$B^5W+Xxy8&Wvz6qN@j+X{VEqsmehgmm3`#t^C!e{gCI9&o#3%!l-#~VEW zsb1?fHs6ia86eg0HNv+y*Z^#P*+w-$s^M#d@6Ol&sc$~~*m()aCHx;W26j3F zklW^W?$MiHuNZ>ydK(~@@J(oh@zw*7+vc0l2zIs_AouW1XauvSl+8Dx5q4`-!Qq?G z2>&HHN5Qo#RfiyxntOtNILRq}L5!Cm@4~8NS zdk=u=T23?MA?RDdoE6d+Yydbb=* literal 0 HcmV?d00001