미디어 콘텐츠 스터디

08. 다중 오브젝트 배치하기(Multiple Object Placement) 본문

증강현실(Augmented Reality)/ARCore 사용하기

08. 다중 오브젝트 배치하기(Multiple Object Placement)

danmujicat 2023. 10. 3. 18:02

AR 개발을 위한 프로젝트를 준비하기 위해 Window | Package Manangement 메뉴를 선택하여  Package Manangement 창을 열고 AR 장치 플러그인을 설치합니다.

1장의  ARCore 개발을 위한 환경 구축하기 참고하세요

더보기
  •  AR 장치용 XR plugins 설치하기
  • ARCore XR Plugin 설치하기
  • AR Foundation 패키지 설치하기
  • Input System 설치하기
  • Androd 플랫폼의 ARcore 설정하기
  • Player 설정하기

 

1. 기본 AR 장면 만들기

① File | Save As 메뉴를 선택하여  Assets/Scenes/ 폴더에 이름을 ARPart08으로  저장합니다.

② Hierarchy 창에서 Main Camera를 삭제합니다.

③ GameObject |  XR | AR Session 메뉴를 선택하여 Hierarchy 창에 AR Session을 추가합니다.

④ GameObject |  XR | XR Origin  메뉴를 선택하여 Hierarchy 창에 XR Origin 을 추가합니다.

 

1.1 AR Default Point Cloud 프리팹 설정하기

① Hierarchy 창에서 AR Session Origin 오브젝트를 선택하고 Inspector 창에 Add Component 버튼을 클릭하여 AR Point Cloud Manager 컴포넌트를 추가합니다. 

② Hierarchy 창에서 GameObject | XR | AR Default Point Cloud을 선택하여 오브젝트를 추가합니다.

③ Hierarchy 창에서 Project 창의 Prefabs 폴더로 AR Default Point Cloud 오브젝트를 드래그하여 프리팹으로 만듭니다.

 Hierarchy 창에서  AR Default Point Cloud  오브젝틀르 삭제합니다.

⑤  Hierarchy 창에서 XR Origin 오브젝트를 선택하고 Inspector 창에서 AR Point Cloud Manager의 Point Cloud Prefab에 AR Default Point Cloud 프리팹을 설정합나다.

 

1.2  AR Default Plane 프리팹 설정하기

① Hierarchy 창에서 AR Session Origin 오브젝트를 선택하고 Inspector 창에 Add Component 버튼을 클릭하여 AR  Plane Manager 컴포넌트를 추가합니다.

② Hierarchy 창에서 GameObject | XR | AR Default Plane을 선택하여 오브젝트를 추가합니다.

③ Hierarchy 창에서 Project 창의 Prefabs 폴더로 AR Default Plan 오브젝트를 드래그하여 프리팹으로 만듭니다.

 Hierarchy 창에서  AR Default Plane  오브젝틀르 삭제합니다.

⑤  Hierarchy 창에서 XR Origin 오브젝트를 선택하고 Inspector 창에서 AR  Plane Manager 의 Plane Prefab에 AR Default Plane 프리팹을 설정합나다.

    - Detection Mode : Horizontal

1.3  AR 오브젝트 추적하기 

 Hierarchy 창에서 XR Origin 오브젝트를 선택하고 Inspector 창에 Add Component 버튼을 클릭하여 AR Raycast Manager 컴포넌트를 추가합니다.

 

2. UI 만들기

image.unitypackage
0.20MB
uploads_files_745381_Microbe.FBX
0.07MB

  메인 메뉴에서  GameObject | UI | Canvas를 선택하여 Canvas를 추가하고 이름을 UI Canvas로 변경하고 Inspector 창에 Canvas Scaler의 UI Scale Mode를 Scale With Screen Size로 설정합니다. 

② 메인 메뉴에서  GameObject | UI | Panel 를 선택하여 UI Canvas  하위에 Panel를 추가하고 이름을 App Title Panel로 변경합니다.

