개발/Unity

유니티 AR - 그라운드 플레인으로 평면 인식하기 (Vuforia Ground Plane)

피로물든딸기 2023. 7. 4. 22:31
반응형

Unity 전체 링크

 

참고

- 유니티 AR 뷰포리아 튜토리얼

- 미드 에어 앵커로 오브젝트 생성하기

- 유니티 더블 클릭 구현하기

 

그라운드 플레인평면을 인식하는 기술이다.

뷰포리아에서는 평면을 인식하면, 평면에서 AR 오브젝트를 생성할 수 있게 한다.


Ground Plane 적용하기

 

Vuforia Engine에서 아래 두 오브젝트를 추가한다.

 

Plane Finder에서 ContentPositioningBehaviour.cs의 Anchor Stage를 Ground Plane Stage로 설정한다.

 

그리고 AR로 만들 오브젝트 Ground Plane Stage자식 오브젝트로 설정한다.

 

제공되는 Ground Plane Stage는 100cm 기준이기 때문에 오브젝트의 사이즈를 적절히 줄인다.

 

위에서 사용한 오브젝트는 아래 링크를 참고하자.

https://assetstore.unity.com/packages/3d/characters/creatures/kawaii-slimes-221172

 

Kawaii Slimes | 3D 생물 | Unity Asset Store

Elevate your workflow with the Kawaii Slimes asset from Awaii Studio. Find this & other 생물 options on the Unity Asset Store.

assetstore.unity.com

 

아쉽게도 웹캠에서는 Ground Plane을 테스트할 수 없다.

빌드를 하지 않고 테스트하려면, 뷰포리아에서 임시로 제공하는 이미지타겟으로 테스트해야 한다.

 

위의 이미지에 플레인 파인더 마커가 나타나게 되고, 클릭하면 슬라임이 나타난다.


중복 생성 옵션

 

현재 설정으로는 클릭을 할 때마다 슬라임이 계속 만들어지고 있다.

Plane Finder 오브젝트에서 ContentPositioningBehaviour.cs의 Duplicate Stage를 체크 해제하자.

 

다시 게임을 실행하면 가장 나중에 클릭을 한 위치에만 슬라임이 나타난다.


Plane Finder 제어하기

 

이제 슬라임을 만들면 플레인 파인더의 기능을 끄도록 제어해보자.

즉, 한 번 슬라임을 만들고 나면 다시 평면을 클릭해도 슬라임의 위치가 변하지 않는다.

 

먼저 슬라임에 PlaneFinderController.cs를 추가한다.

이 스크립트에서 planeFinder의 스크립트를 모두 가져온다.

    public GameObject planeFinder;

    AnchorInputListenerBehaviour ailr;
    PlaneFinderBehaviour pfb;
    ContentPositioningBehaviour cpb;

    public void initialize()
    {
        ailr.enabled = false;
        pfb.enabled = false;
        this.gameObject.SetActive(true);
    }

    void Start()
    {
        ailr = planeFinder.GetComponent<AnchorInputListenerBehaviour>();
        pfb = planeFinder.GetComponent<PlaneFinderBehaviour>();
        cpb = planeFinder.GetComponent<ContentPositioningBehaviour>();

        cpb.OnContentPlaced.AddListener(delegate { initialize(); });
    }

 

AnchorInputListenerBehaviour는 오브젝트를 추가하고, PlaneFinderBehaviour는 플레인 파인더를 만든다.

오브젝트가 추가될 때 이벤트를 발생시키고 싶다면 ContentPositioningBehaviourOnContentPlaced를 이용하면 된다.

즉, 오브젝트가 생성되면 오브젝트를 생성하지 못하고 플레인 파인더도 보이지 않도록 스크립트를 disabled로 만든다.

 

위의 경우 AddListener를 이용하였지만, 아래와 같이 직접 메서드를 추가해도 된다.

 

 

여기서 슬라임을 더블 클릭하면 슬라임이 잠시 사라지고 다시 Plane Finder의 기능을 on 시키자.

    float interval = 0.25f;
    float doubleClickedTime = -1.0f;
    bool isDoubleClicked = false;

    void OnMouseUp()
    {
        if ((Time.time - doubleClickedTime) < interval)
        {
            isDoubleClicked = true;
            doubleClickedTime = -1.0f;
        }
        else
        {
            isDoubleClicked = false;
            doubleClickedTime = Time.time;
        }
    }

    void Update()
    {
        if (isDoubleClicked)
        {
            isDoubleClicked = false;

            this.gameObject.SetActive(false);
            ailr.enabled = true;
            pfb.enabled = true;
        }
    }

 

더블 클릭 이벤트를 위해 슬라임에는 Sphere Collider를 추가하였다.

 

이제 게임을 실행하면 한 번만 슬라임을 만들 수 있을 것이다.

그리고 더블 클릭하면 다시 새로운 Groud Plane으로 슬라임의 위치를 옮기게 된다.

 

apk 빌드 후, 평면을 정상적으로 인식하는 것을 확인해보자.

 

전체 코드는 다음과 같다.

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

public class PlaneFinderController : MonoBehaviour
{
    public GameObject planeFinder;

    AnchorInputListenerBehaviour ailr;
    PlaneFinderBehaviour pfb;
    ContentPositioningBehaviour cpb;

    float interval = 0.25f;
    float doubleClickedTime = -1.0f;
    bool isDoubleClicked = false;

    public void initialize()
    {
        ailr.enabled = false;
        pfb.enabled = false;
        this.gameObject.SetActive(true);
    }

    void Start()
    {
        ailr = planeFinder.GetComponent<AnchorInputListenerBehaviour>();
        pfb = planeFinder.GetComponent<PlaneFinderBehaviour>();
        cpb = planeFinder.GetComponent<ContentPositioningBehaviour>();

        cpb.OnContentPlaced.AddListener(delegate { initialize(); });
    }

    void OnMouseUp()
    {
        if ((Time.time - doubleClickedTime) < interval)
        {
            isDoubleClicked = true;
            doubleClickedTime = -1.0f;
        }
        else
        {
            isDoubleClicked = false;
            doubleClickedTime = Time.time;
        }
    }

    void Update()
    {
        if (isDoubleClicked)
        {
            isDoubleClicked = false;

            this.gameObject.SetActive(false);
            ailr.enabled = true;
            pfb.enabled = true;
        }
    }
}

 

반응형