Войти
ПрограммированиеФорумГрафика

[Unity3D] Делаем нормальный инструментарий для линий без трололо и бесплатно.

Страницы: 1 2 3 4 Следующая »
#0

Я тут набросал немного кода в процессе беседы и подумал почему бы и нет. Цели как таковой нет, но есть предположения того что туда можно еще добавить помимо самого рисования линий.

По функционалу отрисовки линий:
- сглаживание углов при рисовании ломаной линии.
- формирование одного меша из примитивов.
- базовые примитивы: линии, круги, полигоны, кривые.
- возможность последующего текстурирования.
- толщина линии с учетом глубины или без, размер в глобальных координатах или экранных, ориентировано экрану.
- градиет цвета и толщины по сегментам или по длине.

Дополнительный функционал:
- редактор меша, линий и отдельных примитивов.
- конвертация обычного полигонального меша в линии.

Думаю добавить это в assetstore бесплатно. Или если кто захочет из желающих сделает это сам.

Какие будут идеи, пожелания, свои решения, правки?

LineTool_2017_V0003.unitypackage
LineTool_2017_V0004.unitypackage
LineTool_2017_V0005.unitypackage
LineTool_2017_V0006.unitypackage

linerender_001 | [Unity3D] Делаем нормальный инструментарий для линий без трололо и бесплатно. linerender_006 | [Unity3D] Делаем нормальный инструментарий для линий без трололо и бесплатно.
linerender_004 | [Unity3D] Делаем нормальный инструментарий для линий без трололо и бесплатно. linerender_007 | [Unity3D] Делаем нормальный инструментарий для линий без трололо и бесплатно.

9 янв. 2019, 12:59 (Правка: 15 янв. 2019, 0:46)

#1

LR_ND_NUV - Базовый шейдер без каких то приблуд и без глубины
LR_NUV - Базовый шейдер c глубиной
LR_ND_T - Базовый шейдер c глубиной и смешиванием по альфа каналу
LR_T - Базовый шейдер c глубиной и смешиванием по альфа каналу

+ LR_ND_NUV
+ LR_NUV
+ LR_ND_T
+ LR_T

9 янв. 2019, 12:59 (Правка: 14 янв. 2019, 21:09)

#2
+ LineMeshFunctions

9 янв. 2019, 13:54 (Правка: 10 янв. 2019, 1:13)

#3

foxes
> Какие будут идеи, пожелания
безьешки энного порядка c тулзовинками :)

9 янв. 2019, 19:12

#4

напишите лучше что нибудь полезное, делающее шаг в сторону реализма, красивостей и перфоманса) я б даже немного профинансировал, если че-то попутное. вроде грамотных пациков тут хватает, вон тот же alexxz но ништяки мало кто старается пилить.

толи все заняты в казуальном игрострое который приносит некоторый доход и влом отвлекаться на сомнительные затеи, толи наоборот заняты какой-то хренью отдаленной от игростроя.

9 янв. 2019, 20:01

#5

Mira
> но ништяки мало кто старается пилить.
У меня идей ноль, куда не кинь уже все есть, остается только заоптимизировать или для себя любимого завелосипедить.

9 янв. 2019, 20:11 (Правка: 20:41)

#6

Есть идея для ассета, как раз связанная с линиями.

Когда занимался этой штукой, очень не хватало (и сейчас периодически хочется) легковесной рисовалки линий, которую можно было бы использовать в билдах в интерактивном стиле, как Debug/Gizmos/Handles.DrawLine. Вот прям щас надо показать линию, вызываешь одной строчкой DrawLine и линия видна, перестаёшь вызывать ― пропадает. Ну и желательно в комплекте с линиями простые фигурки из них, разные стрелочки, кружочки, bounding-боксы... С упором не на красивости, а на удобство и скорость.

Debug/Gizmos/Handles в билде недоступны, а LineRenderer и Vectrosity тяжелые. LineRenderer'ы надо создавать, как-то их все отслеживать, чтобы обновлять координаты вершин, пока линия нужна, и уничтожать, когда не нужна. Я пользовался Vectrosity. Он не рассчитан на такое использование, но хотя бы проще и умеет уничтожать собственные линии по таймауту. Ставил линиям минимальный таймаут, чтобы в следующем кадре их уже не было:

    public static void DrawLine(Vector3 start, Vector3 end, Color color, float width = 3)
    {
        if (start == end)
        {
            return;
        }

        var points = new List<Vector3> {start, end};
        var line = new VectorLine("line", points, width);
        line.SetColor(color);
        line.Draw3DAuto(.0001f);
    }

