package com.atsuishio.superbwarfare.client.renderer; import com.atsuishio.superbwarfare.client.model.item.CustomGunModel; import com.atsuishio.superbwarfare.config.client.DisplayConfig; import com.atsuishio.superbwarfare.item.gun.GunItem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import software.bernie.geckolib.animatable.GeoAnimatable; import software.bernie.geckolib.cache.object.BakedGeoModel; import software.bernie.geckolib.cache.object.GeoBone; import software.bernie.geckolib.model.GeoModel; import software.bernie.geckolib.renderer.GeoItemRenderer; import software.bernie.geckolib.util.Color; import software.bernie.geckolib.util.RenderUtil; public class CustomGunRenderer extends GeoItemRenderer { public static final float SCALE_RECIPROCAL = 1.0f / 16.0f; public static final int LOD_DISTANCE = 100; protected T animatable; protected boolean renderArms = false; protected MultiBufferSource currentBuffer; protected RenderType renderType; public ItemDisplayContext transformType; public CustomGunRenderer(GeoModel model) { super(model); } @Override public void actuallyRender(PoseStack matrixStackIn, T animatable, BakedGeoModel model, RenderType type, MultiBufferSource renderTypeBuffer, VertexConsumer vertexBuilder, boolean isRenderer, float partialTicks, int packedLightIn, int packedOverlayIn, int color) { this.currentBuffer = renderTypeBuffer; this.renderType = type; this.animatable = animatable; super.actuallyRender(matrixStackIn, animatable, model, type, renderTypeBuffer, vertexBuilder, isRenderer, partialTicks, packedLightIn, packedOverlayIn, color); if (this.renderArms) { this.renderArms = false; } } @Override public RenderType getRenderType(T animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { return RenderType.entityTranslucent(texture); } @Override public ResourceLocation getTextureLocation(T animatable) { var geoModel = getGeoModel(); if (renderPerspective != ItemDisplayContext.FIRST_PERSON_RIGHT_HAND && DisplayConfig.ENABLE_GUN_LOD.get() && geoModel instanceof CustomGunModel gunModel ) { return gunModel.getLODTextureResource(animatable); } return geoModel.getTextureResource(animatable, null); } public ResourceLocation getTextureLocation(T animatable, PoseStack poseStack) { var geoModel = getGeoModel(); if (renderPerspective != ItemDisplayContext.FIRST_PERSON_RIGHT_HAND && DisplayConfig.ENABLE_GUN_LOD.get() && geoModel instanceof CustomGunModel gunModel ) { var player = Minecraft.getInstance().player; if (player != null) { Vec3 pos = new Vec3(poseStack.last().pose().m30(), poseStack.last().pose().m31(), poseStack.last().pose().m32()); if (pos.lengthSqr() >= LOD_DISTANCE) { return gunModel.getLODTextureResource(animatable); } else { return geoModel.getTextureResource(animatable, null); } } return gunModel.getLODTextureResource(animatable); } return geoModel.getTextureResource(animatable, null); } @Override public void renderByItem(ItemStack stack, ItemDisplayContext transformType, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay) { this.animatable = (T) stack.getItem(); this.currentItemStack = stack; this.renderPerspective = transformType; if (transformType == ItemDisplayContext.GUI) { renderInGui(transformType, poseStack, bufferSource, packedLight, packedOverlay, Minecraft.getInstance().getTimer().getRealtimeDeltaTicks()); } else { RenderType renderType = getRenderType(this.animatable, getTextureLocation(this.animatable, poseStack), bufferSource, Minecraft.getInstance().getTimer().getRealtimeDeltaTicks()); VertexConsumer buffer = ItemRenderer.getFoilBufferDirect(bufferSource, renderType, false, this.currentItemStack != null && this.currentItemStack.hasFoil()); defaultRender(poseStack, this.animatable, bufferSource, renderType, buffer, 0, Minecraft.getInstance().getTimer().getRealtimeDeltaTicks(), packedLight); } } @Override public void defaultRender(PoseStack poseStack, T animatable, MultiBufferSource bufferSource, @Nullable RenderType renderType, @Nullable VertexConsumer buffer, float yaw, float partialTick, int packedLight) { poseStack.pushPose(); Color renderColor = getRenderColor(animatable, partialTick, packedLight); int packedOverlay = getPackedOverlay(animatable, 0, partialTick); var player = Minecraft.getInstance().player; ResourceLocation modelLocation; var geoModel = getGeoModel(); if (renderPerspective != ItemDisplayContext.FIRST_PERSON_RIGHT_HAND && DisplayConfig.ENABLE_GUN_LOD.get() && geoModel instanceof CustomGunModel gunModel ) { if (player != null) { Vec3 pos = new Vec3(poseStack.last().pose().m30(), poseStack.last().pose().m31(), poseStack.last().pose().m32()); if (pos.lengthSqr() >= LOD_DISTANCE) { modelLocation = gunModel.getLODModelResource(animatable); } else { // TODO 这个地方有问题,如果是在这里使用了高模,会导致custom animation无法分离 modelLocation = geoModel.getModelResource(animatable, null); } } else { modelLocation = gunModel.getLODModelResource(animatable); } } else { modelLocation = geoModel.getModelResource(animatable, null); } BakedGeoModel model = geoModel.getBakedModel(modelLocation); if (renderType == null) renderType = getRenderType(animatable, getTextureLocation(animatable, poseStack), bufferSource, partialTick); if (buffer == null) buffer = bufferSource.getBuffer(renderType); preRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor.argbInt()); if (firePreRenderEvent(poseStack, model, bufferSource, partialTick, packedLight)) { preApplyRenderLayers(poseStack, animatable, model, renderType, bufferSource, buffer, packedLight, packedLight, packedOverlay); actuallyRender(poseStack, animatable, model, renderType, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor.argbInt()); this.renderIlluminatedBones(model, poseStack, bufferSource, animatable, renderType, buffer, partialTick, packedLight, packedOverlay, renderColor.argbInt()); postRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor.argbInt()); firePostRenderEvent(poseStack, model, bufferSource, partialTick, packedLight); } poseStack.popPose(); renderFinal(poseStack, animatable, model, bufferSource, buffer, partialTick, packedLight, packedOverlay, renderColor.argbInt()); } public void renderIlluminatedBones(BakedGeoModel model, PoseStack poseStack, MultiBufferSource bufferSource, T animatable, RenderType renderType, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay, int color) { poseStack.pushPose(); preRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, color); this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); updateAnimatedTextureFrame(animatable); for (GeoBone bone : model.topLevelBones()) { this.illuminatedRender(poseStack, animatable, bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay, color); } postRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, color); poseStack.popPose(); } public void illuminatedRender(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay, int color) { if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); bone.setModelSpaceMatrix(RenderUtil.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix(RenderUtil.invertAndMultiplyMatrices(poseState, this.itemRenderTranslations)); } poseStack.pushPose(); RenderUtil.prepMatrixForBone(poseStack, bone); if (bone.getName().endsWith("_illuminated")) { renderCubesOfBone(poseStack, bone, bufferSource.getBuffer(ModRenderTypes.ILLUMINATED.apply(this.getTextureLocation(animatable, poseStack))), packedLight, OverlayTexture.NO_OVERLAY, color); } this.illuminatedRenderChildBones(poseStack, animatable, bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay, color); poseStack.popPose(); } public void illuminatedRenderChildBones(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay, int color) { if (bone.isHidingChildren()) return; for (GeoBone childBone : bone.getChildBones()) { illuminatedRender(poseStack, animatable, childBone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay, color); } } }