메인 메뉴에서   GameObject | UI | Button를 선택하여  App Title Panel 하위에 Button을 추가하고  이름을 Home Button로 변경합니다.

 - Image 컴포넌트의 Source Image  : home.png을 sprite로 변경하여 설정

home.png
0.01MB

 

메인 메뉴에서  GameObject | UI | Text를 선택하여   App Title Panel 하위에 Text를 추가하고 이름을 Title Text로 변경합니다.

    - Text Input : Multiple Object Placement

    메인 메뉴에서  GameObject | UI | Create Empty를  선택하여 UI Canvas   하위에 GameObject를 추가하고  이름을 Startup UI로 변경하고  Add Component 버튼을 클릭하여 Canvas Group 컴포넌트를 추가합니다. 

메인 메뉴에서  GameObject | UI | Text를 선택하여 Startup UI  하위에  Text를 추가합니다.

 

  메인 메뉴에서  GameObject | Create Empty를   선택하여 UI Canvas   하위에 GameObject   추가하고 이름을 Main UI로 변경하고  Add Component 버튼을 클릭하여 Canvas Group 컴포넌트를 추가합니다. 

메인 메뉴에서 GameObject | UI | Image를 선택하여  Main UI 하위에 Image를  추가하고 이름을 Main Menu로 변경하고 Inspector 창에서 Add Component 버튼을 클릭하여 Horizontal Latout Group 컴포넌트를 추가합니다. 

- Control Child Size : Width와 Height 체크

- 메인 메뉴에서  GameObject | UI | Button 을 선택하여 Main Menu 를 하위에 Button을 추가하고 이름을 Cube Button으로 변경합니다. 메인 메뉴에서  GameObject | UI | Image 을 선택하여 Cube Button 를 하위에 Image을 추가하고   Source Image 속성은 CubeImage를 설정하고, 하위에 Text의 Text속성은 Cube로 입력합니다.  

-  메인 메뉴에서  GameObject | UI | Button 을 선택하여 Main Menu 를 하위에 Button을 추가하고 이름을 Sphere Button으로 변경합니다. 메인 메뉴에서  GameObject | UI | Image 을 선택하여 Cube Button 를 하위에 Image을 추가하고 Source Image  속성은   Sphere Image를 설정하고, 하위에 Text의 Text속성은 Sphere로 입력합니다.  

- 메인 메뉴에서  GameObject | UI | Button 을 선택하여 Main Menu 를 하위에 Button을 추가하고 이름을 Virus Button으로 변경합니다. 하위에 Image의 Source Image  속성은  Virus Image를 설정하고, 하위에 Text의 Text속성은 Virus로 입력합니다.  

 

 Hierarchy 창에서 UI Canvas를 선택하고 인스펙터 창에서 Add Component 버튼을 클릭하여 UIController.cs 스크립트를 추가합니다.

UIController.cs

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

public class UIController : MonoBehaviour
{
    public CanvasGroup[] canvasGroups;   
    private Dictionary<string, CanvasGroup> uiPanels = new Dictionary<string, CanvasGroup>();
    private static UIController Instance = null;
    CanvasGroup currentPanel;

    void Awake()
    {      
        uiPanels.Add("Startup", canvasGroups[0]);
        uiPanels.Add("Main", canvasGroups[1]);

        if (Instance ==null )
        {
            Instance = this;
        }
        ResetAllUI();
    }

    public static void ShowUI(string name)
    {      
        Instance._ShowUI(name);
    }

    void _ShowUI(string name)
    {
        CanvasGroup panel;
        if (uiPanels.TryGetValue(name, out panel))
        {
            ChangeUI(uiPanels[name]);
        }
        else
        {
            Debug.LogError("Undefined ui panel " + name);
        }
    }

    void ResetAllUI()
    {
        foreach (CanvasGroup panel in uiPanels.Values)
        {
            panel.gameObject.SetActive(false);
        }
    }

