Объект-клип для шейдера Unity Canvas Image - PullRequest
0 голосов
/ 07 октября 2018

TL; DR

При применении шейдера к объекту UI.Image на холсте Unity3D UNITY_MATRIX_MVP представляется относительно средства визуализации Canvas, а не самого объекта Image, который рисуется.

Есть ли способ вычисления координат пространства клипа точки в локальном пространстве объекта Image, и не только относительно корня Canvas?


Обзор

В качестве шага предварительной обработки для шейдера я вычисляю x_min, x_max, y_min и y_max четырехугольника изображения на экране, как они появляются в этом макете:

enter image description here

Мой основной подход заключается в том, чтобы вручную вычислять позиции в пространстве между 4 углами, используя UnityObjectToClipPos (что простоиспользует встроенную матрицу преобразования UNITY_MATRIX_MVP), а затем получает значения min / max из них.

Я нашел, что это работает для SpriteRenderer или MeshRenderer компонентов, но для UI.Image компонентов на холсте UNITY_MATRIX_MVP, по-видимому, относится только к родительскому элементу холста, а не к самому объекту изображения, что означает, что я не могу использовать его для вычисления положений относительно изображения.

Подробности

Вы можете найти полный шейдер здесь: https://gist.github.com/JohannesMP/5a74fcc41d77f281a5900021c01f2356

Для данного объектаКоордината ect-space UnityObjectToClipPos используется для того, чтобы сначала получить однородную координату пространства клипа, которая затем сдвигается, чтобы быть в УФ-пространстве экрана (значения в диапазоне от 0 до 1, когда видны на экране):

inline float2 ObjToScreenUV(in float3 obj_pos)
{
    float4 clip_pos4d = UnityObjectToClipPos(obj_pos);
    float2 clip_pos2d = clip_pos4d.xy / clip_pos4d.w;
#if UNITY_UV_STARTS_AT_TOP
    return float2(1 + clip_pos2d.x, 1 - clip_pos2d.y) / 2;
#else
    return (1 + clip_pos2d) / 2;
#endif
}

Поскольку 4 вершины единичного четырехугольника тривиальны для определения в пространстве объектов (просто смещение на 0,5 по осям X / Y пространства объектов), минимальные / максимальные значения на экране могутрассчитывается следующим образом:

inline float4 GetQuadUVBounds()
{
    // 1. Get relative screen position of 4 quad corners
    float2 bl = ObjToScreenUV(float3(-0.5, -0.5, 0));
    float2 tl = ObjToScreenUV(float3(-0.5, 0.5, 0));
    float2 br = ObjToScreenUV(float3(0.5, -0.5, 0));
    float2 tr = ObjToScreenUV(float3(0.5, 0.5, 0));

    // 2. Get min/max of x and y
    float min_x = min(min(bl.x, tl.x), min(br.x, tr.x));
    float max_x = max(max(bl.x, tl.x), max(br.x, tr.x));
    float min_y = min(min(bl.y, tl.y), min(br.y, tr.y));
    float max_y = max(max(bl.y, tl.y), max(br.y, tr.y));

    return float4(min_x, min_y, max_x, max_y);
}

Обратите внимание, что в настоящее время я не собираюсь оптимизировать логику минимума / максимума.


Чтобы убедиться, чтоминимальные / максимальные значения были правильно рассчитаны, их можно использовать для красного и зеленого канала при рисовании объекта.

Например, чтобы убедиться, что x_min и y_min работают, следующий фрагментный шейдер можетиспользоваться:

half4 frag () : COLOR
{
    // Min is bounds.xy, max is bounds.zw
    float4 bounds = GetQuadUVBounds();
    return float4(bounds.xy, 0, 1);
}

Что для MeshRenderer квадов и SpriteRenderer объектов приводит к этому:

enter image description here

  • По мере увеличения x_min увеличивается и красный канал.
  • По мере увеличения y_minкак и зеленый канал.

Проверка максимальных значений также дает ожидаемые результаты.

Однако при тестировании того же шейдера на компоненте UI.Image в канве,он не работает должным образом:

enter image description here

Несмотря на то, что объект UI.Image (в качестве материала которого выбран шейдер) перемещается на экране,его цвет не меняется.Однако, когда в окне сцены редактора камера редактора перемещается, то цвет меняет .

Кажется, это означает, что UnityObjectToClipPos, и, соответственно, матрица UNITY_MATRIX_MVP зависит, относятся к родительскому объекту Canvas, а не к объекту Image внутри родительского объекта.


Вопрос

Правильно ли я полагаю, чтоUNITY_MATRIX_MVP относится к объекту Canvas, а не к рисуемому объекту Image?Если да, есть ли другой способ получить матрицу MVP специально для объекта Image?В качестве альтернативы, есть ли какие-либо другие средства, с помощью которых можно было бы вычислить позицию в пространстве клипа точки в локальном пространстве изображения в шейдере?

  • Я использую Unity 2017.1.2f1
  • Включен флаг шейдера DisableBatching
...