Реально ли зарендерить circle с текстуркой?

Версия Minecraft
1.12.2
476
9
39
Реально ли зарендерить circle с текстуркой?
Вообщем есть идея сделать классный прогресс бар, но особо в голову ничего не лезет, как точки там расчитывать, как оно должно быть.
По идее прогресс рассчитывать простым делением на 360, но как брать uv у текстуры, какие точки брать для x,y.
И делать это быстро или хотя бы без потерь по производительности, знаю, что есть разные алгоритмы на эту тему, но как адаптировать всё под lwjgl/minecraft пока не смог полностью представить.
Логика вроде должна быть простой строим часть окружности до определенного значения, где максимум 360, а минимум 0.
На этом заканчивается простая логика ибо как это построить с помощью buffer.pos().tex(); понятия не имею.
В целом есть идея юзать три точки, где первая это центр окружности, и ещё две как крайние для треугольника.
Дальше нужно рассчитать их x,y и придумать, как рассчитать u/v и повторить до текущего прогресса.
В общем, непонятно.
 
Решение
Kotlin:
/**
 * x, y - центр окружности на экране
 * rx, ry - радиусы окружности на экране
 * u, v - центр окружности на текстуре [0.0, 1.0]
 * ru, rv - радиусы окружности на текстуре [0.0, 1.0]
 * a1, a2 - начальный и конечный углы в градусах
 * freq - частота треугольников в градусах
 */