Vectrosity такое издевательство не нравилось и он тормозил. Жить можно, но неприятно.

По аналогии, ещё хотелось то же для спрайтов: вызваешь DrawIcon(worldPosition, iconId, color, size) и спрайт видно, перестал вызывать ― пропал.

10 янв. 2019, 0:21 (Правка: 0:30)

#7

alexzzzz
Тут есть вариант, например:
- Если тебе нужно чтобы Gizmos отображались в игровом окне то там есть кнопочка Gizmos.
- Если это билд и нужен какой то легкий дебаг то GL.Begin(GL.LINES) для простых линий.
- Как вариант этой тулзы то можно добавить Graphics.DrawMesh.

Пока будет громоздкий вариант, но думаю для него можно придумать обертку.
Зато такой вариант можно вызывать откуда угодно.

LineMeshFunctions.Counter counter = LineMeshFunctions.Counter.start;
LineMeshFunctions.LineSize(ref counter);

LineMeshFunctions.MeshTmp meshTmp = new LineMeshFunctions.MeshTmp(ref counter);
counter = LineMeshFunctions.Counter.start;

LineMeshFunctions.Line(ref meshTmp, start, end, 8.0f, Color.white, ref counter);
Graphics.DrawMesh(meshTmp.CreateMesh(), Vector3.zero, Quaternion.identity, new Material(Shader.Find("LinesTool/LR_NUV")), 0)

10 янв. 2019, 0:43 (Правка: 12:03)

#8

foxes
GL.Begin(GL.LINES) просит много лишних телодвижений ради одной линии и работает только из OnPostRender. Забыл про это, вызвал сейчас из Update ― 2018.3.0f2 упал два раза подряд.

Хочется простой в использовании, но продвинутый Gizmos.DrawXXX, с готовыми примитивами на разные случаи жизни, и чтоб в билдах работал. Понятно, что есть разные варианты как организовать, но руки не доходят. Хочется не собрать на коленке, а сделать хорошо и удобно. Продумать способы использования, отточить, причесать и оформить, чтобы было приятно пользоваться и чтобы никогда к этой теме больше не возвращаться.

10 янв. 2019, 1:18

#9

alexzzzz
У меня пока лимит во втором посте на количество символов кончился так что я туда эту обертку не запихаю, надо куда то выложить.

Я запустил то что я тебе написал выше в Update, по профайлеру 0.07mc.

Ну и какие будут идеи, дополнять данный класс LineMeshFunctions или создать отдельный файл LineGizmos. Насколько это будет легковесно? Два шейдера и два C# кода. Или совсем все с ноля?

10 янв. 2019, 1:28 (Правка: 2:50)

#10

На всякий пожарный копирую сюда идею оптимизации vectorosity.

alexzzzz
> Для чего они нужны, не вникал.
Проекция координат, из мировых в экранные и наоборот. Такие расчеты хорошо переносятся в шейдер.
alexzzzz
> Было бы интересно заменить вызовы этих методов явным кодом на C# и посмотреть,
> что будет.
Там умножение на матрицу проекции projectionMatrix и матрицу камеры worldToCameraMatrix (прямую и обратную) и масштабирование по разрешению экрана. Просто выведи результат оригинала для Camera.transform.forward + Camera.transform.position и там видно будет чем заменить.
Допустим если разрешение экрана 1191x614 (как у меня в отладчике показывает) то результат получается (595.5, 307.0, 1.0).

для Camera.WorldToScreenPoint можно такую формулу использовать

        Vector4 v = (Camera.main.projectionMatrix * Camera.main.worldToCameraMatrix) * new Vector4(tv.x, tv.y, tv.z, 1.0f);
        v.x = (v.x/v.z + 1.0f) * Camera.main.pixelWidth * 0.5f;
        v.y = (v.y/v.z + 1.0f) * Camera.main.pixelHeight * 0.5f;

для Camera.ScreenToWorldPoint получилось такое

        Vector4 tv.x = (v.x * (2.0f / Camera.main.pixelWidth) - 1.0f) * v.z;
        tv.y = (v.y * (2.0f / Camera.main.pixelHeight) - 1.0f) * v.z;
        tv.z = v.z;
        tv.w = v.z;
        tv = (Camera.main.projectionMatrix * Camera.main.worldToCameraMatrix).inverse * tv;

Думаю IntersectAndDoSkip можно убрать для теста. А вот это за скобки цикла, и два цикла сделать по условию.

