https://www.youtube.com/watch?v=ARgf9Q8PLgI&list=PLXwWzhDeMm-zpSpCQOFxR9iyfMUqSLIoM&index=2

 

3D 프로젝트를 만들고 하이라키에 AR Session Orign, AR Session, AR Default Point Cloud, AR Default Plane을 추가하고 Main Camera를 지운다.

AR Session Origin에 AR Plane Manager, AR Point cloud Manager, AR Raycast Manager를 추가하자, 하이라키상의 AR Default Point Cloud, AR Default Plane을 끌어다 연결해준다

하이라키에 3D 객체를 스폰해준기 위한 EmptyObject를 CreateEmpty해주고 CarSpawner로 명명하고 ARPlaceOnPlane 스크립트를 추가

public class ARPlaceOnPlane : MonoBehaviour
{
    ARRaycastManager raycastManager;
    GameObject placeObject;

생성할 3D Object를 Import하던가 임시로 Cube를 생성해준다.

CarSpawner의 ARPlaceOnPlae스크립트에 public을 연결해주자 RayCastManager는 AR Session Origin의 컴포넌트이므로 그걸 끌어다 주자

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class ARPlaceOnPlane : MonoBehaviour
{
     public ARRaycastManager raycastManager;
    public GameObject placeObject;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    private void updateCenterObject()
    {
        Vector3 screenCenter = Camera.current.ViewportToScreenPoint(new Vector3(0.5f, 0.5f, 0));  
        List<ARRaycastHit> hits = new List<ARRaycastHit>();
        raycastManager.Raycast(screenCenter, hits, TrackableType.Planes);
        if (hits.Count > 0)
        {
            Pose placePose = hits[0].pose;
            placeObject.SetActive(true);
            placeObject.transform.SetPositionAndRotation(placePose.position, placePose.rotation);
        }
        else
        {
            placeObject.SetActive(false);
        }
    }
}

타이머를 설정하는것은 정말 빈번하게 사용하게됩니다. 그렇기 때문에 좀더 좋은 형태를 가지도록 구현하고자 정리하려고 합니다.

 

Update를 이용한 방법

Private float time = 0f; 
Void Update() 
{ 
    this.time += Time.deltaTime; 
    if(this.time > 5f) 
    { 
        Debug.Log(“Do something!”); 
        this.time = 0; 
    } 
} 
[출처] [유니티 C#] - 타이머 설정하기|작성자 자판기

 

Time.deltaTime은 지난 프레임이 완료되는게까지 걸린 시간을 말합니다.

저희가 만든 time프로퍼티에 매 프레임마다 더해줌으로써 현재까지 걸린시간을 측정할 수 있습니다.

그 time프로퍼티가 5초를 넘는순간 어떠한 작업을 하고 다시 0초로 초기화해줘서 5초마다 일정한 시간을 가지고 어떠한 반복작업을 하는것이 가능해집니다.

 

이런 식으로 update를 이용하는 방법으로 간단하고 직관적으로 코드를 작성할수있지만 저는 이보다 좀더 복잡한 상황에서 사용하기 좋을수있는 coroutine을 사용해서 구현하고자합니다.

 

타이머 만드는 3개지 방법

검색을 하던 도중 코루틴과 Invoke의 차이점에 대해 묻는 질문을 발견했고, 나는 명확하게 대답하지 못해 해당 지식에 대한 정리를 해두고자 글을 작성한다.

🌐 코루틴

Cooperate(협력하다) 할때 Co와 routine이 합쳐진 Co-routine은 여러개의 루틴이 동시에 실행되게 해주며 멀티쓰레드가 아닌 유니티에서 마치 멀티쓰레드 처럼 보여 병렬적인 구조를 만드는 기능이다.

코루틴을 사용할 때는 Yield return을 해주어야 하는데, 이를 통해서 현재 위치를 기억하고 다른 루틴에게 수행권한을 넘겨주고 다시와서 처리하는 방식이다.

멀티 쓰레드 같지만 단일 쓰레드이기에 Race Condition과 같은 멀티 쓰레드에 문제점을 고민하지 않아도 된다.

💽 코루틴 특징

  • 코루틴은 해당 GameObject가 inactive일때 동작하지 않는다.
  • 정지 된 코루틴은 다시 GameObject가 Active 되더라도 다시 동작하지 않는다.(다시 실행을 시켜주어야한다.)
  • yield return new WaitForSeconds(시간) 이게 너무 편하다.. 함수 중간 중간 쉬었다가 동작 시킬 수 있는데 매우 간편하고, Update를 통해 Timer를 만들어 시간을 재는것 보다 효율적이다.왜 효율적인가?
    5초 뒤 동작을 위해 코드를 구현할 떄 Update에서는 초당 50프레임 정도를 동작하면서 250번을 호출하면서 동작을 하는데, 코루틴은 엔진에게 5초 뒤에 깨우라고 맡기고 쉬다가 동작하니 더 효율적일 수 밖에 없다.

🎇 Invoke

인보크는 코루틴에 비해 비교적 간단하다. 함수를 대신 실행시켜준다. 또한 간단한 방법으로 지연시간 뒤에 함수를 동작하게도 할 수 있다.

Invoke( "함수명"(string) , 지연시간(float));

다만 Invoke는 Reflection을 통해 값을 가져오는데 이 방식이 코루틴 보다는 느리다. 코루틴이 메서드 자체를 인자로 받아가는 것과는 다르게 메서드의 이름을 받아간다.

Reflection
프로그램 실행 도중에 객체의 정보 조사, 다른 모듈에 선언된 인스턴스를 생성, 기존 개체에서 형식을 가져오고 해당하는 메서드를 호출, 접근할 수 있는 강력한 기능
-> 코루틴도 string으로 부를 수 있는데 이때도 리플렉션이 동작되는건가 궁금한데 찾아도 잘 나오지 않는다. 더 공부해보고 추가 글을 남겨야겠다.

👓 인보크 특징

  • Invoke는 GameObject가 비활성화 되더라도 동작을 한다.
  • InvokeRepeating을 통해 지속 반복 동작을 시킬 수 있다.
    -> CancelInvoke, 오브젝트를 파괴하여 종료해주어야 한다.

✅ 차이점

결국은 글에서 언급하면서 나오긴 했지만 다시 정리하자면

  • 코루틴은 GameObject가 활성화 일때만 동작, 인보크는 파괴 전 까지 동작
  • 코루틴은 매개변수 전달 가능, Invoke는 불가능
  • 코루틴은 TimeScale이 0인 경우에도 동작 시킬 수 있다.
    -> yield return new WaitForSecondsRealtime()를 사용
  • 리플렉션의 차이로 코루틴의 속도가 조금 더 빠르다.

공부중인 내용이라 틀릴 수도 있습니다. 추가로 부족한 부분이 있으면 조언 부탁드립니다.

Couroutine을 이용하는 방법

Void Start()
{ 
    StartCoroutine(“timerCoroutine”);
} 

IEnumerator testCoroutine() 
{ 
    While(true) 
    { 
        Debug.Log(“Do something!”); 
        yield return new WaitForSeconts(5f); 
    } 
    yield return null; 
} 
[출처] [유니티 C#] - 타이머 설정하기|작성자 자판기

 

StartCoroutine()는 파라미터로 주어진 IEnumerator타입의 메소드를 실행시켜주는 역할을합니다.

IEnumerator타입 함수는 yield의 사용을 할수있어서 함수가 호출되고 나서 저희가 함수로 다시 돌아오고 어떻게 동작하는지 확인 할수있게 해줍니다.

 

Yield return new WaitForSecond()은 IEnumerator타입 함수가 재시작 할때까지 얼마나 오랫동안 기다려야하는지를 결정하는 유연성을 제공해줍니다. 파라미터로 원하는 시간을 넘겨주면 그시간동안 다음 동작을 기다립니다. 그후에 더이상의 이함수의 반복이 필요하지않은 부분에서 yield return null로 탈출해주면됩니다.

 

이 코루틴을 이용한 타이머는 타이머가 필요한 동작을 각각 분리하여 구현을 할수있다는것이 장점이 될수있습니다.

 

update로 하기에는 다양한 조건을 검사하거나 동시에 여러개의 타이머가 필요할때는 코루틴을 사용해 구현하는것이 편리할것같다고 생각합니다.

'AR > 24 KMOOC 비주얼심화과정' 카테고리의 다른 글

Unity 타이머  (0) 2024.07.06
7/5 수업  (0) 2024.07.05
7/3 강의 마커기반 AR  (0) 2024.07.03
7/1 FaceTracking2  (1) 2024.07.03
4일차 FaceTracking (6.30 강의)  (3) 2024.06.30

타이머를 설정하는것은 정말 빈번하게 사용하게됩니다. 그렇기 때문에 좀더 좋은 형태를 가지도록 구현하고자 정리하려고 합니다.

 

Update를 이용한 방법

Private float time = 0f; 
Void Update() 
{ 
    this.time += Time.deltaTime; 
    if(this.time > 5f) 
    { 
        Debug.Log(“Do something!”); 
        this.time = 0; 
    } 
} 
[출처] [유니티 C#] - 타이머 설정하기|작성자 자판기

 

Time.deltaTime은 지난 프레임이 완료되는게까지 걸린 시간을 말합니다.

저희가 만든 time프로퍼티에 매 프레임마다 더해줌으로써 현재까지 걸린시간을 측정할 수 있습니다.

그 time프로퍼티가 5초를 넘는순간 어떠한 작업을 하고 다시 0초로 초기화해줘서 5초마다 일정한 시간을 가지고 어떠한 반복작업을 하는것이 가능해집니다.

 

이런 식으로 update를 이용하는 방법으로 간단하고 직관적으로 코드를 작성할수있지만 저는 이보다 좀더 복잡한 상황에서 사용하기 좋을수있는 coroutine을 사용해서 구현하고자합니다.

 

타이머 만드는 3개지 방법

검색을 하던 도중 코루틴과 Invoke의 차이점에 대해 묻는 질문을 발견했고, 나는 명확하게 대답하지 못해 해당 지식에 대한 정리를 해두고자 글을 작성한다.

🌐 코루틴

Cooperate(협력하다) 할때 Co와 routine이 합쳐진 Co-routine은 여러개의 루틴이 동시에 실행되게 해주며 멀티쓰레드가 아닌 유니티에서 마치 멀티쓰레드 처럼 보여 병렬적인 구조를 만드는 기능이다.

코루틴을 사용할 때는 Yield return을 해주어야 하는데, 이를 통해서 현재 위치를 기억하고 다른 루틴에게 수행권한을 넘겨주고 다시와서 처리하는 방식이다.

멀티 쓰레드 같지만 단일 쓰레드이기에 Race Condition과 같은 멀티 쓰레드에 문제점을 고민하지 않아도 된다.

💽 코루틴 특징

  • 코루틴은 해당 GameObject가 inactive일때 동작하지 않는다.
  • 정지 된 코루틴은 다시 GameObject가 Active 되더라도 다시 동작하지 않는다.(다시 실행을 시켜주어야한다.)
  • yield return new WaitForSeconds(시간) 이게 너무 편하다.. 함수 중간 중간 쉬었다가 동작 시킬 수 있는데 매우 간편하고, Update를 통해 Timer를 만들어 시간을 재는것 보다 효율적이다.왜 효율적인가?
    5초 뒤 동작을 위해 코드를 구현할 떄 Update에서는 초당 50프레임 정도를 동작하면서 250번을 호출하면서 동작을 하는데, 코루틴은 엔진에게 5초 뒤에 깨우라고 맡기고 쉬다가 동작하니 더 효율적일 수 밖에 없다.

🎇 Invoke

인보크는 코루틴에 비해 비교적 간단하다. 함수를 대신 실행시켜준다. 또한 간단한 방법으로 지연시간 뒤에 함수를 동작하게도 할 수 있다.

Invoke( "함수명"(string) , 지연시간(float));

다만 Invoke는 Reflection을 통해 값을 가져오는데 이 방식이 코루틴 보다는 느리다. 코루틴이 메서드 자체를 인자로 받아가는 것과는 다르게 메서드의 이름을 받아간다.

Reflection
프로그램 실행 도중에 객체의 정보 조사, 다른 모듈에 선언된 인스턴스를 생성, 기존 개체에서 형식을 가져오고 해당하는 메서드를 호출, 접근할 수 있는 강력한 기능
-> 코루틴도 string으로 부를 수 있는데 이때도 리플렉션이 동작되는건가 궁금한데 찾아도 잘 나오지 않는다. 더 공부해보고 추가 글을 남겨야겠다.

👓 인보크 특징

  • Invoke는 GameObject가 비활성화 되더라도 동작을 한다.
  • InvokeRepeating을 통해 지속 반복 동작을 시킬 수 있다.
    -> CancelInvoke, 오브젝트를 파괴하여 종료해주어야 한다.

✅ 차이점

결국은 글에서 언급하면서 나오긴 했지만 다시 정리하자면

  • 코루틴은 GameObject가 활성화 일때만 동작, 인보크는 파괴 전 까지 동작
  • 코루틴은 매개변수 전달 가능, Invoke는 불가능
  • 코루틴은 TimeScale이 0인 경우에도 동작 시킬 수 있다.
    -> yield return new WaitForSecondsRealtime()를 사용
  • 리플렉션의 차이로 코루틴의 속도가 조금 더 빠르다.

공부중인 내용이라 틀릴 수도 있습니다. 추가로 부족한 부분이 있으면 조언 부탁드립니다.

Couroutine을 이용하는 방법

Void Start()
{ 
    StartCoroutine(“timerCoroutine”);
} 

IEnumerator testCoroutine() 
{ 
    While(true) 
    { 
        Debug.Log(“Do something!”); 
        yield return new WaitForSeconts(5f); 
    } 
    yield return null; 
} 
[출처] [유니티 C#] - 타이머 설정하기|작성자 자판기

 

StartCoroutine()는 파라미터로 주어진 IEnumerator타입의 메소드를 실행시켜주는 역할을합니다.

IEnumerator타입 함수는 yield의 사용을 할수있어서 함수가 호출되고 나서 저희가 함수로 다시 돌아오고 어떻게 동작하는지 확인 할수있게 해줍니다.

 

Yield return new WaitForSecond()은 IEnumerator타입 함수가 재시작 할때까지 얼마나 오랫동안 기다려야하는지를 결정하는 유연성을 제공해줍니다. 파라미터로 원하는 시간을 넘겨주면 그시간동안 다음 동작을 기다립니다. 그후에 더이상의 이함수의 반복이 필요하지않은 부분에서 yield return null로 탈출해주면됩니다.

 

이 코루틴을 이용한 타이머는 타이머가 필요한 동작을 각각 분리하여 구현을 할수있다는것이 장점이 될수있습니다.

 

update로 하기에는 다양한 조건을 검사하거나 동시에 여러개의 타이머가 필요할때는 코루틴을 사용해 구현하는것이 편리할것같다고 생각합니다.

'AR > 24 KMOOC 비주얼심화과정' 카테고리의 다른 글

Unity 타이머  (0) 2024.07.08
7/5 수업  (0) 2024.07.05
7/3 강의 마커기반 AR  (0) 2024.07.03
7/1 FaceTracking2  (1) 2024.07.03
4일차 FaceTracking (6.30 강의)  (3) 2024.06.30

BallController Script를 만든다

 

SetBallPosition()이라는 함수를 만든다.

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

public class BallController : MonoBehaviour
{
    Rigidbody rb;  //녹색은 값을 넣어줘야함.
    //공이 준비 상태인지 확인하는 변수
    bool isReady = true;
    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        //리지드 바디의 물리 능력을 비활성화
        rb.isKinematic = true;
     
    }

    // Update is called once per frame
    void Update()
    {
        //공을 카메라 전방 하단에 배치
        SetBallPosition(Camera.main.transform);
    }

    void SetBallPosition(Transform anchor)
    {
        //카메라의 위치로부터 일정 거리만큼 떨어진 위치 설정
        // Vector3 = anchor로 부터 앞으로 0.5+ anchor로 부터 아래로 0.2
        Vector3 offset = anchor.forward * 0.5f + anchor.up * -0.2f;
        //공의 위치를 offset만큼 이동
        transform.position = anchor.position + offset;
    }
}

Ball에 스크립트를 끌어다 놓고

 

 

공을 발사하고 3초후 공을 다시 만들어 주기위해 타이머를 만들어야 하는데 수업에서는 invoker를 사용하였다.

3초가 지나면 Ball을 Reset()해줘 위치를 초기화 해준다.

void Update()에서 터치후 드래그시 공에 addForce로 공을 약간 위로 나가게 해준다.

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

public class BallController : MonoBehaviour
{
    Rigidbody rb;
    // 공이 준비 상태인지 확인하는 변수
    bool isReady = true;
    // 터치 시작 지점
    Vector2 startPos;
    // 공을 초기화 할 시간
    float resetTime = 3f;
    // 포획 확률
    float captureRate = 0.5f;
    // 포획 결과 텍스트
    public Text result;

    // Start is called before the first frame update
    void Start()
    {
        // 포획 결과 텍스트 초기화
        result.text = "";
        rb = GetComponent<Rigidbody>();
        // 리지드 바디의 물리 능력을 비활성화
        rb.isKinematic = true;
    }

    // Update is called once per frame
    void Update()
    {
        if (!isReady)
        {
            return;
        }
        // 터치가 입력 되었고, 공이 준비 상태라면
        if (Input.touchCount > 0 && isReady)
        {
            Touch touch = Input.GetTouch(0);
            // 만약 터치를 시작했다면
            if (touch.phase == TouchPhase.Began)
            {
                // 시작 지점 저장
                startPos = touch.position;
            }
            // 터치가 끝났다면
            else if (touch.phase == TouchPhase.Ended)
            {
                // 드래그한 y축 거리를 계산
                float dragDistance = touch.position.y - startPos.y;
                // 카메라를 기준으로 45도 각도 계산
                Vector3 throwAngle = (Camera.main.transform.forward
                    + Camera.main.transform.up).normalized;
                // 물리 능력 활성화
                rb.isKinematic = false;
                // 준비 상태 변경
                isReady = false;
                // 던질 방향과 드래그 거리만큼 공에 물리적 힘을 더함
                rb.AddForce(throwAngle * dragDistance * 0.005f, ForceMode.VelocityChange);
                // 3초 뒤에 공의 위치와 속도 초기화
                Invoke("ResetBall", resetTime);
            }
        }

        // 공을 카메라 전방 하단에 배치
        SetBallPosition(Camera.main.transform);
    }

    void SetBallPosition(Transform anchor)
    {
        // 카메라의 위치로부터 일정 거리만큼 떨어진 위치 설정
        // Vector3 = anchor로부터 앞으로 0.5 + anchor로부터 아래로 0.2
        Vector3 offset = anchor.forward * 0.5f + anchor.up * -0.2f;
        // 공의 위치를 카메라 위치로부터 offset만큼 이동
        transform.position = anchor.position + offset;
    }

    void ResetBall()
    {
        // 물리 능력 비활성화
        rb.isKinematic = true;
        // 속도 초기화
        rb.velocity = Vector3.zero;
        // 준비 상태로 변경
        isReady = true;
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (isReady)
        {
            return;
        }
        // 포획 확률을 랜덤한 값으로 설정
        float draw = Random.Range(0, 1f);
        // 만약 랜덤 값이 captureRate 보다 작다면 포획 성공
        if (draw <= captureRate)
        {
            result.text = "포획에 성공했습니다!";
        }
        // 그렇지 않다면 포획 실패
        else
        {
            result.text = "포획에 실패하여 도망쳤습니다.";
        }
        // 마커 오브젝트 제거
        Destroy(collision.gameObject);
        // 공 비활성화
        gameObject.SetActive(false);
    }
}

하이라키+를 눌러 Leagacy Text를 추가해준다.

Canvas Scaler는 Scale with Screen Size로 해주고 해상도는 다음과 같이해준다.

 

BallController.cs
0.00MB

 

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

public class BallController : MonoBehaviour
{
    Rigidbody rb;
    // 공이 준비 상태인지 확인하는 변수
    bool isReady = true;
    // 터치 시작 지점
    Vector2 startPos;
    // 공을 초기화 할 시간
    float resetTime = 3f;
    // 포획 확률
    float captureRate = 0.5f;
    // 포획 결과 텍스트
    public Text result;

    public GameObject effect;
    // Start is called before the first frame update
    void Start()
    {
        // 포획 결과 텍스트 초기화
        result.text = "";
        rb = GetComponent<Rigidbody>();
        // 리지드 바디의 물리 능력을 비활성화
        rb.isKinematic = true;
    }

    // Update is called once per frame
    void Update()
    {
        if (!isReady)
        {
            return;
        }
        // 터치가 입력 되었고, 공이 준비 상태라면
        if (Input.touchCount > 0 && isReady)
        {
            Touch touch = Input.GetTouch(0);
            // 만약 터치를 시작했다면
            if (touch.phase == TouchPhase.Began)
            {
                // 시작 지점 저장
                startPos = touch.position;
            }
            // 터치가 끝났다면
            else if (touch.phase == TouchPhase.Ended)
            {
                // 드래그한 y축 거리를 계산
                float dragDistance = touch.position.y - startPos.y;
                // 카메라를 기준으로 45도 각도 계산
                Vector3 throwAngle = (Camera.main.transform.forward
                    + Camera.main.transform.up).normalized;
                // 물리 능력 활성화
                rb.isKinematic = false;
                // 준비 상태 변경
                isReady = false;
                // 던질 방향과 드래그 거리만큼 공에 물리적 힘을 더함
                rb.AddForce(throwAngle * dragDistance * 0.005f, ForceMode.VelocityChange);
                // 3초 뒤에 공의 위치와 속도 초기화
                Invoke("ResetBall", resetTime);
            }
        }

        // 공을 카메라 전방 하단에 배치
        SetBallPosition(Camera.main.transform);
    }

    void SetBallPosition(Transform anchor)
    {
        // 카메라의 위치로부터 일정 거리만큼 떨어진 위치 설정
        // Vector3 = anchor로부터 앞으로 0.5 + anchor로부터 아래로 0.2
        Vector3 offset = anchor.forward * 0.5f + anchor.up * -0.2f;
        // 공의 위치를 카메라 위치로부터 offset만큼 이동
        transform.position = anchor.position + offset;
    }

    void ResetBall()
    {
        // 물리 능력 비활성화
        rb.isKinematic = true;
        // 속도 초기화
        rb.velocity = Vector3.zero;
        // 준비 상태로 변경
        isReady = true;
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (isReady)
        {
            return;
        }
        // 포획 확률을 랜덤한 값으로 설정
        float draw = Random.Range(0, 1f);
        // 만약 랜덤 값이 captureRate 보다 작다면 포획 성공
        if (draw <= captureRate)
        {
            result.text = "포획에 성공했습니다!";
        }
        // 그렇지 않다면 포획 실패
        else
        {
            result.text = "포획에 실패하여 도망쳤습니다.";
        }
        //이펙트생성
        Instantiate(effect, collision.gameObject.transform.position, Camera.main.transform.rotation);
        // 마커 오브젝트 제거
        Destroy(collision.gameObject);
        // 공 비활성화
        gameObject.SetActive(false);
    }
}

Asset Store에서 이펙트를 찾아 다운로드해주고

Import해준다.

스크립트에 effect변수에 import한 이펙트를 끌어다 놔준다. UI LegacyText로 끌어다 놔준다

실행해서 마커를 촬용하면 고양이가 나오고 볼을 드래그해서 맞추면 폭발이 일어나는데 확율에 의해 성공과 실패가 나뉜다. 

실제 해보면 공의 초기 위치와 고양이의 위치가 비슷해 고양이가 공위에 있다. AddForce가 앞으로 날라가기때문에 맞지 않는다. 공위로 고양이가 있을때 억지로 가깝게 해서 맞춰줘야야만 한다. 난 공을 좀더 카메라쪽(-) 고양이를 뒤로 위치시켜 거리를 만들어 공이 앞으로 날라가다 맞게 해주었다

'AR > 24 KMOOC 비주얼심화과정' 카테고리의 다른 글

Unity 타이머  (0) 2024.07.08
Unity 타이머  (0) 2024.07.06
7/3 강의 마커기반 AR  (0) 2024.07.03
7/1 FaceTracking2  (1) 2024.07.03
4일차 FaceTracking (6.30 강의)  (3) 2024.06.30

새로운 씬을 만든다. 씬폴더에서 우클릭 Create Scene 해준다.

PackageManager에서 

AR VR은 Main Camera가 아니라 AR VR전용카메라를 사용한다.

VR은 다른 플러그인 설치가 필요하다 여기서는 안쓴다.

하이라키에서 AR Session Orign을 추가한다 그러면 카메라가 2개니 지우라고 하고 MainCamera를 지운다

하이라키에서 AR Session을 추가한다.

AR Detection은 마커리스 마커 페이스디텍션등이 있다.

MarkerAR 폴더를 만든다.

맨먼저 마커 등록(학습)을 시켜야한다.

MarketAR폴더안에 Create>XR> Image or Object 2가지가 있다.

우선 이미지기반 마커를 만들어보자. XR>Reference Image Library를 선택하자.

마커로 사용되는 이미지는 너무 단순하면 안된다. 복잡할수록 좋다. 다운 받은 그림을 Marker Library 2D 에 끌어다 놓는다.

Add Image를 눌러 3개를 추가했다.

Unity Assets Store Character>Animal>CartoonCat을 가져온다. Unity에서 열기하면PackageManger가 나오는데 다운로드후 Import한다.

Cat_Idle을 끌어다 하이라키에 놓는다.

고양이 애니메이션을 컨트롤 할려면  애니메이터 컨르롤러를 알아야 한다.

현재는 전체 애니메이션이 순환 반복되는데 밥먹는거만 반복되게 해보자 일단 편집을 위해 플레이를 끈다.

 

CatAnim으로 이름 바꾸고 더블클릭

3개의 스테이지가 보이는데 Entry가 시작이다. Exit는 종료 Any State는 모든 스테이트에서 이동이 가능하다.

그래프 우클릭 하고

하이라키 Cat_Idle을 선택하고 Controller 동그라미를 클릭하고 CatAnim으로 바꿔준다.

 

하이라키 Cat을 끌어다 MarketAR폴더에 놓고 프리팹으로 만듬 하이라키 Cat은 삭제

Marke

Cat 프리팹을 끌어 Tracked Image Prefab에 놓는다.

빌드세팅즈 열고 MarketAR 이외는 꺼준다.

빌드앤런 처음 마커로 설정한 뽀로로 위에서만 고양이가 나타난다.

하이라키 MarketCat Delete

 

Rigidbody 컴포넌트 추가

 

Mass: 무게

Drag: 공기저항

Angular Drag:

Use Gravity :

Is Kinematic:체크되면 물리효과 무

Material  폴더를 만들고 Create>Material M_Ball로 이름을 만든다.

'AR > 24 KMOOC 비주얼심화과정' 카테고리의 다른 글

Unity 타이머  (0) 2024.07.06
7/5 수업  (0) 2024.07.05
7/1 FaceTracking2  (1) 2024.07.03
4일차 FaceTracking (6.30 강의)  (3) 2024.06.30
3일차 인디케이터에서 오브젝트 생성및 회전 (6월28일)  (0) 2024.06.28

이전에 마스크를 얼굴에 씌워봤는데 이번에는 동영상을 올려보겠다.

하이라키+를 누르고 CreateEmpty만들고 이름을 FaceModel로 하고 Transform을 리셋한다. 삼점을 누르면 된다.

 

FaceModel을 선택하고 MeshFilter, MeshRendere, MeshCollider, AR Face, AR Mesh Visualizer를 추가한다.

 

얼굴에 덮을 이미지를 적당히 찾는다 png가 좋다.

유니티 Material Folder로 가져온후 인스펙터에서 Transparecy 체크하고 apply

Material을 하나 만들고 M_Face로 하나 만들고 Redering Mode를 Cutout PNG를 Albedo 왼쪽에 끌어다 놓는다.

 

하이라키 FaceModel을 선택하고 머터리얼 M_Face를 끌어다 Materials Element 0 에 넣어준다.

이제 하이라키의 FaceModel을 프로젝트 Prefabs폴더에 끌어다 놓고 프리팹으로 만든다.

만든 프리팹을 하이라키의 AR Session Orign을 선택하고 AR Face Manager컴포넌트의 Face Prefab에 끌어다  적용한다.

하이라키의 FaceModel은 지운다.

빌드앤런 해보면 잘된다. 마스크가 3D로 적용된다 .

첫날은 MyMask라는 빈 오브젝트에 Mask라는 Quad에 M_Mask를 머터리얼로 얹은 2D 평면이었지만 이번에 만든 FaceModel은 3D화 되었다.

 

빈오브젝트에 이것저것 넣어서 만들기 귀찮으면

하이라키에서 우클릭후 AR Default Face를 추가하고 M_Face 머터리얼을 추가해고  AR Face Manager 프리팹에 적용해도 같은 효과가 난다.

 

이제 동영상을 마스크 대신 띄워보자 인터넷에서 영상을 캡쳐해서 머터리얼 폴더로 끌고오자.

하이라키에 CreateEmpty를 만들고 이름을 FaceVideo로 하자

VideoPlayer Component를 추가하고 비디오를 끌어다 Source에 연결해주자 Loop 체크하고 Mute를 체크해서 소리를 꺼준다.

 

프로젝트창 우클릭후 Create>RenderTexture를 만든다. 이름은 FaceVideoRT로 변경하고 이걸 하이라키의 FaceVideo의 TargetTexture에 넣어준다.

프로젝트창에 Create>Material만들고 이름을 M_FaceVideo로 한다. 알베도 왼쪽에 FaceVideoRT를 넣어준다.

 

아까 만든 FaceModel 프리팹을 열어 Matarial에 M_FaceVideo를 연결해준다. 

하이라키의 AR Session Orign>AR Face Manager의 Face Prefab에 Face Model을 연결해주자

정리해보면 M_FaceVideoRT 를 FaceVideoRT>알베도에 놓고 FaceVideoRT 를 M_FaceVideo->Target Texture 에 넣고 M_FaceVideo를 Face Mdel->Material-에 넣고 Face Mode을 AR FaceManager->Face prefab에 넣는다.

빌드런 해보면 잘된다.

 

Cavas 버튼을 2개더 복사해서 좌우로 펼쳐준다

 

버튼을 선택하고 이미지를 지워주자

 

Text를 Image Video로 바꾸고 폰트사이즈를 48로 키워준다.

UI_Manager 스크립트에 머터리얼 행 변수와 SwitchMaterial()함수를 만들어준다

    public Material[] faceMats;

    public void SwitchMaterial(int num)
    {

    }

하이라키의 Canvas를 선택하고 UI Manager(Script)의 Face Mats +를 2번 눌러 Element를 2개 만들고 Material을 2개 연결해준다.

 

2개의 버튼이 함수는 SwitchMaterial로 똑같지만. Button Image OnClick()은 0,ButtonVideo OnClick()은 1로 설정한다.

해본면 안된다. 아직 SwitchMaterial()함수를 정의 안해서 그런것 같다.

눈코입 위치 인식하기

C#스크립트를 만들고 FindDetection 이라고 한다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARCore;
using Unity.Collections;

public class FindDetection : MonoBehaviour
{
    public ARFaceManager afm; 
    public GameObject cube;  //얼굴에 띄워줄 cubeObject
    List<GameObject> faceCubes = new List<GameObject>();
    ARCoreFaceSubsystem subSys;
    NativeArray<ARCoreFaceRegionData> regionData;
    // Start is called before the first frame update
    void Start()
    {
        //얼굴 위치 표시를 위한 큐브 3개 생성
        for(int i = 0; i < 3; i++)
        {
            GameObject go = Instantiate(cube);
            faceCubes.Add(go);
            go.SetActive(false);
        }
        //얼굴 인식 함수 연결
        afm.facesChanged += OnDetectPoints;  //얼굴이 변화될때 아래 정의된 함수를 델리게이션 추가
        subSys = (ARCoreFaceSubsystem)afm.subsystem; //서브시스템의 정보를 가져와 저장한다.
    }
    //얼굴이 인식될 대마다 실행할 함수
    void OnDetectPoints(ARFacesChangedEventArgs args)
    {
        //얼굴 정보가 갱신된 것이 있다면
        if (args.updated.Count > 0)
        {
            //인식된 얼굴에서 특정 위치를 가져옴
            subSys.GetRegionPoses(args.updated[0].trackableId, Allocator.Persistent, ref regionData);
            //인식된 얼굴을 특정 위치에 오브젝트 배치
            for(int i = 0; i < regionData.Length; i++)
            {
                faceCubes[i].transform.position = regionData[i].pose.position;
                faceCubes[i].transform.rotation = regionData[i].pose.rotation;
                faceCubes[i].SetActive(true);
            }
        }
        //얼굴 정보를 잃었다면
        else if (args.removed.Count > 0)
        {
            //큐브오브젝 비활성화
            for( int i = 0; i< regionData.Length; i++)
            {
                faceCubes[i].SetActive(false);
            }
        }
    }
    // Update is called once per frame
    void Update()
    {
        
    }
}

하이라키+를 눌러 빈게임 오브젝트를 만들고 이름을 FaceElements로 한다  FindDetection을 끌어다 놓고 AR Session Origin을 끌어다 afm에 연결해준다.

하이라키+ 3D 오브젝트>Cube를 추가한다. 스케일을 0.02로 한다.

Cube를 프리팹폴더로 옮겨서 프리팹으로 만들고 FaceElements를 선택해서 Cube프리팹을 끌어다 놓는다.

빌드앤런 해보면 잘된 아까 페이스 위에 큐브 3개가 나온다.

https://www.youtube.com/watch?v=UuoNTYZaT7k&list=PLATff1khpIscTMN2KXxagrTkBCwdzOeol&index=2

 

프로젝트는 새로 만들어도 되고 만들때마다 용량이 늘어나므로 기존 프로젝트에 New Scene을 하는걸 추천한다. 3D면 된다.

File>Save를 하면 이름을 물어보는데 난 DebugTest로 했다.

Window>Package Manager에 AR Foundation, ARCore가 잘 설치되어 있어야 한다 기타 빌드 설정도 잘되어 있어야하고 핸드폰도 개발자모드로 되어 있어야하고 연결하고 승인도 해줘야한다. 잡일이 많다.

하이라키 +를 누르거나 우클릭후 AR Session, AR Session Orign을 추가하고 Main Camera는 지워준다.

이제 AR Foundation기능을 테스트 해보자  AR Foundation이 지원하는 기능은 다음과 같은데

특징설명

 

세션 대상 플랫폼에서 AR을 활성화, 비활성화하고 구성합니다.
장치 추적 실제 공간에서 장치의 위치와 회전을 추적합니다.
카메라 장치 카메라에서 이미지를 렌더링하고 조명 추정을 수행합니다.
비행기 감지 평평한 표면을 감지하고 추적합니다.
이미지 추적 2D 이미지를 감지하고 추적합니다.
객체 추적 3D 객체를 감지하고 추적합니다.
얼굴 추적 인간의 얼굴을 감지하고 추적합니다.
신체 추적 인체를 감지하고 추적합니다.
포인트 클라우드 특징점을 감지하고 추적합니다.
레이캐스트 추적된 항목에 광선을 비춥니다.
앵커 공간상의 임의의 지점을 추적합니다.
메싱 환경의 메시를 생성합니다.
환경 프로브 환경의 큐브맵을 생성합니다.
폐색 AR 콘텐츠를 물리적 객체로 가리고 인간 세분화를 수행합니다.
참가자들 공유된 AR 세션에서 다른 기기를 추적합니다.

일단 하이라키위를 우클릭하면 나타나는 것들부터 해보자

AR Default Point Cloud를 추가하자

AR Session Origin을 클릭후 Inspection뷰에서 Add Component를 클릭하고 AR Point라고 검색한후 AR Point Manager를 추가하자. 그럼 Point Cloud Prefab이라는 Item이 생기고 None에 프리팹을 연결해줘야한다..

프로젝트뷰에 Prefab폴더를 만들고 AR Default Point Cloud를 끌어다 놓으면 Prefab이 생성된다.  하이라키의 있는 것들은 GameObject라는 객체인데 이것들을 끌어다 프로젝트에 놓으면 Prefab으로 바뀐다. Prefab은 Class라고 생각하면 된다. 객체에서 클래스를 만드어 주는거다. 보통은 클래스를 만들고 클래스이용 객체를 만드는 것의 반대이다. 객체지향 어려워요. 참 프리팹을 만든후에는 AR Default Point Cloud는 지워주자. 끌어다 놓을때는 이름을 잘보자 프로젝트뷰가 아이콘아 아니라 리스트로 나오는건 우측 삼점을 누르고 One Columb Layout을 선택하면 된다.

이제 빌드를 해보자 File>BuildSetting를 눌러서 Add Open Scenes를 눌러 현재 씬을 추가해줘야한다.

좌측아래 PlayerSettings(Project Setting에서도 접근가능)를 눌 앱이름을 설정하자.

 

오른쪽아래 빌드앤런을 누르면 파일명을 물어보면 build라는 폴더를 만들고 들어가서 적당히 이름만든다. 클

세이브할꺼냐고 물어보면 Save

이때 부터 핸드폰을 잘봐라 대기화면이면 풀어주자. 프로그레스바에서 device에 copy한다는 메세지가 나와야 한다. 물론 빌드폴더에서 apk를 핸드폰으로 카피해서 깔아도 되지만 이게 편하다.

핸드폰 화면을 대기화면에서 풀고 잘 보면 아래 팝업이 뜬다. 당황하지 말고 확인 위에 세부정보 더보기를 누르고 다시 확인위에 무시하고 설치하기 누른다.

다음 카메라사용 승인해주면 드디어 앱이 뜬다. 포인트가 안 나온다면 좀 기다려 보고 앵글을 움직여 보면 나온다. 포인트는 오브젝트의 엣지부분을 찾는 기능 같다.

 

다음은 하이라키 뷰위를 우클릭후 AR Default Plane을 추가 하고

프리팹 폴더에 끌어다 프리팹을 만들자. 그럼 파란색으로 변하고

AR Session Origine에 AR Plane Manager 컴포넌트를 추가하고

AR Default Plane 프리팹을 AR Plane Manager컴포넌트의 Prefab 참조에 연결해준다

Detection Mode는 원하는 면을 선택할수 있는데 현재는 그냥 두자

 

빌드해주자 잘보면 방법이 똑같다 AR Default XXXX를 추가하고 프리팹을 만들고 AR Session Origne에 AR XXXX Manager를 컴포넌트에 추가하고 프리팹을 연결해준다.

빌드해보면 Point와 Plane인식을 할것이다. Plane인식은 약간 시간이 걸리는것 같다. 그리고 정확하지 않은것 같다. 아이폰은 라이더가 내장되어 있어 정확안듯 하

마지막으로 하이라키에 우클릭후 XR>AR Default Face를 추가하고 프리팹폴더에 끌어다 프리팹만들고 지워주자

AR Session Origine에 AR Face Management 컴포넌트를 추가하고 AR Default Face Prefabs를 연결해준다.

Face Detect를 하기 위해 모델이 있다면야 후방으로 해도 되지만 자신으로 테스트하기 위해 전방카메라를 선택해보자. AR Session Orign>AR Camera를 선택해서 Inspector View아래 Face Direction이 있는데 World->User로 바꾸준다. World가 후방이다.

Face Tracking에서는 Point, Plane Manager가 필요 없다고 해서 지우라는데 난 귀찮아서 안지웠는데 잘되었다  지우는것 대신 불필요한 부분을 비활성화 하는 방법도 있을것 같다. 컴포넌트 이름 왼쪽을 언체크하면 된다.

실행화면 내 눈 코 입을 만들어주고 표정까지 트래킹 해준다. 얼굴을 돌려보면 나름 3D로 모델을 만들어서 맵핑해준다. 유튜브는 이빨과 눈동자도 보이는데  버전에 따라 좀 다른듯 

오른쪽이 유튜브 강좌 화면 눈동자와 이빨이 보임.

 

'AR > AR Foundation' 카테고리의 다른 글

AR 개발환경구축하기  (0) 2024.07.02
소개  (0) 2024.07.02
iOS / Unity 2022.3.5f1 + AR FOUNDATION / ARKit  (0) 2024.06.30
유니티 Unity AR Foundation  (0) 2024.06.30

https://www.youtube.com/watch?v=yLH9Gj1cO6U&list=PLATff1khpIscTMN2KXxagrTkBCwdzOeol&index=3

 

일단 유니티 사이트에서 유니티 허브를 설치

아이디 생성후 로그인후 유니티 에디터를 설치해야함

Archive탭에서 Download archive를 클릭해

21.3.39f1을 설치한다. 강의하시는 선생님이 이버전을 사용해서인데 최신버전을 사용해도 된다.

허브가 자동으로 열린다.

Anidroid Build Support를 체크후 Continue한다 2022가 있는데 2019를 꼭 갈아야하는지는 모르겠다.

비주얼스튜디오도 설치하고

유니티게임개발을 체크해준다.

 

유니티 허브를 열고 프로젝트를 만들자

3D를 선택하고 경로는 한글로만 되어야 한다.

 발드를 위한 설정을 위해 Fie>Buid Settings로 들어간다. windows에서 Android로 바꾸고 Switch Platform

 

windows 메뉴에서 Package Mannage를 열고 AR은 올인원 패키지라 용량이 크므로 개별로 설치하자

밑으로 내려가면  AR Foundation을 선택후 오른쪽 아래 install을 누른다

다음은 구 플래폼을 위해 AR Core를 설치한다. ios라면 ARKit같이 다른걸 해야한다.

Edit>ProjectSettings>왼쪽아래 PlayerSettings를 클릭하고

Quality카테고리에서 안드로이드를 Mediaum으로 체크한다. 

Player카테고리의 OtherSetting Color Space를 Gamma에서 Linear로 변

앱의 이름및 버전을 설정할 수도 있다.

밑의 Auto Graphic API를 해제후 Graphics API창이 나타나는데

모바일에서 지원안하는 vulkan을 -를 눌러 지워준다.

조금더 아래 Multithreaded Rendering을 체크해주자

아래 Minimum API Level을 Android 7.0으로 바꾼다. Nuga 

Scripting Backend를 IL2CPP, API Compatibility Level을 .NET Framework로 변경한다.

ARM64 채크

XR Plug-In Management 카테고리로 이동후  ARCore를 체크해주면 된다.

게임를 Simulator로 변경후 자신의 안드로이드 기종으로 변경한다.

적성에 맞게 윈도우  패널들을 재 배치한다 모바일 개발은 수직방향이라 다음과 같이 배치했다.

설치가 잘되었다면 빌드가 잘되어야 하는데 스마트폰 드라이브를 깔고 스마트폰을 연결해야 하는것 같다.

스마트폰 드라이버는 당연히 자신의 핸드폰 메이커에 맞는걸 메이커 사이트에가서 다운 받아야 한다.

스마트폰 설정 버전에가서 열심히 두들겨 개발자 모드로 진입하고 디버깅허용한후 케이블 연결하면 다른건 할필요 없고 기다리면 디버깅 허용할꺼냐고 물어보면 승인한다.

나중에 빌드하면 인증안된 앱을 깔꺼냐고 물어보는데 이것도 눌러야한다. 이것 안하고 빌드앤런 누르면 마지막에 멈쳐있다. 니 연결을 체크하는 에러 메세지가 난다. 

 

https://blog.naver.com/kal9107/223003398900

 

유니티 엔진 모바일 디버깅하는 방법

#유니티 #모바일 #디버깅 디버깅 환경이 갖춰져야 원활한 개발이 가능하다! 모바일 게임을 만들던 도중 유...

blog.naver.com

 

설정이 잘되어 있다면 하이라키에서 우클릭하면 XR 관련 팝업리스트가 보여야 한다.

이중 AR Session, AR Session Origin은 무조건 추가해야하고 AR Session Origin에 AR Camera가 있기 때문에 하이라키 맨위 Main Camera는 지워준다.

 

'AR > AR Foundation' 카테고리의 다른 글

[유니티 AR] 디버깅을 위한 빌드 테스트  (1) 2024.07.02
소개  (0) 2024.07.02
iOS / Unity 2022.3.5f1 + AR FOUNDATION / ARKit  (0) 2024.06.30
유니티 Unity AR Foundation  (0) 2024.06.30

https://www.youtube.com/watch?v=C5taq2a3_rQ&list=PLATff1khpIscTMN2KXxagrTkBCwdzOeol&index=1

AR Foundation은 유니티에서 AR을 개발시 사용하는 통합워크플로이다.

 

https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/manual/index.html

 

AR Foundation | AR Foundation | 5.1.5

AR Foundation AR Foundation enables you to create multi-platform augmented reality (AR) apps with Unity. In an AR Foundation project, you choose which AR features to enable by adding the corresponding manager components to your scene. When you build and ru

docs.unity3d.com

 

특징

AR Foundation은 다음 기능을 지원합니다.

특징설명
세션 대상 플랫폼에서 AR을 활성화, 비활성화하고 구성합니다.
장치 추적 실제 공간에서 장치의 위치와 회전을 추적합니다.
카메라 장치 카메라에서 이미지를 렌더링하고 조명 추정을 수행합니다.
비행기 감지 평평한 표면을 감지하고 추적합니다.
이미지 추적 2D 이미지를 감지하고 추적합니다.
객체 추적 3D 객체를 감지하고 추적합니다.
얼굴 추적 인간의 얼굴을 감지하고 추적합니다.
신체 추적 인체를 감지하고 추적합니다.
포인트 클라우드 특징점을 감지하고 추적합니다.
레이캐스트 추적된 항목에 광선을 비춥니다.
앵커 공간상의 임의의 지점을 추적합니다.
메싱 환경의 메시를 생성합니다.
환경 프로브 환경의 큐브맵을 생성합니다.
폐색 AR 콘텐츠를 물리적 객체로 가리고 인간 세분화를 수행합니다.
참가자들 공유된 AR 세션에서 다른 기기를 추적합니다.

 

AR을 개발하기 위해 플랫폼마다  개발킷이 존재하는데 이를 통합했다고 보면  되는데 지원하는 해당기능은 다음과 같다.

Feature ARCore ARKit OpenXR
Session Yes Yes Yes Yes Yes
Device tracking Yes Yes Yes Yes Yes
Camera Yes Yes     Yes
Plane detection Yes Yes Yes Yes Yes
Image tracking Yes Yes Yes    
Object tracking   Yes      
Face tracking Yes Yes      
Body tracking   Yes      
Point clouds Yes Yes      
Raycasts Yes Yes   Yes Yes
Anchors Yes Yes Yes Yes Yes
Meshing   Yes Yes Yes  
Environment probes Yes Yes      
Occlusion Yes Yes      
Participants   Yes    

 

UnityMars를 통해 시뮬레이션도 가능하다고 함. 뭘까?

3,91f 버전 설치

우리집이 아니라 처음부터 다시해야한다. ㅠㅠ APK도 추가하고 핸드폰 드라이버도 깔아야한다. 기종마다 다르니 메이커에 가서 다운 받아야 한다.

하이라키에 +XR>AR Sesssion 추가

하이라키에 +XR>AR Sesssion Origin 추가  AR Camera를 선택하고 Facing Direction을 User로 한다. 전면카메라는 뜻한다. 참고로 World는 후면카메라

 

하이라키 +XR>AR Default Face 추가

하이라키의 AR Default Face를 끌어다 프리팹으로 만든다. 이름을 MyMask로 한다. 프리팹 폴더를 만들어 넣어도 된다. 프리팹을 만들었으면 하이라키의 AR Default Face는 지우자

히이라키 AR Session Origin에 AR Face Manager 컴포넌트를 추가하자

방금 만든 프리팹 MyMask를 끌어다 놓자

빌드andRun을 눌러보자 빌드하고 실행해보면 전면카메라를 보면 노란 마스크가 보여야한다. 

좀 멋있는 마스크를 적용하기 위해 구글에서 Mask PNG를 이미지로 검색해 투명한 배경이 있는 마스크를 골라 다운로드 한다. 

이걸 Asset폴더에 Material을 만들고 끌어다 놓는다.

Material Folder를 만들고

머터리얼을 하나 Create하고 M_Mask라고 한다.

Inspector Albedo왼쪽에 M_Mask를 끌어다 놓는다. Rendering Mode는 cutout으로 한다.

이제 머터리얼을 만들었으니 이 머터리얼을 오브젝트에 띄워줘야한다.

하이라키에서 3D Object에서 Quad를 추가하고 Mask로 이름 바꾸주고 사이즈를 변경한다.

머터리얼도 적용해준다.

이상태라면 마스크가 얼굴 중앙에 오므로 좀 올려주가 위해 다시 CreateEmpt를 Create하고 MyMask로 이름을 바구고 방금 만든 Mak를 자식으로 끌어다 놓고 위치를 0.025로 올린다.

이제 MyMask를 프리팹으로 만들고 AR Session Origne>AR Face Manager의 FacePrefab을 바꾼다.

빌드하면 얼굴에 가면이 보인다.

이제 UI를 만들어 가면을 껏다 켰다 해보겠다. 하이라키+ UI>Legacy>Button을 선택하면 Cavas의 자식으로 Button이 생긴다.

Cavas를 선택하고 UI Scale Mode를 1080x1920으로 바꾼다.

2D 모드로 바꾼다.

Button을 선택하고  앵커는 아래쪽 중앙 포지션 사이즈를 다음과 같이 바군다.

그럼 버튼이 화면 아래 생긴다.

버튼에 이미지를 입혀주기 위해 Mask PNG를 ctrl-D카피한다 이름을 Mask_Btn으로 바꾼다. Inspector 뷰에서 Text Type을 2D and UI로 바꾼다 Transparency도 체크한다. Apply

하이라키의 Button을 클릭하고 Image를 Mask_btn으로 끌어다 넣어준다. 그럼 UI가 Mask로 바뀐다.

오랜만에 스크립트를 하나 만들고 UI_Manager라고 하자

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARCore;

public class UI_Manager : MonoBehaviour
{
    public ARFaceManager faceManager;

    public void ToggleMask()
    {
        foreach(ARFace face in faceManager.trackables)
        {
            if (face.trackingState == UnityEngine.XR.ARSubsystems.TrackingState.Tracking)
            {
                // face오브젝트 상태를 반대로 변경
                face.gameObject.SetActive(!face.gameObject.activeSelf);
            }
        }
    }
    // Start is called before the first frame update
    void Start(){}

    // Update is called once per frame
    void Update(){ }
}

이제 UI_Manager Script안의 ToggleMask()를 버튼과 연결해야한다.

 그런데 스크립트는 게임오브젝트와 연결이 안되기 때문에 스크립트를 일단 하라라키의 Cavnas아이콘위에 놓으면 자동으로 컴포넌트로 연결한다. 끌어다 놓으면 된다. 

연결후 AR SEssion Origne을 끌어다 FaceManger와 연결해준다.

다음 버튼을 선택하고 OnClick() +를 누르고 Canvas를 끌어다 놓는다. ToggleMask()함수를 선택한다.

마지막으로 가면이 처음에는 안보이게 

MyMask Prefab을 열고 체크박스를 해제하자.

이제 빌드런 해보면 처음에는 마스크가 안 나온지만 밑 버튼을 누르면 나온다.

+ Recent posts