fun drawTexturedCircle(x: Double, y: Double, z: Double, rx: Double, ry: Double,
                       u: Double, v: Double, ru: Double, rv: Double,
                       a1: Double, a2: Double, freq: Double) {
    val tess = Tessellator.instance
    tess.startDrawing(GL_TRIANGLE_FAN)
    tess.addVertexWithUV(x, y, z, u, v)
    
    var from = a2.toFloat() * Maths.degreesToRadians
    val to = a1.toFloat() * Maths.degreesToRadians
    val step =...

Icosider

Kotliner
Администратор
3,600
99
663
2,505
81
397
Kotlin:
/**
 * x, y - центр окружности на экране
 * rx, ry - радиусы окружности на экране
 * u, v - центр окружности на текстуре [0.0, 1.0]
 * ru, rv - радиусы окружности на текстуре [0.0, 1.0]
 * a1, a2 - начальный и конечный углы в градусах
 * freq - частота треугольников в градусах
 */
fun drawTexturedCircle(x: Double, y: Double, z: Double, rx: Double, ry: Double,
                       u: Double, v: Double, ru: Double, rv: Double,
                       a1: Double, a2: Double, freq: Double) {
    val tess = Tessellator.instance
    tess.startDrawing(GL_TRIANGLE_FAN)
    tess.addVertexWithUV(x, y, z, u, v)
    
    var from = a2.toFloat() * Maths.degreesToRadians
    val to = a1.toFloat() * Maths.degreesToRadians
    val step = -freq.toFloat() * Maths.degreesToRadians
    while (from >= to) {
        val cos = MathHelper.cos(from)
        val sin = MathHelper.sin(from)
        tess.addVertexWithUV(x + rx * cos, y + ry * sin, z, u + ru * cos, v + rv * sin)
        from += step
    }
    tess.draw()
}
 
476
9
39
Maths.degreesToRadians
В Java такого нет, в котлине есть, есть какой-то ближайший аналог?
Просто не особо понятно на что именно тут умножается?
Java:
double from = a2 * Math.toDegrees(1);
double to = a1 * Math.toDegrees(1);
double step = -freq * Math.toDegrees(1);
 
7,099
324
1,509
476
9
39
Юзаю так:
Java:
GlStateManager.translate(sc.getScaledWidth_double() / 2D, sc.getScaledHeight_double() / 2D, 1D);
mc.getTextureManager().bindTexture(CIRCLE);
GuiHelper.drawTexturedCircle(-30, -30, 32, 32, 0.4648, 0.4648, 0.9296, 0.9296, 0, 360, 10);
Не катит, не в какую, почитал javadoc у Math util -> нужно юзать toRadians ибо он переводит из градусов в радианы, но в любом случае не катит. Даже артефактов нету, адаптация на java + mc 1.12.2, текстура разрешением 128x128, занимает 119х119.
Java:
/** Пытаемся строить окружность с текстурой
* @param x    центр окружности на экране
* @param y    центр окружности на экране
* @param rx   радиус окружности на экране
* @param ry   радиус окружности на экране
* @param u    центр окружности на текстуре [0.0, 1.0]
* @param v    центр окружности на текстуре [0.0, 1.0]
* @param ru   радиус окружности на текстуре [0.0, 1.0]
* @param rv   радиус окружности на текстуре [0.0, 1.0]
* @param toAngle   начальный угол в градусах
* @param fromAngle   конечный угол в градусах
* @param freq частота треугольников в градусах
*/
public static void drawTexturedCircle(double x, double y, double rx, double ry, double u, double v, double ru, double rv, double fromAngle, double toAngle, double freq)
{
    Tessellator tessellator = Tessellator.getInstance();
    BufferBuilder buffer = tessellator.getBuffer();
   
    buffer.begin(GL_TRIANGLE_FAN, DefaultVertexFormats.POSITION_TEX);
    buffer.pos(x, y, 0D).tex(u, v);
   
    float from = (float) (Math.toRadians(fromAngle));
    float to = (float) (Math.toRadians(toAngle));
    float step = (float) (Math.toRadians(-freq));
    while (from >= to)
    {
        double cos = MathHelper.cos(from);
        double sin = MathHelper.sin(from);
        buffer.pos(x + rx * cos, y + ry * sin, 0D).tex(u + ru * cos, v + rv * sin);
        from += step;
    }
    tessellator.draw();
}
 
2,505
81
397
В Java такого нет, в котлине есть, есть какой-то ближайший аналог?
Ой, не заметил. На самом деле это моя константа. Просто сделал так, чтобы не было лишних кастов Double-Float
Kotlin:
const val PI = 3.1415927f
const val degreesToRadians = PI / 180

Напиши метод, который приводит нормальную позицию пикселя на картинке в uv. 0.4648 я еще могу представить - примерно центр картинки. Но радиус 0.9296? Это получается у тебя радиус размером почти с изображение.
Пример: Есть картинка 100х100. Центр в точке (50, 50). Радиус окружности 40. Вместо u, v, ru, rv тебе нужно подставить 50 / 100.0, 50 / 100.0, 40 / 100.0, 40 / 100.0
 
Последнее редактирование:
476
9
39
Попытался сделать без текстуры что-то с помощью POSITION_COLOR
Java:
/**
* Пытаемся строить окружность с текстурой
*
* @param x         центр окружности на экране
* @param y         центр окружности на экране
* @param rx        радиус окружности на экране
* @param ry        радиус окружности на экране
* @param toAngle   начальный угол в градусах
* @param fromAngle конечный угол в градусах
* @param freq      частота треугольников в градусах
*/
public static void drawTexturedCircle(double x, double y, double rx, double ry, double fromAngle, double toAngle, double freq)
{
    Tessellator tessellator = Tessellator.getInstance();
    BufferBuilder buffer = tessellator.getBuffer();
   
    buffer.begin(GL_TRIANGLE_FAN, DefaultVertexFormats.POSITION_COLOR);
    buffer.pos(x, y, 0D).color(255, 255,255,255);
   
    float from = (float) (fromAngle * PI / 180);
    float to = (float) (toAngle * PI / 180);
    float step = (float) (-freq * PI / 180);
    while (from >= to)
    {
        double cos = MathHelper.cos(from);
        double sin = MathHelper.sin(from);
        buffer.pos(x + rx * cos, y + ry * sin, 0D).color(255, 255,255,255);
        from += step;
    }
    tessellator.draw();
}
Понятия не имею почему он ничего не строит, вечно проблемы с buffer'ом. Пробовал добавить .endVertex() не катит, пару десятков вариаций испробовал всё равно не катит... Блин, со старым addVertexWithUV никогда проблем не было.
Java:
GuiHelper.drawTexturedCircle(-30, -30, 64, 64, 59F/128F, 59F/128F, 51F/128F, 51F/128F, 0, 360, 1);
//Вариации без uv, с color(255, 255, 255, 255) внутри
GuiHelper.drawTexturedCircle(0, 0, 32, 32, 0, 360, 1);
GuiHelper.drawTexturedCircle(0, 0, 64, 64, 0, 360, 1);
GuiHelper.drawTexturedCircle(0, 0, 64, 64, 0, 360, 10);
GuiHelper.drawTexturedCircle(0, 0, 64, 64, 0, 360, 10);
GuiHelper.drawTexturedCircle(0, 0, 64, 64, 360, 0, 1);
GuiHelper.drawTexturedCircle(0, 0, 64, 64, 360, 0, 1);
GuiHelper.drawTexturedCircle(0, 0, 64, 64, 360, 0, 10);
GuiHelper.drawTexturedCircle(0, 0, 64, 64, 360, 0, 10);
 
Последнее редактирование:
476
9
39
Так, во, для рендера без текстуры нужно отключить 2д текстуринг, щя с uv разберусь.
 
476
9
39
Разобрался, не знаю, что я сломал при портировании или с координатами радиуса косякнул, но теперь всё завелось. Спасибо!)
 
