版本信息
系统: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();
}
}