Помощь с OpenGl minecraft 1.12.2 forge

Версия Minecraft
1.12.2
API
Forge
Здравствуйте! Сделал кастомный рендер для оружия(через bakedmodel) если конечно можно назвать это рендером , но суть не в этом , а в translate и rotate , хотелось бы сделать чтобы они всегда выполняли одну и туже "задачу" так сказать , ведь если сделать пару настроек в rotate то в translate по X уже будет смещать не в такие стороны как раньше , как сделать чтобы функционал rotate и translate никогда не "деформировался" ? я думаю это достаточно распространенная проблема , но найти на решение я так и не смог , код рендера прикрепил.
GunRenderer:
package com.deadcraft.deadcraftmod.Renders.Item;

import com.deadcraft.deadcraftmod.Items.Gun.ItemGun;
import com.deadcraft.deadcraftmod.Items.Module.ModuleType;
import com.deadcraft.deadcraftmod.Renders.RenderCustomArms;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderItem;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import com.deadcraft.deadcraftmod.client.anim.ReloadAnimation;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
import com.deadcraft.deadcraftmod.client.model.ItemLayerWrapper;
import com.deadcraft.deadcraftmod.client.model.NoTransformWrapper;
import net.minecraftforge.client.ForgeHooksClient;
import com.deadcraft.deadcraftmod.client.GunRenderTuning;
import com.deadcraft.deadcraftmod.gui.ScopeOverlay;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import org.lwjgl.opengl.GL11;


@SideOnly(Side.CLIENT)
public class GunRenderer extends TileEntityItemStackRenderer {
    public static final GunRenderer INSTANCE = new GunRenderer();

    private static final float RECOIL_DISTANCE = 0.15f;
    private static final int RECOIL_DURATION = 150;

    private boolean isRecoiling = false;
    private long recoilStartTime = 0;
    private float recoilProgress = 0.0f;

    private TransformType currentTransformType = TransformType.NONE;
    private TransformType lastNonGuiTransformType = TransformType.FIRST_PERSON_RIGHT_HAND;

    public void setTransformType(TransformType type) {
        this.currentTransformType = (type != null) ? type : TransformType.NONE;
        if (type != null && type != TransformType.NONE && type != TransformType.GUI) {
            this.lastNonGuiTransformType = type;
        }
    }

    public TransformType getTransformType() {
        return this.currentTransformType;
    }

    @Override
    public void renderByItem(ItemStack stack) {
        if (!(stack.getItem() instanceof ItemGun)) {
            super.renderByItem(stack);
            return;
        }

        Minecraft mc = Minecraft.getMinecraft();
        if (mc.player == null || mc.world == null) {
            super.renderByItem(stack);
            return;
        }

        updateRecoilAnimation();

        GlStateManager.pushMatrix();

        GlStateManager.color(1f, 1f, 1f, 1f);
        GlStateManager.disableBlend();
        GlStateManager.enableDepth();
        GlStateManager.depthMask(true);

        TransformType type = this.currentTransformType;
        if (type == TransformType.NONE) {
            type = this.lastNonGuiTransformType != null ? this.lastNonGuiTransformType : TransformType.FIRST_PERSON_RIGHT_HAND;
        }

        RenderItem renderItem = mc.getRenderItem();
        IBakedModel baseModel = renderItem.getItemModelWithOverrides(stack, mc.world, mc.player);
        if (baseModel instanceof ItemLayerWrapper) {
            baseModel = ((ItemLayerWrapper) baseModel).getInternal();
        }

        boolean left = (type == TransformType.FIRST_PERSON_LEFT_HAND || type == TransformType.THIRD_PERSON_LEFT_HAND);
        ForgeHooksClient.handleCameraTransforms(baseModel, type, left);

        if (type == TransformType.FIRST_PERSON_RIGHT_HAND || type == TransformType.FIRST_PERSON_LEFT_HAND) {
            applyFirstPersonTransforms(type);
            applyRecoilTransform();
            applyAnimations(stack, mc);
        }

        GlStateManager.enableDepth();
        GlStateManager.depthMask(true);
        GlStateManager.disableBlend();
        GlStateManager.color(1f, 1f, 1f, 1f);

      
        GlStateManager.enableTexture2D();
        Minecraft.getMinecraft().getTextureManager().bindTexture(net.minecraft.client.renderer.texture.TextureMap.LOCATION_BLOCKS_TEXTURE);

        renderItem.renderItem(stack, new NoTransformWrapper(baseModel));
        
        if (type == TransformType.FIRST_PERSON_RIGHT_HAND || type == TransformType.FIRST_PERSON_LEFT_HAND) {
            RenderCustomArms.renderFirstPersonArms(type);
        }

        renderModulesOverlay(stack, type);

        GlStateManager.popMatrix();
    }
    public void triggerRecoil() {
        isRecoiling = true;
        recoilStartTime = System.currentTimeMillis();
        recoilProgress = 0.0f;
    }

 
    private void updateRecoilAnimation() {
        if (!isRecoiling) {
            recoilProgress = 0.0f;
            return;
        }

        long elapsed = System.currentTimeMillis() - recoilStartTime;
        if (elapsed >= RECOIL_DURATION) {
            isRecoiling = false;
            recoilProgress = 0.0f;
            return;
        }

        float t = (float) elapsed / RECOIL_DURATION;
        recoilProgress = 1.0f - (float) Math.pow(1.0f - t, 3.0);
    }

