Луч с неба

Версия Minecraft
1.12.2
API
Forge

sk9zist :l

Исправился
981
18
158
Как сделать красный луч, который ведет от одного блока к другому с помощью GlStateManager ?
 
Спасибо, попробую. Кстати, translateToZeroCoord полезный метод, я возможно тоже буду его использовать
 
@hohserg Извиняюсь, а что за переменная entity.curve?
TestItem.java:
public static void translateToZeroCoord(float partialTicks)
    {
        Entity player = Minecraft.getMinecraft().player;
        double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks;
        double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks;
        double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks;
        GlStateManager.translate(-x, -y, -z);
    }
    
    private void drawLine(Vec3d first, Color color, BufferBuilder buffer)
    {
        buffer.pos(first.x, first.y, first.z).color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()).endVertex();
    }
    
    private void drawPolyChain(List<Vec3d> path, Color color)
    {
        Tessellator tessellator = Tessellator.getInstance();
        BufferBuilder buffer = tessellator.getBuffer();
        buffer.begin(3, DefaultVertexFormats.POSITION_COLOR);

        for (Vec3d vec3d : path)
            drawLine(vec3d, color, buffer);

        tessellator.draw();
    }
    
    private List<Vec3d> makePath(World worldIn, Vec3d startPos, BlockPos targetPos)
    {
        Vec3d finalPos = new Vec3d(targetPos.getX() + 0.5, targetPos.getY() + 0.75, targetPos.getZ() + 0.5);

        List<Vec3d> r = new ArrayList<>();
        r.add(startPos);

        Vec3d aboveFrame = new Vec3d(targetPos.getX() + 0.5, targetPos.getY() + 3, targetPos.getZ() + 0.5);
        double height = aboveFrame.y - startPos.y;
        if (height > 1 && startPos.squareDistanceTo(finalPos) > 25) {
            Vector2d direction = new Vector2d(aboveFrame.x, aboveFrame.z);
            direction.sub(new Vector2d(startPos.x, startPos.z));
            direction.normalize();
            r.add(new Vec3d(
                    startPos.x + height * direction.x,
                    startPos.y + height,
                    startPos.z + height * direction.y
            ));
        }
        r.add(aboveFrame);

        r.add(finalPos);
        return r;
    }
    
    public static Function<Double, Vec3d> bezierCurve(List<Vec3d> path)
    {
        Vec3d first = path.get(0);
        Vec3d last = path.get(path.size() - 1);
        float angle = (float) Math.atan2(last.x - first.x, last.z - first.z);

        List<Vec3d> rotatedPath = path.stream().map(v -> v.rotateYaw(-angle)).collect(Collectors.toList());

        return t -> {
            double z = 0;
            double y = 0;

            int n = rotatedPath.size() - 1;

            Vec3d vec = rotatedPath.get(0);
            double pow_1_minus_t_n = Math.pow((1 - t), n);
            z += vec.z * pow_1_minus_t_n;
            y += vec.y * pow_1_minus_t_n;

            double factorial_n = factorial(n);

            for (int index = 1; index < rotatedPath.size(); index++) {
                Vec3d item = rotatedPath.get(index);
                z += factorial_n / factorial(index) / factorial(n - index) * item.z * Math.pow((1 - t), n - index) * Math.pow(t, index);
                y += factorial_n / factorial(index) / factorial(n - index) * item.y * Math.pow((1 - t), n - index) * Math.pow(t, index);
            }
            return new Vec3d(vec.x, y, z).rotateYaw(angle);
        };
    }
    
    private static Int2IntMap factorialCache = new Int2IntOpenHashMap();
    
    private static double factorial(int num)
    {
        return factorialCache.computeIfAbsent(num, num1 -> factorial(num1, 1));
    }
    
    private static int factorial(int num, int acc)
    {
        if (num <= 1) {
            return acc;
        } else {
            return factorial(num - 1, acc * num);
        }
    }
    
    @Override
    public void onUpdate(ItemStack stack, World worldIn, Entity entity, int itemSlot, boolean isSelected)
    {
        if(entity instanceof EntityPlayer)
        {
            GlStateManager.pushMatrix();
            translateToZeroCoord(Minecraft.getMinecraft().getRenderPartialTicks());
            GlStateManager.disableLighting();
            GlStateManager.depthMask(false);
            GlStateManager.glLineWidth(2.0F);
            GlStateManager.disableTexture2D();

            List<Vec3d> path = makePath(worldIn, entity.getPositionVector(), entity.getPosition().east(50));
            
            drawPolyChain(path, Color.green);
            drawPolyChain(IntStream.range(0, 100).mapToDouble(i -> ((double) i) / 100).mapToObj(entity.curve::apply).collect(Collectors.toList()), Color.red);

            GlStateManager.enableLighting();
            GlStateManager.depthMask(true);
            GlStateManager.enableTexture2D();
            GlStateManager.popMatrix();
        }
    }
    
    @Override
    public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn)
    {
        
        
        return new ActionResult<ItemStack>(EnumActionResult.PASS, playerIn.getHeldItem(handIn));
    }
 
