关于Canvas使用世界坐标即使用3D的UI时的排序问题

目前基于Unity2021.3版本发现的问题是3D的UI虽然空间上位于三维的位置,但是UI之间的渲染的遮挡关系不是按照距离摄像机的远近进行的,导致距离摄像机远的UI有可能遮挡距离摄像机近的UI。由于渲染按照子物体排序进行的,即子物体编号靠后的后渲染,而渲染时又不考虑深度,所以就出现了上述问题,我尝试给UI使用自定义ShaderGraph的Material,其中的ShaderGraph里面使用了UnlitSprite类型,或者使用Unlit类型的同时强制写入深度,并在测试深度中选择了Less Equal。然而一通折腾下来似乎并没有什么作用。不过我还是觉得在Shader方面下手应该是比较好的解决方法,亦或许应该配合渲染管线做一些什么工作,但是目前对渲染管线的理解和开发依旧处于幼稚阶段,所以还搞不定,有高人愿意不吝赐教可以留言,这里先行谢过。

目前的解决办法是给UI按照距离摄像机的远近进行排序。这里面做了两个优化,一个是用距离的平方代替距离进行比较,另一个是通过点乘运算测试UI是否位于摄像机之前,只有在摄像机前面的UI才排序,位于摄像机后面的不考虑。

基于上面的想法,给需要培训的UI的组件添加了sqrtDistToCam浮点属性和inFrontOfCam布尔属性,代码参考如下:

//这个ZJNumberPlate列表里面保存需要排序的UI的组件,就是在摄像机前面的UI组件。//虽然在摄像机的前面也未必在摄像机的视锥体里面,但是检查是否在摄像机视锥体里面这个以后考虑。
List<ZJNumberPlate> listPlateForOrder = new List<ZJNumberPlate>();
voidUpdatePlanteInsSilder()
{
    //需要排序的组件位于numberPlateIns数组里面,其类型是ZJNumberPlate。//这个ZJNumberPlate组件里面包含了inFrontOfCam和sqrtDistToCam属性。
	if (numberPlateIns == null || numberPlateIns.Length == 0) return;
	//
	listPlateForOrder.Clear();
	Transform tranCam = Camera.main.transform;
	for (int i = 0; i < numberPlateIns.Length; i++)
	{
        //首先通过UpdateParamToCam方法更新了inFrontOfCam和sqrtDistToCam属性的值。
		numberPlateIns[i].UpdateParamToCam(tranCam);
        //不在摄像机前面的直接忽略。
		if (!numberPlateIns[i].inFrontOfCam) continue;
		//通过while循环找到UI插入到ZJNumberPlate列表里面的位置。
		int j = 0;
		while (j < listPlateForOrder.Count)
		{
			if (numberPlateIns[i].sqrtDistToCam < listPlateForOrder[j].sqrtDistToCam)
			{
				j++;
				continue;
			}
			break;
		}
		//在找到的位置将UI插入到ZJNumberPlate列表里面。
		listPlateForOrder.Insert(j, numberPlateIns[i]);
	}
    //凡是在ZJNumberPlate列表里面的UI组件都按照由远及近的顺序排在兄弟关系前面。
	for(int i = 0; i < listPlateForOrder.Count; i++)
	{
		listPlateForOrder[i].rectTran.SetSiblingIndex(i);
	}
}

猜你喜欢

转载自blog.csdn.net/ttod/article/details/129360537
今日推荐