    private void applyRecoilTransform() {
        if (recoilProgress <= 0.0f) return;

        float offset;
        if (recoilProgress < 0.3f) {
            offset = (recoilProgress / 0.3f) * RECOIL_DISTANCE;
        } else {
            float returnProgress = (recoilProgress - 0.3f) / 0.7f;
            offset = RECOIL_DISTANCE * (1.0f - returnProgress);
        }

        //GlStateManager.translate(-offset, 0.0f, 0.0f);
        GlStateManager.rotate(-offset * 20.0f, 0.0f, 0.0f, 5.0f);
    }

    private void applyFirstPersonTransforms(TransformType type) {
        boolean isRight = (type == TransformType.FIRST_PERSON_RIGHT_HAND);
        float baseScale = isRight ? GunRenderTuning.FP_R_SCALE : GunRenderTuning.FP_L_SCALE;
        float adsScale = 1.0f;
        if (ScopeOverlay.isScoped) {
            adsScale = isRight ? GunRenderTuning.FP_R_ADS_SCALE : GunRenderTuning.FP_L_ADS_SCALE;
        }
        GlStateManager.scale(baseScale * adsScale, baseScale * adsScale, baseScale * adsScale);

        float tx = isRight ? GunRenderTuning.FP_R_TX : GunRenderTuning.FP_L_TX;
        float ty = isRight ? GunRenderTuning.FP_R_TY : GunRenderTuning.FP_L_TY;
        float tz = isRight ? GunRenderTuning.FP_R_TZ : GunRenderTuning.FP_L_TZ;

        if (ScopeOverlay.isScoped) {
            tx += isRight ? GunRenderTuning.FP_R_ADS_TX : GunRenderTuning.FP_L_ADS_TX;
            ty += isRight ? GunRenderTuning.FP_R_ADS_TY : GunRenderTuning.FP_L_ADS_TY;
            tz += isRight ? GunRenderTuning.FP_R_ADS_TZ : GunRenderTuning.FP_L_ADS_TZ;
        }

        GlStateManager.translate(tx, ty, tz);

        float rx = isRight ? GunRenderTuning.FP_R_RX : GunRenderTuning.FP_L_RX;
        float ry = isRight ? GunRenderTuning.FP_R_RY : GunRenderTuning.FP_L_RY;
        float rz = isRight ? GunRenderTuning.FP_R_RZ : GunRenderTuning.FP_L_RZ;

        if (ScopeOverlay.isScoped) {
            rx += isRight ? GunRenderTuning.FP_R_ADS_RX : GunRenderTuning.FP_L_ADS_RX;
            ry += isRight ? GunRenderTuning.FP_R_ADS_RY : GunRenderTuning.FP_L_ADS_RY;
            rz += isRight ? GunRenderTuning.FP_R_ADS_RZ : GunRenderTuning.FP_L_ADS_RZ;
        }
        
        if (rz != 0) GlStateManager.rotate(rz, 0, 0, 1);
        if (ry != 0) GlStateManager.rotate(ry, 0, 1, 0);
        if (rx != 0) GlStateManager.rotate(rx, 1, 0, 0);
    }
    private void applyAnimations(ItemStack stack, Minecraft mc) {
        if (mc.player.isSprinting()) {
            GlStateManager.rotate(10, 1, 0, 0);
            GlStateManager.rotate(10, 0, 0, 1);
        }
        ReloadAnimation.apply(stack, mc, Minecraft.getMinecraft().getRenderPartialTicks());
    }
    
