需求:
在使用Unity进行Gis开发时,希望一些目标以图标的形式显示,显示效果和UI图标跟随一致,并且当目标移动时,图标也需要继续跟随。
解决方案1:
以UI跟随的方式进行开发。将目标的三维空间坐标转为屏幕坐标赋值给UI。
这种方案效果满足,但是因为UI图标的贴图不一致,导致无法触发合批,一旦UI数量一多,就会极大的影响性能。最终,该方案不可行。
解决方案2:
使用Mesh代替UI图标,采用GPUInstance来生成图标,使用Job进行图标位置计算,开发脚本,将Mesh图标放置到相机裁面中。最终完美解决。
即有了和UI相同的效果显示,又有了高性能。
效果截图如下:
红色为UI图标,彩色为mesh图标。
核心脚本:
using System;
using UnityEngine;
public class MeshCanvas : MonoBehaviour
{
/// <summary>
/// 计算逻辑
/// canvas scale基于高度变化进行计算
/// base = 1.15936f
/// 公式:scale = base/(screen height/100)*(canvas distance/100)
/// </summary>
public static float CanvasScale = 1.0f;
/// <summary>
/// 当分辨率变换时,触发的回调
/// </summary>
public static Action onMeshCanvasChanged;
/// <summary>
/// 固定缩放常数
/// </summary>
public static float BaseScale = 1.15936f;
public static float UIDistance = 100.0f;
public float StartUIDistance = 100;
private void Start()
{
onMeshCanvasChanged += OnMeshCanvasChanged;
}
private void Update()
{
//实时计算
float _caS = BaseScale / (Screen.height / 100.0f) * (UIDistance / 100.0f) ;
if(_caS != CanvasScale)
{
CanvasScale = _caS;
onMeshCanvasChanged?.Invoke();
}
UIDistance = StartUIDistance;
}
/// <summary>
/// 获取Mesh UI元素在此Canvas下的缩放比例
/// </summary>
/// <param name="uiWidth"></param>
/// <param name="uiHeight"></param>
/// <returns></returns>
public static Vector3 GetUIItemScaleV3(float uiWidth,float uiHeight)
{
return new Vector3(uiWidth * CanvasScale/(CanvasScale * Screen.width)*(Screen.height/1080.0f), uiHeight * CanvasScale/(CanvasScale * Screen.height) * (Screen.height / 1080.0f), 1) ;
}
/// <summary>
/// 传入计算后的屏幕坐标,返回对象在此Canvas下的坐标
/// UI坐标和Canvas下的坐标都是采用锚点在左下角的规则进行计算,如果锚点在其他地方,需要自己更改计算方式
/// </summary>
/// <param name="screenPos"></param>
/// <returns></returns>
public static Vector3 GetUIItemPosV3(Vector2 screenPos)
{
return new Vector3((screenPos.x * (Screen.height / 1080.0f) / Screen.width - 0.5f), (screenPos.y * (Screen.height / 1080.0f) / Screen.height - 0.5f), 0);
}
private void OnMeshCanvasChanged()
{
transform.localScale = new Vector3(CanvasScale * Screen.width, CanvasScale * Screen.height, 1);
transform.localPosition = new Vector3(0, 0, UIDistance);
}
private void OnDestroy()
{
onMeshCanvasChanged -= OnMeshCanvasChanged;
}
}