TL; DR
При применении шейдера к объекту UI.Image
на холсте Unity3D UNITY_MATRIX_MVP
представляется относительно средства визуализации Canvas, а не самого объекта Image, который рисуется.
Есть ли способ вычисления координат пространства клипа точки в локальном пространстве объекта Image, и не только относительно корня Canvas?
Обзор
В качестве шага предварительной обработки для шейдера я вычисляю x_min
, x_max
, y_min
и y_max
четырехугольника изображения на экране, как они появляются в этом макете:
Мой основной подход заключается в том, чтобы вручную вычислять позиции в пространстве между 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
объектов приводит к этому:
- По мере увеличения
x_min
увеличивается и красный канал. - По мере увеличения
y_min
как и зеленый канал.
Проверка максимальных значений также дает ожидаемые результаты.
Однако при тестировании того же шейдера на компоненте UI.Image
в канве,он не работает должным образом:
Несмотря на то, что объект UI.Image
(в качестве материала которого выбран шейдер) перемещается на экране,его цвет не меняется.Однако, когда в окне сцены редактора камера редактора перемещается, то цвет меняет .
Кажется, это означает, что UnityObjectToClipPos
, и, соответственно, матрица UNITY_MATRIX_MVP
зависит, относятся к родительскому объекту Canvas, а не к объекту Image внутри родительского объекта.
Вопрос
Правильно ли я полагаю, чтоUNITY_MATRIX_MVP
относится к объекту Canvas, а не к рисуемому объекту Image?Если да, есть ли другой способ получить матрицу MVP специально для объекта Image?В качестве альтернативы, есть ли какие-либо другие средства, с помощью которых можно было бы вычислить позицию в пространстве клипа точки в локальном пространстве изображения в шейдере?
- Я использую Unity 2017.1.2f1
- Включен флаг шейдера
DisableBatching