之前在试玩一些涂涂乐的应用,发现大多数AR扫描时,屏幕都会有一个扫描框。个人觉得这样的设计非常不错,只有当需要的识别图出现在扫描框内时才可以渲染出模型。
这两天抽出时间,做了一个简单的demo。
环境:
- unity5.2.2
- vuforia6.2.10
创建面片
在场景中新建面片Plane,调整面片的位置和大小与Imagetarget重合。
扫描框的四个屏幕坐标
首先在Canvas上创建一个Image作为扫描框,屏幕的分辨率是800*600,而Image的大小为400*300.单击canvas在右侧的Inspector,把Canvas——Render Mode设置为Screen Space—overlay。在Canvas Scaler的UI Scale Moder设置为Scale With Sceen Size。
扫描框的四个坐标,如下图所示:
那么由此得出
TopLeft_UI = new Vector2 ((Screen.width-400)*0.5f,(Screen.height-300)*0.5f+300f);
BottomLeft_UI = new Vector2 ((Screen.width-400)*0.5f,(Screen.height-300)*0.5f);
TopRight_UI = new Vector2 ((Screen.width-400)*0.5f+400f,(Screen.height-300)*0.5f+300f);
BottomRight_UI = new Vector2 ((Screen.width-400)*0.5f+400f,(Screen.height-300)*0.5f);
计算面片上的四个点的坐标
在Plane新建四个空节点,位置调整到plane的四个顶点上。
在脚本上获取到这四个点的世界坐标
public Transform TopLeft_PI; //面片左上角坐标
public Transform BottomLeft_PI;//面片左左角坐标
public Transform TopRight_PI;//面片右上角坐标
public Transform BottomRight_PI;//面片右下角坐标
在将这四个点的世界坐标转化成屏幕坐标
void Update () {
TopLeft_W_Sc = ToScreenPosition (TopLeft_PI.position);
BottomLeft_W_Sc = ToScreenPosition (BottomLeft_PI.position);
TopRight_W_Sc = ToScreenPosition (TopRight_PI.position);
BottomRight_W_Sc = ToScreenPosition (BottomRight_PI.position);
private Vector2 ToScreenPosition(Vector3 pointPos)
{
return Camera.main.WorldToScreenPoint (pointPos);
}
最后只要比较plane的四个点的屏幕坐标是否在Image里就可以了。把Plane设置成ImageTarget的子节点下,运行时就可以看到效果了。
附上完整代码:
private Vector2 TopLeft_UI; //扫描框左上角坐标
private Vector2 BottomLeft_UI;//扫描框左左角坐标
private Vector2 TopRight_UI;//扫描框右上角坐标
private Vector2 BottomRight_UI;//扫描框右下角坐标
private Vector2 TopLeft_W_Sc; //记录面片左上角的屏幕坐标
private Vector2 BottomLeft_W_Sc;//记录面片左下角的屏幕坐标
private Vector2 TopRight_W_Sc;//记录面片右上角的屏幕坐标
private Vector2 BottomRight_W_Sc;//记录面片右下角的屏幕坐标
public GameObject Plane;
public Transform TopLeft_PI; //面片左上角坐标
public Transform BottomLeft_PI;//面片左左角坐标
public Transform TopRight_PI;//面片右上角坐标
public Transform BottomRight_PI;//面片右下角坐标
public Material red;
public Material green;
// Use this for initialization
void Start ()
{
TopLeft_UI = new Vector2 ((Screen.width-400)*0.5f,(Screen.height-300)*0.5f+300f);
BottomLeft_UI = new Vector2 ((Screen.width-400)*0.5f,(Screen.height-300)*0.5f);
TopRight_UI = new Vector2 ((Screen.width-400)*0.5f+400f,(Screen.height-300)*0.5f+300f);
BottomRight_UI = new Vector2 ((Screen.width-400)*0.5f+400f,(Screen.height-300)*0.5f);
}
// Update is called once per frame
void Update () {
TopLeft_W_Sc = ToScreenPosition (TopLeft_PI.position);
BottomLeft_W_Sc = ToScreenPosition (BottomLeft_PI.position);
TopRight_W_Sc = ToScreenPosition (TopRight_PI.position);
BottomRight_W_Sc = ToScreenPosition (BottomRight_PI.position);
if (BeyondOut()) //是否超出扫描框的范围{
Plane.GetComponent<MeshRenderer> ().material = green;
} else {
Plane.GetComponent<MeshRenderer> ().material = red;
}
}
private Vector2 ToScreenPosition(Vector3 pointPos)
{
return Camera.main.WorldToScreenPoint (pointPos);
}
private bool BeyondOut()
{
return TopLeft_W_Sc.x > TopLeft_UI.x && TopLeft_W_Sc.y < TopLeft_UI.y && BottomLeft_W_Sc.x > BottomLeft_UI.x &&
BottomLeft_W_Sc.y > BottomLeft_UI.y && TopRight_W_Sc.x < TopRight_UI.x && TopRight_W_Sc.y < TopRight_UI.y &&
BottomRight_W_Sc.x < BottomRight_UI.x && BottomRight_W_Sc.y > BottomRight_UI.y ? true : false;
}
在扫描框内:
没有完全在扫描框内: