使用1.15后的新渲染代码翻转玩家模型后手持物品渲染异常&无法调整光照角度

LucunJi


版本信息
系统:Win10 x64
JDK: jdk1.8.0_251 x64
IDE:IntelliJ IDEA
IDE 版本: 2019.3 x64
Fabric 版本: 0.9.1-build205
Minecraft 版本: 1.15.2,1.16.1,1.16.2
Mapping 文件版本: yarn:1.16.1+build.21:v2

出错图


错误情况简述
这个 mod 是用来在屏幕上渲染一个玩家的模型,用来充当 Live2D 的效果。
直接借用了玩家背包里那个小人的渲染代码。
Mixin的注入位置,无论版本都是 net.minecraft.client.render.GameRenderer@Inject(method = "render(FJZ)V", at = @At(value = "RETURN"))

在 1.14.4 的时候通过 GlStateManager.scaled(size * (mirror ? 1 : -1), size, size);来调节镜像和大小,并且通过这三行代码来调整光照角度:

GlStateManager.rotated(lightDegree, 0.0F, 1.0F, 0.0F);
DiffuseLighting.enable();
GlStateManager.rotated(-lightDegree, 0.0F, 1.0F, 0.0F);

到了 1.15 及后续版本,通过 matrixStack.scale((float) size * (mirror ? 1 : -1), (float) size, (float) size); 调整镜像和大小的时候,一旦 mirror 是 false,scale的第一个参数是负数,玩家本身能较好地翻转,但是手持物品渲染异常(图中的斧子、信标)。
而且无法通过先旋转,打开 DiffuseLighting,再反向旋转的方式修改光照角度。

相关代码
完整的代码可以在 GitHub - LucunJi/ExtraPlayerRenderer at 1.14.4-fabric (没有这个问题的1.14.4)和 GitHub - LucunJi/ExtraPlayerRenderer at 1.16.1-fabric (1.15后开发进度最靠前的版本)看到。

在 1.14.4 的时候的代码:
PlayerHUD.java

public class PlayerHUD extends DrawableHelper {
    private static final MinecraftClient client  = MinecraftClient.getInstance();

    public void render(int ticks) {
        int scaledWidth = client.window.getScaledWidth();
        int scaledHeight = client.window.getScaledHeight();

        PlayerEntity player;
        if (Configs.SPECTATOR_AUTO_SWITCH.getBooleanValue()) {
            Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity();
            if (cameraEntity instanceof PlayerEntity && !cameraEntity.isSpectator()) {
                player = (PlayerEntity)MinecraftClient.getInstance().getCameraEntity();
            } else {
                return;
            }
        } else {
            player = client.world.getPlayers().stream().filter(p -> p.getName().getString().equals(Configs.PLAYER_NAME.getStringValue())).findFirst().orElse(client.player);
        }

        double posX = Configs.OFFSET_X.getDoubleValue() * scaledWidth;
        double posY = Configs.OFFSET_Y.getDoubleValue() * scaledHeight;
        double size = Configs.SIZE.getDoubleValue() * scaledHeight;
        boolean mirror = Configs.MIRROR.getBooleanValue();

        if (player.isInSneakingPose()) posY += Configs.SNEAKING_OFFSET_Y.getDoubleValue();
        if (player.isFallFlying()) posY += Configs.ELYTRA_OFFSET_Y.getDoubleValue();

        double lightDegree = Configs.LIGHT_DEGREE.getDoubleValue();

        GlStateManager.enableColorMaterial();
        {
            GlStateManager.pushMatrix();
            GlStateManager.translated(posX, posY, 50.0F);
            GlStateManager.scaled(size * (mirror ? 1 : -1), size, size);
            GlStateManager.rotated(180.0F, 0.0F, 0.0F, 1.0F);

            float bodyYaw = player.field_6283;
            float yaw = player.yaw;
            float pitch = player.pitch;
            float prevHeadYaw = player.prevHeadYaw;
            float headYaw = player.headYaw;
            float handSwingProgress = player.handSwingProgress;
            float horizontalSpeed = player.horizontalSpeed;
            int hurtTime = player.hurtTime;

            GlStateManager.rotated(lightDegree, 0.0F, 1.0F, 0.0F);
            DiffuseLighting.enable();
            GlStateManager.rotated(-lightDegree, 0.0F, 1.0F, 0.0F);

            player.field_6283 = (float) MathHelper.clamp(player.field_6283, Configs.BODY_YAW_MIN.getDoubleValue(), Configs.BODY_YAW_MAX.getDoubleValue());
            player.headYaw = (float) MathHelper.clamp(player.headYaw, Configs.HEAD_YAW_MIN.getDoubleValue(), Configs.HEAD_YAW_MAX.getDoubleValue());
            player.pitch = (float) (MathHelper.clamp(player.pitch, Configs.PITCH_MIN.getDoubleValue(), Configs.PITCH_MAX.getDoubleValue()) + Configs.PITCH_OFFSET.getDoubleValue());
            if (Configs.SWING_HANDS.getBooleanValue()) {
                player.handSwingProgress = player.getHandSwingProgress(client.getTickDelta());
            } else {
                player.handSwingProgress = 0;
            }

            if (!Configs.HURT_FLASH.getBooleanValue()) {
                player.hurtTime = 0;
            }

            GlStateManager.rotatef(((float) Configs.ROTATION_X.getDoubleValue()), 1.0F, 0.0F, 0.0F);
            GlStateManager.rotatef(((float) Configs.ROTATION_Y.getDoubleValue()), 0.0F, 1.0F, 0.0F);
            GlStateManager.rotatef(((float) Configs.ROTATION_Z.getDoubleValue()), 0.0F, 0.0F, 1.0F);

            GlStateManager.translated(0.0F, 0.0F, 0.0F);
            EntityRenderDispatcher entityRenderDispatcher = MinecraftClient.getInstance().getEntityRenderManager();
            entityRenderDispatcher.method_3945(180.0F);
            entityRenderDispatcher.setRenderShadows(false);
            entityRenderDispatcher.render(player, 0.0D, 0.0D, 0.0D, 0.0F, 1.0f, true);
            entityRenderDispatcher.setRenderShadows(true);

            player.field_6283 = bodyYaw;
            player.yaw = yaw;
            player.pitch = pitch;
            player.prevHeadYaw = prevHeadYaw;
            player.headYaw = headYaw;
            player.handSwingProgress = handSwingProgress;
            player.hurtTime = hurtTime;
            player.horizontalSpeed = horizontalSpeed;
        }

        GlStateManager.popMatrix();
        DiffuseLighting.disable();
        GlStateManager.disableRescaleNormal();
        GlStateManager.activeTexture(GLX.GL_TEXTURE1);
        GlStateManager.disableTexture();
        GlStateManager.activeTexture(GLX.GL_TEXTURE0);
    }
}

1.15以后的代码(这里是1.16.1,1.15.2/1.16.2也一样)
PlayerHUD.java

public class PlayerHUD extends DrawableHelper {
    private static final MinecraftClient client = MinecraftClient.getInstance();

