【Unity3d學習】AR技術的簡單瞭解

寫在前面

AR簡介

增強現實(Argumented Reality (AR))是一種將真實世界信息和虛擬世界信息“無縫”集成的新技術,是把原本在現實世界的一定時間空間範圍內很難體驗到的實體信息(視覺信息,聲音,味道,觸覺等),通過電腦等科學技術,模擬仿真後再疊加,將虛擬的信息應用到真實世界,被人類感官所感知,從而達到超越現實的感官體驗。
混合現實(Mixed reality (MR)) 有時被稱爲超現實(hybrid reality),是真實和虛擬世界的合併,產生新的可視化環境,物理和數字對象實時共存且在其中交互。混合現實不僅發生在物理世界或虛擬世界中,而是融合了現實和虛擬現實,通過身臨其境的技術包含增強現實和增強虛擬。
實際應用中,我們對 AR 和 MR 技術通常是不區分,簡稱 AR/MR 技術。

Vuforia使用

Vuforia一直是開發者最青睞的AR SDK,衆多的功能以及高質量的識別技術,良好的跨平臺性和兼容性,兼容目前主流的PC,Android,IOS平臺。 Vuforia 引擎支持 Unity 引擎以及三個主要平臺:iOS、Android 和 UWP (Windows)。所以它收到許多開發者的喜愛。

Unity內嵌的Vuforia模塊

使用Unity2017以上版本就可以在安裝的時候選擇添加Vuforia的模塊,從而能夠在Unity編輯器上使用Vuforia的組件。
在這裏插入圖片描述
或者是從官網中下載(鏈接地址)相應的安裝包。
在這裏插入圖片描述
對於2019版本,有一點坑就是需要導入相應的package,然後該包中含有一個自動執行的腳本,會將所需要安裝包的鏈接加入到Unity2019版的包管理器中,然後自動從鏈接中下載所需要的資源,但是由於服務器的國外的,所以下載速度非常慢,會造成卡住不動的現象。
所以我安裝了2018版的Unity來使用。

安裝完成之後,需要在Unity中打開相應的設置:
在這裏插入圖片描述
在這裏插入圖片描述
然後就可以在對象樹中添加相應的AR組件了:
在這裏插入圖片描述

使用Vuforia的AR組件

到官網(鏈接)註冊一個賬號,然後添加一個License Key。
在這裏插入圖片描述

然後添加數據庫:
在這裏插入圖片描述
並且添加一張圖片,作爲識別的目標:
在這裏插入圖片描述
注意圖片的識別度,星越多,越容易識別。
在這裏插入圖片描述
把數據庫下載下來:
在這裏插入圖片描述

使用AR Camera組件

進入Unity,設置playsetting:
在這裏插入圖片描述
在這裏插入圖片描述

然後就可以在Unity中添加Vuforia的AR組件了:
在這裏插入圖片描述

添加AR Camera,刪除原有的Camera。然後進行一點設置:
在這裏插入圖片描述

添加License和database:
在這裏插入圖片描述
數據庫的添加通過導入之前我們下載的包來實現。

在場景中添加Image,就會在結構樹中出現一個ImageTarget的對象。將準備好的模型添加在上面,並且調整一下位置:
在這裏插入圖片描述
在這裏插入圖片描述

運行,然後攝像頭對着圖片,就能夠顯示相應的模型了:
在這裏插入圖片描述

添加虛擬按鈕

在Image Target 的 Inspecter中找到添加虛擬按鈕的選項:
在這裏插入圖片描述

給虛擬按鈕掛載一下代碼:

using UnityEngine;
using Vuforia;

public class VirtualButtonEventHandler : MonoBehaviour, IVirtualButtonEventHandler {
    public GameObject vb;
    public Animator ani;

    void Start() {
        VirtualButtonBehaviour vbb = vb.GetComponent<VirtualButtonBehaviour>();
        if(vbb){
            vbb.RegisterEventHandler(this);
        }
    }

    public void OnButtonPressed(VirtualButtonBehaviour vb) {
        ani.SetTrigger("Take Off");
        ani.SetBool("onPress", true);
        Debug.Log("Pressed!");
    }

    public void OnButtonReleased(VirtualButtonBehaviour vb) {
        ani.SetTrigger("Land");
        ani.SetBool("onPress", false);
        Debug.Log("Released!");
    }
}

其中改變了模型的動畫,動畫狀態轉換圖如下:
在這裏插入圖片描述

然後爲了顯示button,可以在button的位置加一個平面對象(Plane),使其能夠顯示在屏幕中。
觸碰虛擬按鈕(需要完全覆蓋),就能發現模型能夠動起來。
項目地址:傳送門
在這裏插入圖片描述

AR小遊戲製作

利用AR組件製作一個簡單的躲避球小遊戲:

玩家控制角色(天藍色小球),向上移動(會自然下落),從而躲避衝來的障礙小球。
碰到障礙則遊戲失敗

首先還是一樣用到Vuforia的圖像數據庫,這裏直接用之前的龍紋圖片。
然後將我們控制的角色(一個天藍色小球)添加爲ImageTarget的子對象,就能夠隨着圖像的識別而顯示出來,基本佈局很簡單,上面已經有過相關的實踐了。
直接來遊戲設計部分:
首先需要有各種障礙出現,來躲避。所以這裏可以給這些障礙製成預製體,並且掛載一個控制移動的腳本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move : MonoBehaviour
{
    public Controller controller;
    public float speed = 9;
    Vector3 target;
    float time = 0;
    bool flag = true;
    // Start is called before the first frame update
    void Start()
    {
        GameObject tmp = GameObject.Find("Bird");
        target = 3*tmp.transform.position - 2*this.transform.position;
        controller = Director.getInstance().currentSceneController as Controller;
    }

    // Update is called once per frame
    void Update()
    {
        if (controller.getState() == 0) return;
        if (time > 5) {
            controller.addScore();
            flag = false;
            Debug.Log("score: " + controller.getScore());
            Destroy(this.gameObject);
            return;
        }
        time += Time.deltaTime;

        this.transform.position = Vector3.MoveTowards(transform.position,target,Time.deltaTime * speed);
        // this.transform.Translate(target*speed*Time.deltaTime);
        
    }
}