    private void renderModulesOverlay(ItemStack gunStack, TransformType transformType) {
        if (!(gunStack.getItem() instanceof ItemGun)) return;

        ItemGun gun = (ItemGun) gunStack.getItem();
        Minecraft mc = Minecraft.getMinecraft();
        
        GlStateManager.pushMatrix();

        boolean isGuiView = (transformType == TransformType.GUI || transformType == TransformType.GROUND || transformType == TransformType.FIXED);

        if (isGuiView) {
            GlStateManager.translate(-0.5f, -0.5f, 0.0f);
        } else {
            GlStateManager.translate(-0.5f, -0.5f, 0.0f);
            
        }

    
        GlStateManager.enablePolygonOffset();
        GlStateManager.doPolygonOffset(-1.0f, -10.0f);
        GlStateManager.disableLighting();
        GlStateManager.enableBlend();
        GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

        
        mc.getTextureManager().bindTexture(net.minecraft.client.renderer.texture.TextureMap.LOCATION_BLOCKS_TEXTURE);

      
        for (ModuleType moduleType : ModuleType.values()) {
            ItemStack moduleStack = gun.getInstalledModule(gunStack, moduleType);

            
            if (moduleStack.isEmpty()) {
                continue;
            }
            
            ItemGun.OverlayPos overlayPos = gun.getModuleOverlay(moduleStack.getItem());
            if (overlayPos == null) {
                continue;
            }

            TextureAtlasSprite moduleSprite = getItemSprite(moduleStack);
            if (moduleSprite == null) {
              
                continue;
            }

            renderModuleAtPosition(overlayPos, moduleSprite, isGuiView, moduleType);
        }

      
        GlStateManager.disableBlend();
        GlStateManager.enableLighting();
        GlStateManager.doPolygonOffset(0.0f, 0.0f);
        GlStateManager.disablePolygonOffset();

        GlStateManager.popMatrix();
    }

 
    private void renderModuleAtPosition(ItemGun.OverlayPos overlayPos, TextureAtlasSprite sprite, boolean isGuiView, ModuleType moduleType) {
        GlStateManager.pushMatrix();

        if (isGuiView) {
            float pixelSize = 1.0f / 16.0f;
            int px = Math.max(0, Math.min(15, overlayPos.x));
            int py = Math.max(0, Math.min(15, overlayPos.y));

            GlStateManager.translate(px * pixelSize, -py * pixelSize, 0.001f);
            drawTexturedQuad(0.0f, 0.0f, pixelSize, pixelSize, sprite, 0.0f);
        } else {
      
            float basePixelSize = 1.0f / 16.0f;

          
            float normalizedX = overlayPos.x * basePixelSize;
            float normalizedY = -overlayPos.y * basePixelSize;

          
            float moduleWidth = getModuleWidth(moduleType) * basePixelSize;
            float moduleHeight = getModuleHeight(moduleType) * basePixelSize;

            GlStateManager.translate(normalizedX, normalizedY, 0.001f);
            drawTexturedQuad(0.0f, 0.0f, moduleWidth, moduleHeight, sprite, 0.0f);

          
        }

        GlStateManager.popMatrix();
    }

  
    private float getModuleWidth(ModuleType moduleType) {
        switch (moduleType) {
            case BARREL: return 1.0f;
            case SCOPE: return 1.0f; 
            case UNDERBARREL: return 1.0f;
            case MAGAZINE: return 1.0f;
            default: return 1.0f;
        }
    }