476
9
39
Ну по логике endVertex нужен.
А есть способ убрать тиринг при динамическом изменении полосы?
Если задать маленький freq то видно кучу пикселей, если большой видно тиринг.
tiringOnBlack.png
На чёрном хорошо видно, она немного вверх поднимается, и потом снова отпускается вниз. Выглядит странно, будто круг вращают.
Код особо не менял.
Java:
/**
* Пытаемся строить окружность с текстурой
*
* @param x         центр окружности на экране
* @param y         центр окружности на экране
* @param rx        радиус окружности на экране
* @param ry        радиус окружности на экране
* @param u         центр окружности на текстуре [0.0, 1.0]
* @param v         центр окружности на текстуре [0.0, 1.0]
* @param ru        радиус окружности на текстуре [0.0, 1.0]
* @param rv        радиус окружности на текстуре [0.0, 1.0]
* @param fromAngle начальный угол в градусах
* @param toAngle   конечный угол в градусах
* @param freq      частота треугольников в градусах
*/
public static void drawTexturedCircle(double x, double y, double rx, double ry, double u, double v, double ru, double rv, double fromAngle, double toAngle, double freq)
{
    Tessellator tessellator = Tessellator.getInstance();
    BufferBuilder buffer = tessellator.getBuffer();

    buffer.begin(GL_TRIANGLE_FAN, DefaultVertexFormats.POSITION_TEX);
    buffer.pos(x, y, 0D).tex(u, v).endVertex();

    float from = (float) (toAngle * PI / 180);
    float to = (float) (fromAngle * PI / 180);
    float step = (float) (-freq * PI / 180);
    while (from >= to)
    {
        double cos = MathHelper.cos(from);
        double sin = MathHelper.sin(from);
        buffer.pos(x + rx * cos, y + ry * sin, 0D).tex(u + ru * cos, v + rv * sin).endVertex();
        from += step;
    }
    tessellator.draw();
}
Java:
//Вызываю так ->
float size = 59.5F / 128F;
GuiHelper.drawTexturedCircle(0, 0, 29.5F, 29.5F, size, size, size, size, 0, progressSize, 6);
Немного разобрался, чувствую придётся мне повозиться с отладчиком тьфу, профайлером, чтобы не запороть производительность, или придумать что-то другое для борьбы с пикселями и тирингом.
 
Последнее редактирование:
1,990
18
105
Такой же эффект кулдауна достигается простеньким шейдером, налепленным на обычный квад, только автоматом идёт антиалиасинг, отсутствие кучи возможных проблем (от криворукости) и возможность сделать клёвый визуал.
Подобный шейдер очень легко гуглится по запросу "draw smooth circle shader". Чтобы превратить круг в кольцо надо только добавить второй радиус. Чтобы задать начало\конец дуги - следить за углами, atan в помощь.
 
476
9
39
Позже попытаюсь сделать иначе, если, конечно, найду реализацию под майн, да и вообще как в майне в коде рендера вызывать шейдер с опр. параметрами?
 
Сверху