GeckoLib

GeckoLib

146M Downloads

[1.20.1] Accessing certain bones during render break the UV mapping

baileyholl opened this issue ยท 6 comments

commented

image

Easy to reproduce, simply fetching a bone in any render method will break UV mappings and causes all sorts of whacky behavior.

@Override
    public void actuallyRender(PoseStack stack, EnchantingApparatusTile tile, BakedGeoModel model, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
            CoreGeoBone frame = model.getBone("frame_all").orElse(null);
super.....
}

Commenting out that line will fix it back to proper UV mappings.

This happens in render recursively, preRender, actually render, and more.

image

Note: this has a different behavior on which bone you fetch. It seems like the higher up in the heirarchy, the more breaking? Sometimes if I pick a bone that has children, it just simply doesnt render other parts of the model.

commented

You're telling the game to render an ItemStack
Which has the game bind the items atlas to the renderbuffer

You're then not rebinding the entity texture to the renderbuffer, so it's then rendering as if it's using your item's texture

You need to re-bind your buffer afterwards if you're changing it

If it worked in Geckolib3, it was either a coincidence, or a miracle of a combination of bugs that ended up working
This is absolutely how rendering works in mc - if you rebind the buffer, it's gone until you rebind it back

commented

There's definitely more to this than is being shown

getBone literally just does a loop through a list and checks for string matches
There's absolutely nothing involved in it that would change anything at all related to anything, let alone breaking UVs

Show the rest of your code

commented

Oops sorry, got this one mixed up.

For context, in geckolib 3, we used renderRecursively to translate the posestack to the bone to render an itemstack at the location.

In geckolib 4, rendering an itemstack in render recursively will break the mappings/model depending on which bone you pick. In actuallyRender, it just breaks using the itemrenderer at all.

    @Override
    public void actuallyRender(PoseStack stack, EnchantingApparatusTile tile, BakedGeoModel model, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
         double x = tile.getBlockPos().getX();
         double y = tile.getBlockPos().getY();
         double z = tile.getBlockPos().getZ();
         if (tile.renderEntity == null || !ItemStack.matches(tile.renderEntity.getItem(), tile.getStack())) {
             tile.renderEntity = new ItemEntity(tile.getLevel(), x, y, z, tile.getStack());
         }
         stack.pushPose();
         ItemStack itemstack = tile.renderEntity.getItem();
         Minecraft.getInstance().getItemRenderer().renderStatic(itemstack, ItemDisplayContext.GROUND, packedLight, OverlayTexture.NO_OVERLAY, stack, bufferSource, tile.getLevel(), (int) tile.getBlockPos().asLong());
         stack.popPose();
        super.actuallyRender(stack, tile, model, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha);
    }

What breaks is different on which bone you use in renderRecursively, but you are right, the bone has nothing to do with this particular error - it was removing the render entirely when I marked it as null for testing ๐Ÿ™ˆ

commented

This is an example using render recursively, which worked in geckolib 3. This method is unfortunately the only one that correctly translates items to the exact position of the bone.
image

public class StarbuncleRenderer extends GeoEntityRenderer<Starbuncle> {

    public StarbuncleRenderer(EntityRendererProvider.Context manager) {
        super(manager, new StarbuncleModel());
    }


    @Override
    public void renderFinal(PoseStack poseStack, Starbuncle animatable, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
        super.renderFinal(poseStack, animatable, model, bufferSource, buffer, partialTick, packedLight, packedOverlay, red, green, blue, alpha);
    }

    @Override
    public void renderRecursively(PoseStack stack, Starbuncle animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
        if (bone.getName().equals("item")) {
            stack.pushPose();
            RenderUtils.translateToPivotPoint(stack, bone);
            stack.translate(0, -0.10, 0);
            stack.scale(0.75f, 0.75f, 0.75f);
            ItemStack itemstack = animatable.getHeldStack();
            if (animatable.dynamicBehavior != null) {
                itemstack = animatable.dynamicBehavior.getStackForRender();
            }
            if(!itemstack.isEmpty()) {
                Minecraft.getInstance().getItemRenderer().renderStatic(itemstack, ItemDisplayContext.GROUND, packedLight, OverlayTexture.NO_OVERLAY, stack, bufferSource, animatable.level, (int) animatable.getOnPos().asLong());
            }
            stack.popPose();
        }

        if (animatable.getCosmeticItem().getItem() instanceof ICosmeticItem cosmetic && cosmetic.getBone().equals(bone.getName())) {
            CosmeticRenderUtil.renderCosmetic(bone, stack, bufferSource, animatable, packedLight);
        }
        super.renderRecursively(stack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha);
    }

    @Override
    public ResourceLocation getTextureLocation(Starbuncle entity) {
        return entity.getTexture(entity);
    }

    @Override
    public RenderType getRenderType(Starbuncle animatable, ResourceLocation texture, @org.jetbrains.annotations.Nullable MultiBufferSource bufferSource, float partialTick) {
        return RenderType.entityCutoutNoCull(texture);
    }
}
public class StarbuncleModel extends GeoModel<Starbuncle> {

    @Override
    public void setCustomAnimations(Starbuncle entity, long uniqueID, @Nullable AnimationState customPredicate) {
        super.setCustomAnimations(entity, uniqueID, customPredicate);
        if (entity.partyCarby)
            return;
        if (customPredicate == null)
            return;
        this.getBone("basket").get().setHidden(!entity.isTamed());

        CoreGeoBone head = this.getAnimationProcessor().getBone("head");
        EntityModelData extraData = (EntityModelData) customPredicate.getExtraData().get(DataTickets.ENTITY_MODEL_DATA);
        head.setRotX(extraData.headPitch() * 0.017453292F);
        head.setRotY(extraData.netHeadYaw() * 0.017453292F);
    }

    @Override
    public ResourceLocation getModelResource(Starbuncle carbuncle) {
        return new ResourceLocation(ArsNouveau.MODID, "geo/starbuncle.geo.json");
    }

    @Override
    public ResourceLocation getTextureResource(Starbuncle carbuncle) {
        return carbuncle.getTexture(carbuncle);
    }

    @Override
    public ResourceLocation getAnimationResource(Starbuncle carbuncle) {
        return new ResourceLocation(ArsNouveau.MODID, "animations/starbuncle_animations.json");
    }
}
commented

Ah got it, making a new buffer fixes it, rebinding texture does not. Thanks!

commented

My mistake - poor wording ;)