    private float getModuleHeight(ModuleType moduleType) {
        switch (moduleType) {
            case BARREL: return 1.0f;
            case SCOPE: return 1.0f;
            case UNDERBARREL: return 1.0f;
            case MAGAZINE: return 1.0f;
            default: return 1.0f;
        }
    }

    
    private void drawTexturedQuad(float x, float y, float width, float height,
                                  TextureAtlasSprite sprite, float zOffset) {
        if (sprite == null) return;

        Tessellator tessellator = Tessellator.getInstance();
        BufferBuilder buffer = tessellator.getBuffer();

        float minU = sprite.getMinU();
        float maxU = sprite.getMaxU();
        float minV = sprite.getMinV();
        float maxV = sprite.getMaxV();

        buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
        buffer.pos(x, y, zOffset).tex(minU, maxV).endVertex();
        buffer.pos(x + width, y, zOffset).tex(maxU, maxV).endVertex();
        buffer.pos(x + width, y + height, zOffset).tex(maxU, minV).endVertex();
        buffer.pos(x, y + height, zOffset).tex(minU, minV).endVertex();
        tessellator.draw();
    }
    
    private static TextureAtlasSprite getItemSprite(ItemStack stack) {
        Minecraft mc = Minecraft.getMinecraft();
        RenderItem renderItem = mc.getRenderItem();

        try {
            IBakedModel model = renderItem.getItemModelWithOverrides(stack, mc.world, mc.player);
            if (model != null) {
              
                java.util.List<net.minecraft.client.renderer.block.model.BakedQuad> quads =
                        model.getQuads(null, null, 0L);
                if (quads != null && !quads.isEmpty()) {
                    TextureAtlasSprite quadSprite = quads.get(0).getSprite();
                    if (quadSprite != null && !"minecraft:missingno".equals(quadSprite.getIconName())) {
                        return quadSprite;
                    }
                }
                
                TextureAtlasSprite particleSprite = model.getParticleTexture();
                if (particleSprite != null && !"minecraft:missingno".equals(particleSprite.getIconName())) {
                    return particleSprite;
                }
            }
            
            if (stack.getItem().getRegistryName() != null) {
                String domain = stack.getItem().getRegistryName().getResourceDomain();
                String path = stack.getItem().getRegistryName().getResourcePath();
                String spriteName = domain + ":items/" + path;

                TextureAtlasSprite byName = mc.getTextureMapBlocks().getAtlasSprite(spriteName);
                if (byName != null && !"minecraft:missingno".equals(byName.getIconName())) {
                    return byName;
                }
            }
        } catch (Exception e) {
        }
        
        return mc.getTextureMapBlocks().getMissingSprite();
    }
}
GunRenderTuning(почти безполезный в эом контексте):
package com.deadcraft.deadcraftmod.client;


public class GunRenderTuning {
    
    public static float HAND_R_TX = 0.0f;
    public static float HAND_R_TY = 0.0f;
    public static float HAND_R_TZ = 0.0f;
    public static float HAND_R_RX = 0.0f;
    public static float HAND_R_RY = 0.0f;
    public static float HAND_R_RZ = 0.0f;
    public static float HAND_R_SCALE = 1.10f;

    public static float HAND_L_TX = 0.0f;
    public static float HAND_L_TY = 0.0f;
    public static float HAND_L_TZ = 0.0f;
    public static float HAND_L_RX = 0.0f;
    public static float HAND_L_RY = 0.0f;
    public static float HAND_L_RZ = 0.0f;
    public static float HAND_L_SCALE = 1.990f;
    