就是朝着我們控制目標的方向移動,但是這不是實時追蹤,而只是設定一個初始目標位置的方向。並且設定一段時間後就消失。

而這裏,場景控制器的作用就是不斷地拋出障礙:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Controller : MonoBehaviour, SceneController, Interaction{

    public PipeFactory pipeFactory;
    public int score = 0;
    float time = 0;
    public int state = 1;
    public void loadResources() {

    }
    private void Start()
    {
        score = 0;
        pipeFactory =  this.gameObject.AddComponent<PipeFactory>();
        Director director = Director.getInstance();
        director.currentSceneController = this;
    }
    private void Update() {
        if (state == 1) {
            GameObject tmp = null;
            if (time > 3)
            {   
                tmp = pipeFactory.getPipe();
                time = 0;
            }
            else
            {
                time += Time.deltaTime;
            }
        }
            
    }

    public int getState() {
        return state;
    }

    public void addScore() {
        score += 1;
    }

    public int getScore() {
        return score;
    }
}

然後給我們的主角,添加一個剛體屬性,使其能夠受到重力作用。還要掛載一個控制腳本,這裏暫時用鼠標點擊來觸發向上的動作:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Fly : MonoBehaviour
{
    public float speed = 5.5f;
    private Rigidbody rig;
    public Controller controller;
    // Start is called before the first frame update
    void Start()
    {
        rig = GetComponent<Rigidbody>();
        controller = Director.getInstance().currentSceneController as Controller;
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        if (controller == null) {
            controller = Director.getInstance().currentSceneController as Controller;
            return;
        }
        if (controller.getState() == 0) {
            this.transform.localPosition = Vector3.zero;
            rig.useGravity = false;
            return;
        }
        if (this.transform.position.y < -5f) {
            rig.useGravity = false;
            rig.velocity = Vector3.zero;
        }
        else {
            rig.useGravity = true;
        }
        if(Input.GetButtonDown("Fire1")) {
            rig.velocity = Vector3.up * speed;
        }
    }
}

添加碰撞檢測,如果碰到了障礙就遊戲失敗:

private void OnCollisionEnter(Collision other)
{
     Controller controller = Director.getInstance().currentSceneController as Controller;
     controller.state = 0;
     Destroy(other.gameObject);
 }

使用工廠進行障礙物的創建:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PipeFactory: MonoBehaviour{
    List<GameObject> activeList = new List<GameObject>();
    List<GameObject> freeList = new List<GameObject>();

    public GameObject getPipe() {
        GameObject pipe = null;
        GameObject img = GameObject.Find("ImageTarget");
        if (img != null) {
            if (freeList.Count > 0)
            {
                pipe = freeList[0].gameObject;
                freeList.Remove(freeList[0]);
                pipe.transform.Rotate(0,0,0);
            }
            else
            {
                pipe = Instantiate(Resources.Load<GameObject>("Prefabs/Pipe"), new Vector3(8, Random.Range(-3,3),0), Quaternion.identity);
            }
            pipe.SetActive(true);
            pipe.transform.parent = img.transform;
            float x = Random.Range(-1,1) > 0 ? 0.5333f : -0.5333f;
            pipe.transform.localPosition = new Vector3(x, Random.Range(-1f,1f),0);
        }

        
        return pipe;
    }

    public void free(GameObject pipe) {
        GameObject tmp = null;
        foreach (GameObject i in activeList)
        {
            if (pipe.GetInstanceID() == i.gameObject.GetInstanceID())
            {
                tmp = i;
                break;
            }
        }
        if (tmp != null) {
            tmp.gameObject.SetActive(false);
            freeList.Add(tmp);
            activeList.Remove(tmp);
        }
    }
}

使用虛擬按鈕,添加相應的事件:
使得一直按着按鈕的時候,小球會一直向上運動。

using UnityEngine;
using Vuforia;

public class VirtualButtonEventHandler : MonoBehaviour, IVirtualButtonEventHandler {
    public GameObject vb;
    public GameObject ball;

    public float speed = 7f;
    private Rigidbody rig;
    public Controller controller;
    bool isPressed = false;

    void Start() {
        VirtualButtonBehaviour vbb = vb.GetComponent<VirtualButtonBehaviour>();
        if(vbb){
            vbb.RegisterEventHandler(this);
        }
        rig = ball.GetComponent<Rigidbody>();
        controller = Director.getInstance().currentSceneController as Controller;
    }

    public void OnButtonPressed(VirtualButtonBehaviour vb) {
        if (controller == null) {
            controller = Director.getInstance().currentSceneController as Controller;
            return;
        }
        if (controller.getState() == 0) {
            return;
        }
        isPressed = true;
        Debug.Log("Pressed!");
    }

    public void OnButtonReleased(VirtualButtonBehaviour vb) {
        isPressed = false;
        Debug.Log("Released!");
    }
    private void FixedUpdate()
    {
        if (isPressed) {
            rig.velocity = Vector3.up * speed;
        }
    }
}

還可以根據情況調整button的靈敏度:
在這裏插入圖片描述

最終效果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章