Это только для безье. Если прямые линии - просто забей на это
 
Я уже перенес в RenderWorldLastEvent и сделал проверку глобальную переменную, которую я создал для этого предмета (так как он чисто клиентский, +луч все равно на клиенте)
 
@hohserg ну, как-бэ)
2021-07-10_18.01.01.png
(Линия приходит куда надо, т.e. на 10 блоков от меня на восток как я и задал. Но почему-то она какая-то кривая)

RenderHelper.java:
public class RenderHelper
{
    public static Function<Double, Vec3d> curve;
    public static List<Vec3d> path;
    
    public static void debugDrawing(Entity entity, float partialTicks, World world)
    {
        GlStateManager.pushMatrix();
        translateToZeroCoord(Minecraft.getMinecraft().getRenderPartialTicks());
        GlStateManager.disableLighting();
        GlStateManager.depthMask(false);
        GlStateManager.glLineWidth(2.0F);
        GlStateManager.disableTexture2D();

        path = makePath(world, entity.getPositionVector(), entity.getPosition().east(10));
        
        drawPolyChain(path, Color.green);

        GlStateManager.enableLighting();
        GlStateManager.depthMask(true);
        GlStateManager.enableTexture2D();
        GlStateManager.popMatrix();
    }
    
    public static void translateToZeroCoord(float partialTicks)
    {
        Entity player = Minecraft.getMinecraft().player;
        double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks;
        double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks;
        double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks;
        GlStateManager.translate(-x, -y, -z);
    }
    
    public static void drawLine(Vec3d first, Color color, BufferBuilder buffer)
    {
        buffer.pos(first.x, first.y, first.z).color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()).endVertex();
    }
    
    public static void drawPolyChain(List<Vec3d> path, Color color)
    {
        Tessellator tessellator = Tessellator.getInstance();
        BufferBuilder buffer = tessellator.getBuffer();
        buffer.begin(3, DefaultVertexFormats.POSITION_COLOR);

        for (Vec3d vec3d : path)
            drawLine(vec3d, color, buffer);

        tessellator.draw();
    }
    
    public static List<Vec3d> makePath(World worldIn, Vec3d startPos, BlockPos targetPos)
    {
        Vec3d finalPos = new Vec3d(targetPos.getX() + 0.5, targetPos.getY() + 0.75, targetPos.getZ() + 0.5);

        List<Vec3d> r = new ArrayList<>();
        r.add(startPos);

        Vec3d aboveFrame = new Vec3d(targetPos.getX() + 0.5, targetPos.getY() + 3, targetPos.getZ() + 0.5);
        double height = aboveFrame.y - startPos.y;
        if (height > 1 && startPos.squareDistanceTo(finalPos) > 25) {
            Vector2d direction = new Vector2d(aboveFrame.x, aboveFrame.z);
            direction.sub(new Vector2d(startPos.x, startPos.z));
            direction.normalize();
            r.add(new Vec3d(
                    startPos.x + height * direction.x,
                    startPos.y + height,
                    startPos.z + height * direction.y
            ));
        }
        r.add(aboveFrame);

        r.add(finalPos);
        return r;
    }
    
    public static Function<Double, Vec3d> bezierCurve(List<Vec3d> path)
    {
        Vec3d first = path.get(0);
        Vec3d last = path.get(path.size() - 1);
        float angle = (float) Math.atan2(last.x - first.x, last.z - first.z);

        List<Vec3d> rotatedPath = path.stream().map(v -> v.rotateYaw(-angle)).collect(Collectors.toList());

        return t -> {
            double z = 0;
            double y = 0;

            int n = rotatedPath.size() - 1;

            Vec3d vec = rotatedPath.get(0);
            double pow_1_minus_t_n = Math.pow((1 - t), n);
            z += vec.z * pow_1_minus_t_n;
            y += vec.y * pow_1_minus_t_n;

            double factorial_n = factorial(n);

            for (int index = 1; index < rotatedPath.size(); index++) {
                Vec3d item = rotatedPath.get(index);
                z += factorial_n / factorial(index) / factorial(n - index) * item.z * Math.pow((1 - t), n - index) * Math.pow(t, index);
                y += factorial_n / factorial(index) / factorial(n - index) * item.y * Math.pow((1 - t), n - index) * Math.pow(t, index);
            }
            return new Vec3d(vec.x, y, z).rotateYaw(angle);
        };
    }
    
    public static Int2IntMap factorialCache = new Int2IntOpenHashMap();
    
    public static double factorial(int num)
    {
        return factorialCache.computeIfAbsent(num, num1 -> factorial(num1, 1));
    }
    
    public static int factorial(int num, int acc)
    {
        if (num <= 1) {
            return acc;
        } else {
            return factorial(num - 1, acc * num);
        }
    }
}
EventsHandler.java:
@SubscribeEvent
public void onUpdate(RenderWorldLastEvent e)
{
    RenderHelper.debugDrawing(Minecraft.getMinecraft().player, e.getPartialTicks(), Minecraft.getMinecraft().world);
}
Да, я пропустил часть с безье. Просто у меня ошибка на этой строчке curve::apply
Java:
drawPolyChain(IntStream.range(0, 100).mapToDouble(i -> ((double) i) / 100).mapToObj(curve::apply).collect(Collectors.toList()), Color.red);
 