    public static float FP_R_TX = 0.0f;
    public static float FP_R_TY = 0.0f;
    public static float FP_R_TZ = 0.0f;
    public static float FP_R_RX = 0.0f;
    public static float FP_R_RY = 0.0f;
    public static float FP_R_RZ = 0.0f;
    public static float FP_R_SCALE = 1.340f;

    
    public static float FP_R_ADS_TX = 0.0f;
    public static float FP_R_ADS_TY = 0.0f;
    public static float FP_R_ADS_TZ = 0.0f;
    public static float FP_R_ADS_RX = 0.0f;
    public static float FP_R_ADS_RY = 0.0f;
    public static float FP_R_ADS_RZ = 0.0f;
    public static float FP_R_ADS_SCALE = 1.0f;

  
    public static float FP_L_TX = 0.0f;
    public static float FP_L_TY = 0.0f;
    public static float FP_L_TZ = 0.0f;
    public static float FP_L_RX = 0.0f;
    public static float FP_L_RY = 0.0f;
    public static float FP_L_RZ = 0.0f;
    public static float FP_L_SCALE = 1.0f;


    public static float FP_L_ADS_TX = 0.0f;
    public static float FP_L_ADS_TY = 0.0f;
    public static float FP_L_ADS_TZ = 0.0f;
    public static float FP_L_ADS_RX = 0.0f;
    public static float FP_L_ADS_RY = 0.0f;
    public static float FP_L_ADS_RZ = 0.0f;
    public static float FP_L_ADS_SCALE = 1.0f;
    
    public static float MOD_TX = 0.0f;
    public static float MOD_TY = 0.00f;
    public static float MOD_TZ = 0.00f;
    public static float MOD_RX = 0.0f;
    public static float MOD_RY = 0.0f;
    public static float MOD_RZ = 0.0f;
    public static float MOD_SCALE = 1.0f;
}
 
Решение
Ты когда rotate вызываешь у тебя поворачивается вся координатная система, если например повернуть на 90 градусов вдоль z то: x- станет y+ а y- станет x-
Sprite-0003.png
Во так вот, по хорошему нада трансформации прописывать с учётом этого.
Но если костылить то можно компенсировать поворот координатной плоскости, отрицательным поворотом вектора translate, если по подробнее то
Три значения в GlStateManager:translate можно представить как вектор (по сути это он и есть) допустим он будет (0, 1, 0)
Sprite-0002.png
На втором варианте тот же вектор но из а того что того что координатная плоскость повернута на 90 градусов он направлен в x+
и чтоб он был направлен в правильную сторону, надо повернуть его в обратную сторону то есть на...
Ты когда rotate вызываешь у тебя поворачивается вся координатная система, если например повернуть на 90 градусов вдоль z то: x- станет y+ а y- станет x-
Sprite-0003.png
Во так вот, по хорошему нада трансформации прописывать с учётом этого.
Но если костылить то можно компенсировать поворот координатной плоскости, отрицательным поворотом вектора translate, если по подробнее то
Три значения в GlStateManager:translate можно представить как вектор (по сути это он и есть) допустим он будет (0, 1, 0)
Sprite-0002.png
На втором варианте тот же вектор но из а того что того что координатная плоскость повернута на 90 градусов он направлен в x+
и чтоб он был направлен в правильную сторону, надо повернуть его в обратную сторону то есть на -90, то-есть компенсировать 90 градусный поворот
и того x = x * cos(-90) + y * sin(-90); y = x * sin(-90) - y * cos(-90); получается (-1, 0, 0)
Sprite-0001.png
Во так вот, так можно компенсировать сколь угодно поворотов матрици, но лучше просто все учесть во время прописывания трансформаций.
PS: За за правильность цифр не ручаюсь (но вроде правильно),
в сраном Aseprite поворот по часовой стрелке это -90 градусов, я сам уже раз 10 запутался,
но логика думаю должна быть понятна
 
Назад
Сверху