if (useTransformMatrix) {
  for (int i = start; i < end; i += add) {
    p1 = thisMatrix.MultiplyPoint3x4 (m_points3[i]);
    p2 = thisMatrix.MultiplyPoint3x4 (m_points3[i+1]);
    ...
  }
}
else {
  for (int i = start; i < end; i += add) {
    p1 = m_points3[i];
    p2 = m_points3[i+1];
    ...
  }
}

thisLine = px / (float)System.Math.Sqrt (px.x * px.x + px.y * px.y);
Тут можно попробовать стандартную фишку
  [StructLayout(LayoutKind.Explicit)]
  private struct FloatIntUnion
  {
    [FieldOffset(0)]
    public float f;

    [FieldOffset(0)]
    public int tmp;
  }

  public static float Sqrt2(float z)
  {
      if (z == 0) return 0;
      FloatIntUnion u;
      u.tmp = 0;
      float xhalf = 0.5f * z;
      u.f = z;
      u.tmp = 0x5f375a86 - (u.tmp >> 1);
      u.f = u.f * (1.5f - xhalf * u.f * u.f);
      return u.f * z;
  }

thisLine = px * (float)Sqrt2 (px.x * px.x + px.y * px.y);

Результат тестов от alexzzzz

lines | [Unity3D] Делаем нормальный инструментарий для линий без трололо и бесплатно.

alexzzzz
> Справа оригинальный код Вектросити (~40мс), слева он же с заменой ScreenToWorldPoint и WorldToScreenPoint на C# аналоги, как их привел foxes (~20мс). Одна непрерывная линия из 15 тысяч контрольных точек.

10 янв. 2019, 11:42 (Правка: 12:34)

#11

foxes
> Ну и какие будут идеи, дополнять данный класс LineMeshFunctions или создать
> отдельный файл LineGizmos. Насколько это будет легковесно? Два шейдера и два C#
> кода. Или совсем все с ноля?

Если на мои вкус и потребности (простота, интерактивный стиль использования), то по минимуму должно быть так:

1. Один публичный статический класс со всеми методами, которые предлагаются к использованию. Например:
xxx.DrawLine(start, end, color, thickness)
xxx.DrawArrow(start, end, thickness)
xxx.DrawSphere(center, size, color, thickness)
xxx.DrawBox(center, size, color, thickness)
xxx.DrawBounds(bounds, color, thickness)
xxx.DrawCircle(center, normal, radius, color, thickness)

2. Желательно, чтобы имя класса находилось интеллисенсом с двух-трёх букв, но не мешало с двух-трёх букв находить другие часто используемые имена. Gizmos ― хороший вариант, но занят. LineGizmos ― плохой: не ищется ни по одному из вариантов: lin, lg, lig, giz.

3.  Цвет можно указывать явно. Если не указан, берётся цвет по умолчанию, который можно задать заранее, аналогично Gizmos.color.

4. С толщиной так же, как с цветом. Измеряться должна в экранных единицах.

5. Все кишки, кроме одного публичного класса, спрятаны. Неважно сколько там кода. Важно, чтобы оно всё делало само:
- никаких лишних ручных вызовов,
- никаких видимых объектов в иерархии,
- никаких ресурсов, которые надо добавить в проект, что работало.

6. Оформлено в виде пакета (думаю, пора начинать к этому привыкать), чтобы положить в папку Packages и оно нигде больше не отсвечивало.

7. Банальное: не спамило постоянными аллокациями, не особо тормозило.

--
Но это мои предпочтения. Не факт, что их кто-то разделяет.

10 янв. 2019, 22:53 (Правка: 22:55)

#12

alexzzzz
Такие дела:
>1.
Это возможно, но придется еще то что в коробке туда же положить. Есть такой вариант что будут и другие классы но уже базирующиеся на данном. По необходимости можно все выкинуть и оставить один данный. Второй момент без шейдеров не обойтись.

>DrawArrow
Думаю будут сложности по форме, нужен либо какой то канон либо через текстуру либо задать статичный полигон с формой, который можно отрисовать через DrawPolygon.