    void ChangeUI(CanvasGroup panel)
    {
        if (panel == currentPanel)
            return;
        if (currentPanel)        
            currentPanel.gameObject.SetActive(false);
            
        currentPanel = panel;
        
        if (panel)          
        panel.gameObject.SetActive(true);
    }

}

 Hierarchy 창에서 UI Canvas를 선택하고 Inspector 창에서 UIController.cs 스크립트의 UI Panels에서 +버튼을 눌러서 Hierarchy 창의 UI Canvas  하위에 Startup UI와 Main UI를  설정합니다.

 

 

 3. AR 오브젝트와 상호작용하기

 Hierarchy 창에서 GameObject | Create Empty 메뉴를 선택하여 빈 오브젝트를 생성하고 이름을Interaction Controller로 설정합니다. Transform은 초기화합니다.

  Hierarchy 창에서 Interaction Controller  오브젝트 하위에 GameObject | Create Empty 메뉴를 선택하여 빈 오브젝트를 생성하고 이름을 Startup Mode로 설정합니다. Transform은 초기화합니다.  Inspector 창에 Add Component 버튼을 클릭하여 StartupMode.cs 컴포넌트를 추가합니다. 

StartupMode.cs

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

public class StartupMode : MonoBehaviour
{
    [SerializeField] string nextMode = "Main";

     void OnEnable()
    {
        UIController.ShowUI("Startup");
    }

    void Update()
    {
        if (ARSession.state == ARSessionState.Unsupported)
        {
            InteractionController.EnableMode("Startup");
        }
        else if (ARSession.state >= ARSessionState.Ready)
        {
            //Debug.Log("state " + ARSession.state);
            InteractionController.EnableMode(nextMode);
        }
    }
}

  Hierarchy 창에서 Interaction Controller  오브젝트 하위에 GameObject | Create Empty 메뉴를 선택하여 빈 오브젝트를 생성하고 이름을 Main Mode로 설정합니다. Transform은 초기화합니다.  Inspector 창에 Add Component 버튼을 클릭하여 MainMode.cs 컴포넌트를 추가합니다. 

MainMode.cs

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

public class MainMode : MonoBehaviour
{
    void OnEnable()
    {
        UIController.ShowUI("Main");
    }
}

 

  Hierarchy 창에서 Interaction Controller  오브젝트 하위에 GameObject | Create Empty 메뉴를 선택하여 빈 오브젝트를 생성하고 이름을 PlaceObject Mode로 설정합니다. Transform은 초기화합니다.  

- Inspector 창에 Add Component 버튼을 클릭하여 PlaceObjectMode.cs 컴포넌트를 추가합니다. 

PlaceObjectMode.cs

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


public class PlaceObjectMode : MonoBehaviour
{
    [SerializeField] ARRaycastManager raycaster;
 
    GameObject placedPrefab;
    List<ARRaycastHit> hits = new List<ARRaycastHit>();

    void OnEnable()
    {
        UIController.ShowUI("PlaceObject");
    }


    public void SetPlacedPrefab(GameObject prefab)
    {
        placedPrefab = prefab;
    }

    public void OnPlaceObject(InputValue value)
    {
        Vector2 touchPosition = value.Get<Vector2>();
        //Debug.Log("OnPlaceObject " + touchPosition);
        PlaceObject(touchPosition);
    }

    void PlaceObject(Vector2 touchPosition)
    {
        if (raycaster.Raycast(touchPosition, hits, TrackableType.PlaneWithinPolygon))
        {
            Pose hitPose = hits[0].pose;
            Instantiate(placedPrefab, hitPose.position, hitPose.rotation);

            InteractionController.EnableMode("Main");
        }
    }

}

 

Hierarchy 창에서 Interaction Controller => PlaceObject Mode를 선택하고  Inspector 창에 Add Component 버튼을 클릭하여 ShowTrackablesOnEnable.cs 컴포넌트를 추가합니다. 

ShowTrackablesOnEnable.cs

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