Сделал как мне надо исходя из своих базовых знаний OpenGL:
EventsHandler.java:
@SubscribeEvent
public void onUpdate(RenderWorldLastEvent e)
{
    float x = -231;
    float y = 4;
    float z = 218;
       
    GlStateManager.pushMatrix();
    RenderHelper.translateToZeroCoord(Minecraft.getMinecraft().getRenderPartialTicks());
    GlStateManager.disableLighting();
    GlStateManager.depthMask(false);
    GlStateManager.glLineWidth(2.0F);
    GlStateManager.disableTexture2D();
       
    GlStateManager.glBegin(GL11.GL_LINES);
    GlStateManager.color(255, 0, 0);
    GlStateManager.glVertex3f((float) Minecraft.getMinecraft().player.posX, (float) Minecraft.getMinecraft().player.posY + 1, (float) Minecraft.getMinecraft().player.posZ);
    GlStateManager.glVertex3f((float) (x + 0.5), (float) (y + 0.5), (float) (z + 0.5));
    GlStateManager.glEnd();

    GlStateManager.enableLighting();
    GlStateManager.depthMask(true);
    GlStateManager.enableTexture2D();
    GlStateManager.popMatrix();
}
2021-07-10_18.44.06.png2021-07-10_18.44.13.png
Но луч дёргается при движении, на скрине не видно но есть жесткие подёргивания. Как это исправить?
 
дёргается при движении
Про partialTicks не забывай
GlStateManager.glVertex3f((float) Minecraft.getMinecraft().player.posX, (float) Minecraft.getMinecraft().player.posY + 1, (float) Minecraft.getMinecraft().player.posZ);
posX/Y/Z у игрока - это с точностью до тика. Посмотри, как в translateToZeroCoord вычисляется позиция игрока с учетом partialTicks

Но почему-то она какая-то кривая)
Потому что надо не тупо копипастить все, а взять только то, что нужно для твоей задачи. У мя там кривые безье рисовались.
 
Спасибо-с) Теперь всё гладко.
Заменил получение getPartialTicks из эвента и сделал как ты сказал. Вот готовый код кому будет нужно:
Java:
@SubscribeEvent
    public void onUpdate(RenderWorldLastEvent e)
    {
        float x = -231;
        float y = 4;
        float z = 218;
       
        GlStateManager.pushMatrix();
        RenderHelper.translateToZeroCoord(e.getPartialTicks());
        GlStateManager.disableLighting();
        GlStateManager.depthMask(false);
        GlStateManager.glLineWidth(2.0F);
        GlStateManager.disableTexture2D();
       
        GlStateManager.glBegin(GL11.GL_LINES);
        GlStateManager.color(255, 0, 0);
        GlStateManager.glVertex3f((float) (Minecraft.getMinecraft().player.lastTickPosX + (Minecraft.getMinecraft().player.posX - Minecraft.getMinecraft().player.lastTickPosX) * e.getPartialTicks()),
                                  (float) (Minecraft.getMinecraft().player.lastTickPosY + (Minecraft.getMinecraft().player.posY - Minecraft.getMinecraft().player.lastTickPosY) * e.getPartialTicks()),
                                  (float) (Minecraft.getMinecraft().player.lastTickPosZ + (Minecraft.getMinecraft().player.posZ - Minecraft.getMinecraft().player.lastTickPosZ) * e.getPartialTicks()));
        GlStateManager.glVertex3f((float) (x + 0.5), (float) (y + 0.5), (float) (z + 0.5));
        GlStateManager.glEnd();

        GlStateManager.enableLighting();
        GlStateManager.depthMask(true);
        GlStateManager.enableTexture2D();
        GlStateManager.popMatrix();
    }
Тебе заслуженный - Лучший ответ.
 
Назад
Сверху