У меня сейчас есть в данном классе дополнительные функции (line circle...), которые только генерят примитивы, а потом по Draw формируют полный меш и посылают на отрисовку, остальные DrawXXX рисуют сразу, но генерят отдельные меши - это много аллокации. к вопросу 7.
>7.
От аллокаций к сожалению полностью не избавиться только спрятать в какой нибудь DLL, тут либо вершинный буфер придется постоянно увеличивать, либо все параметры примитивов запоминать (как это сейчас). Так что текущая реализация с меньшей болью. Еще есть вариант сделать свой массив с выделением памяти по логарифму и сделать union структуру. Ни чего другого пока не придумаю.
>2.
GizmosLine, GizmosTool - будет мешаться думаю. Пока вариантов нет... GLine, LTool, GTool. Можешь переименовать и потестит на свое предпочтение.
>3.
Gizmos.color я не смогу задать через значения метода по умолчанию тут только с перегрузкой.
>4. Измеряться должна в экранных единицах.
Сейчас 1=экранный пиксель. Но с учетом глубины это так только на единичном расстоянии от экрана. За счет материала (шейдера) также будет фиксированный вариант (он есть).
>5.
Без шейдеров это все не реализуемо в данном виде. Если только не делать чистый GL_LINE через mesh, будет очень корявая геометрия и толщину не установить. Тогда это все можно будет сделать отдельным самостоятельным классом и при необходимости мачить все остальное за ненадобностью.
>6.
Это я так понял не LineTool в корне, а с начало Packages. Я таких вариантов в других пакетах не наблюдал.

Что из этого приоритетней?

10 янв. 2019, 23:30 (Правка: 11 янв. 2019, 1:24)

#13

foxes
>1.
>Это возможно, но придется еще то что в коробке туда же положить.
Я не про запихать всё в один класс или файл, а про то чтобы всё публичное было собрано в одном месте. Пусть там ещё хоть сто классов и двести файлов, только непубличных. Чтобы был чёрный ящик с простым понятным интерфейсом.

Ну вот как штатный Gizmos. Никому не интересно, как и чем он рисует. Если надо что-то нарисовать, просто пишешь Gizmos. и там внутри всё есть.

А в Vectrosity есть VectorLine, VectorManager, ещё что-то есть, и как-то сходу не особо понятно, каким из доступных способов лучше рисовать.

>DrawArrow
Любая примитивная стрелочка. Часто хочется стрелочку. Ценность в том, чтобы можно было рисовать то, что требуется в данный момент, а не что проще.

>3.
>Gizmos.color я не смогу задать

Я про Gizmos только как образец для подражания. Например, чтобы можно было и так:

xxx.DrawLine(a, b, Color.green, 2f);
и так:
xxx.color = Color.green;
xxx.thickness = 2f;
xxx.DrawLine(a, b);
xxx.DrawLine(b, c);
xxx.DrawLine(c, d);
xxx.DrawLine(d, a);

>5. Все кишки, кроме одного публичного класса, спрятаны.
>Без шейдеров это все не реализуемо в данном виде.

Я не против шейдеров. Какая разница, как рисуется, если оно рисуется. Но вообще-то можно и без них если хочется или требуется:

using UnityEngine;

internal class Foo : MonoBehaviour
{
    [RuntimeInitializeOnLoadMethod]
    private static void Initialize()
    {
        var go = new GameObject("Foo");
        go.hideFlags = HideFlags.HideAndDontSave;
        DontDestroyOnLoad(go);
        go.AddComponent<Foo>();
    }

    private void Update()
    {
        Graphics.Draw...
    }
}

Объект создаёт сам себя и в иерархии не мешается.

>6.
>Это я так понял не LineTool в корне, а с начало Packages. Я таких вариантов в других пакетах не наблюдал.

Если интересно, наподключай к проекту Unity каких-нибудь доступных пакетов через Package Manager, посмотри как они устроены.

+ Показать

Пакеты в Unity пока в стадии обкатки и отладки. Официальной поддержки сторонних пакетов ещё нет и нет требований к ним. Но к этому идёт. Уже сейчас можно хранить в одном месте у себя локально папки со своими пакетами и подключать их к разным проектам через Package Manager кнопочкой «Add package from disk». Чтобы не плодить копии одного и того же по разным проектам и потом не вспоминать, в каких лежит старая версия, в каких более свежая.

>Что из этого приоритетней?
Пять лет не доходили руки этим заняться. Если ты займёшься, могу ещё столько же подождать.

Пункт 6 ― явная блажь. Конкретный список примитивов для пункта 1 и их реализацию можно оставить на потом.

11 янв. 2019, 1:48 (Правка: 2:18)

#14

alexzzzz
> Я не про запихать всё в один класс или файл, а про то чтобы всё публичное было
> собрано в одном месте. Пусть там ещё хоть сто классов и двести файлов, только
> непубличных. Чтобы был чёрный ящик с простым понятным интерфейсом.
В пакете будет много плюшек разно целевых, по этому так не получиться.
alexzzzz
> Я про Gizmos
Да это перегрузом как я и сказал.

В остальном тогда я ничего менять не буду, там это уже все есть, только допилить и причесать.
GLine для этих целей я уже обозначил, легко находиться.

11 янв. 2019, 2:26

Страницы: 1 2 3 4 Следующая »
ПрограммированиеФорумГрафика