将着色器应用于Unity3D画布中的UI.Image
对象时,UNITY_MATRIX_MVP
似乎是相对于Canvas渲染器的,而不是相对于Image对象本身的绘制。
有没有一种方法可以计算Image对象本地空间中某个点的剪辑空间坐标,而不仅仅是相对于Canvas根?
作为着色器的预处理步骤,我正在计算屏幕上出现的图像四边形的x_min
,x_max
,y_min
和y_max
这个样机:
我的基本方法是使用UnityObjectToClipPos
(仅使用内置转换矩阵UNITY_MATRIX_MVP
)手动计算4个角的剪贴空间位置,然后获取最小值/最大值从那些。
我发现这适用于SpriteRenderer
或MeshRenderer
组件,但是对于画布UI.Image
中的UNITY_MATRIX_MVP
组件似乎仅相对于画布父对象,并且不是图像对象本身,这意味着我不能用它来计算相对于图像的位置。
您可以在此处找到完整的着色器:https://gist.github.com/JohannesMP/5a74fcc41d77f281a5900021c01f2356
对于给定的对象空间坐标,UnityObjectToClipPos
首先用于获取齐整的剪辑空间坐标,然后将其移至屏幕UV空间中(在屏幕上可见时,值范围从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个顶点很容易在对象空间中定义(在对象空间X / Y轴上仅偏移0.5),因此屏幕上的最小值/最大值可以按以下方式计算:>
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 Parent对象有关,而不是与Parent内部的Image对象有关。
我是否以UNITY_MATRIX_MVP
是相对于画布对象而不是要绘制的Image对象为假设进行更正?如果是这样,还有另一种方法来获取专门用于Image对象的MVP矩阵吗?另外,还有其他方法可以在着色器中计算点在图像局部空间中的Clip-space位置吗?
DisableBatching
着色器标志已启用