    public void render(int ticks) {
        PlayerEntity player;
        if (Configs.SPECTATOR_AUTO_SWITCH.getBooleanValue()) {
            Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity();
            if (cameraEntity instanceof PlayerEntity && !cameraEntity.isSpectator()) {
                player = (PlayerEntity)MinecraftClient.getInstance().getCameraEntity();
            } else {
                return;
            }
        } else {
            player = client.world.getPlayers().stream().filter(p -> p.getName().getString().equals(Configs.PLAYER_NAME.getStringValue())).findFirst().orElse(client.player);
        }

        int scaledWidth = client.getWindow().getScaledWidth();
        int scaledHeight = client.getWindow().getScaledHeight();
        double posX = Configs.OFFSET_X.getDoubleValue() * scaledWidth;
        double posY = Configs.OFFSET_Y.getDoubleValue() * scaledHeight;
        if (player.isInSneakingPose()) posY += Configs.SNEAKING_OFFSET_Y.getDoubleValue();
        if (player.isFallFlying()) posY += Configs.ELYTRA_OFFSET_Y.getDoubleValue();
        double size = Configs.SIZE.getDoubleValue() * scaledHeight;
        boolean mirror = Configs.MIRROR.getBooleanValue();

        RenderSystem.pushMatrix();
        {
            RenderSystem.translatef((float) posX, (float) posY, 1050.0F);
            RenderSystem.scalef(1.0F, 1.0F, -1.0F);
            MatrixStack matrixStack = new MatrixStack();
            matrixStack.translate(0.0D, 0.0D, 2000.0D);
            matrixStack.scale((float) size * (mirror ? 1 : -1), (float) size, (float) size);
            Quaternion quaternion = Vector3f.POSITIVE_Z.getDegreesQuaternion(180.0F);
            Quaternion quaternion2 = Vector3f.POSITIVE_X.getDegreesQuaternion(0);
            quaternion.hamiltonProduct(quaternion2);
            matrixStack.multiply(quaternion);

            matrixStack.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion((float)Configs.ROTATION_X.getDoubleValue()));
            matrixStack.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion((float)Configs.ROTATION_Y.getDoubleValue()));
            matrixStack.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion((float)Configs.ROTATION_Z.getDoubleValue()));

            float bodyYaw = player.bodyYaw;
            float yaw = player.yaw;
            float pitch = player.pitch;
            float prevHeadYaw = player.prevHeadYaw;
            float headYaw = player.headYaw;
            float handSwingProgress = player.handSwingProgress;
            int hurtTime = player.hurtTime;
            EntityRenderDispatcher entityRenderDispatcher = MinecraftClient.getInstance().getEntityRenderManager();

            player.bodyYaw = 180 - (float) MathHelper.clamp(player.bodyYaw, Configs.BODY_YAW_MIN.getDoubleValue(), Configs.BODY_YAW_MAX.getDoubleValue());
            player.headYaw = 180 - (float) MathHelper.clamp(player.headYaw, Configs.HEAD_YAW_MIN.getDoubleValue(), Configs.HEAD_YAW_MAX.getDoubleValue());
            player.pitch = (float) (MathHelper.clamp(player.pitch, Configs.PITCH_MIN.getDoubleValue(), Configs.PITCH_MAX.getDoubleValue()) + Configs.PITCH_OFFSET.getDoubleValue());

            if (Configs.SWING_HANDS.getBooleanValue()) {
                player.handSwingProgress = player.getHandSwingProgress(client.getTickDelta());
            } else {
                player.handSwingProgress = 0;
            }

            if (!Configs.HURT_FLASH.getBooleanValue()) {
                player.hurtTime = 0;
            }

            quaternion2.conjugate();
            entityRenderDispatcher.setRotation(quaternion2);
            VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
            entityRenderDispatcher.getRenderer(player).render(player, yaw, 1, matrixStack, immediate, 15728880);
            immediate.draw();

            player.bodyYaw = bodyYaw;
            player.yaw = yaw;
            player.pitch = pitch;
            player.prevHeadYaw = prevHeadYaw;
            player.headYaw = headYaw;
            player.handSwingProgress = handSwingProgress;
            player.hurtTime = hurtTime;
        }
        RenderSystem.popMatrix();
    }
}

FledgeXu


我对Fabric不是很熟悉,其实我对渲染这块也是一知半解(逃
以我Forge的经验来说,物品渲染器里应该自带光照的参数的。
另外1.15之后的DiffuseLighting应该也在RenderSystem里了。


system


该主题在最后一个回复创建后7天后自动关闭。不再允许新的回复。