public class ShowTrackablesOnEnable : MonoBehaviour
{
    [SerializeField] XROrigin sessionOrigin;
    ARPlaneManager planeManager;
    ARPointCloudManager cloudManager;
    bool isStarted;

    void Awake()
    {
        planeManager = sessionOrigin.GetComponent<ARPlaneManager>();
        cloudManager = sessionOrigin.GetComponent<ARPointCloudManager>();
    }

     void Start()
    {
        isStarted = true;
    }

    void OnEnable()
    {
        ShowTrackables(true);
    }

    void OnDisable()
    {
        if (isStarted)
        {
            ShowTrackables(false);
        }
    }


    void ShowTrackables(bool show)
    {
        if (cloudManager)
        {
            cloudManager.SetTrackablesActive(show);
            cloudManager.enabled = show;
        }
        if (planeManager)
        {
            planeManager.SetTrackablesActive(show);
            planeManager.enabled = show;
        }
    }
}

 

  Hierarchy 창에서 Interaction Controller  오브젝트를 선택하고 Inspector 창에 Add Component 버튼을 클릭하여 InteractionController.cs 컴포넌트를 추가합니다. 

InteractionController.cs 

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

public class InteractionController : MonoBehaviour
{
   
    [SerializeField]   private GameObject[] gameObjects;
    private Dictionary<string, GameObject> interactionModes = new Dictionary<string, GameObject>();
    GameObject currentMode;
    private static InteractionController Instance = null;
    
    void Awake()
    {
       
        interactionModes.Add("Startup", gameObjects[0]);
        interactionModes.Add("Main", gameObjects[1]);
        interactionModes.Add("PlaceObject", gameObjects[2]);
        if (null == Instance)
        {
            Instance = this;
        }
            ResetAllModes();
    }

    void Start()
    {       
        _EnableMode("Startup");
    }

    public static void EnableMode(string name)
    {
        Instance._EnableMode(name);
    }

    void _EnableMode(string name)
    {
        GameObject modeObject;
        if (interactionModes.TryGetValue(name, out modeObject))
        {
            StartCoroutine(ChangeMode(modeObject));
        }
        else
        {
            Debug.LogError("undefined mode named " + name);
        }
    }

    void ResetAllModes()
    {
        foreach (GameObject mode in interactionModes.Values)
        {
            mode.SetActive(false);
        }
    }

    IEnumerator ChangeMode(GameObject mode)
    {
        if (mode == currentMode)
            yield break;

        if (currentMode)
        {
            currentMode.SetActive(false);
            yield return null;
        }

        currentMode = mode;
        mode.SetActive(true);
    }

}

 Hierarchy 창에서 Interaction Controller  오브젝트를 선택하고 Inspector 창에서 Game Objects 항목에 +버튼을 클릭하여 항목을 추가합니다.

 

4. UI의 Button에 Onclick() 이벤트 설정하기 

메인 메뉴에서  GameObject | 3D Object | Cube를 선택하여 Cube 추가하고 이름을 AR Placed Cube로 변경하고 프리팹으로 만듭니다.

- 메인 메뉴에서  GameObject | 3D Object | Sphere를 선택하여 Sphere 추가하고 이름을 AR Placed Sphere 로 변경하고 프리팹으로 만듭니다.

- Hierarchy 창에 Vvirus.fbx 모델링을 추가하고 이름을 Virus  로 변경하고 프리팹으로 만듭니다.

  Hierarchy 창에서 Main UI=>Main Menu=> Cube Button를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다. 

 - Hierarchy 창에서 Main UI=>Main Menu=> Sphere Button 를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.  

 - Hierarchy 창에서 Main UI=>Main Menu=> Virus Button  를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다. 

 

실행하기

 

 

 

[입력이 안되는 경우]

* Hierarchy 창에서 Interaction Controller  오브젝트를 선택하고  Inspector 창에 Add Component 버튼을 클릭하여 Player Input 컴포넌트를 추가하고 Behavior 속성값에 Broadcast Messages로 설정합니다.

input.unitypackage
0.00MB

Comments