미디어 콘텐츠 스터디
11. 행성 카드 만들기 본문
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/ 폴더에 이름을 ARGallery로 저장합니다.
② Hierarchy 창에서 Main Camera를 삭제합니다.
③ GameObject | XR | AR Session 메뉴를 선택하여 Hierarchy 창에 AR Session을 추가합니다.
④ GameObject | XR | XR Origin 메뉴를 선택하여 Hierarchy 창에 XR Origin 을 추가합니다.
1.1 AR Tracked Image Manager 설정하기
Hierarchy 창에 XR Origin 을 선택하고 Inspector창에서 Add Component 버튼을 클릭하여 AR Tracked Image Manager 컴포넌트를 추가합니다.
① Project 창에서 Asset 폴더 하위에 Images 폴더를 만들고 여기서 오른쪽 마우스 버튼을 선택하여 Create->XR->Reference Image Libray 메뉴를 선택합니다.
② 생성된 ReferenceImageLibray를 선택한 후, Inspector 창에 Add Image 버튼을 클릭하여 인식할 이미지를 등록합니다.
③ Hierarchy 창에 XR Origin 을 선택하고 Inspector창에서 AR Tracked Image Manager의 Serialized Library 속성값에 ReferenceImageLibray를 설정합니다.
1.2 AR 오브젝트 추적하기
① Hierarchy 창에서 XR Origin 오브젝트를 선택하고 Inspector 창에 Add Component 버튼을 클릭하여 AR Raycast Manager 컴포넌트를 추가합니다.
2. UI 만들기
2.1 기본 프레임 UI 만들기
① 메인 메뉴에서 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로 변경하여 설정
메인 메뉴에서 GameObject | UI | Text를 선택하여 App Title Panel 하위에 Text를 추가하고 이름을 Title Text로 변경합니다.
- Text Input : Planet Explorer
③ 메인 메뉴에서 GameObject | Create Empty를 선택하여 UI Canvas 하위에 GameObject를 추가하고 이름을 Startup UI로 변경하고 Inspector 창에 Add Component 버튼을 클릭하여 Canvas Renderer와 Canvas Group 컴포넌트를 추가합니다. 메인 메뉴에서 GameObject | UI | Text를 선택하여 Startup UI 하위에 Text를 추가합니다.
④ 메인 메뉴에서 GameObject | Create Empty를 선택하여 UI Canvas 하위에 GameObject을 추가하고 이름을 Main UI로 변경하고 Inspector 창에 Add Component 버튼을 클릭하여 Canvas Renderer와 Canvas Group 컴포넌트를 추가합니다.
Main UI 하위에 메인 메뉴에서 GameObject | UI | Panel을 선택하여 Panel 을 추가한후 이름을 Info Panel로 변경합니다.
- Info Panel 하위에 메인 메뉴에서 GameObject | UI | Text 을 선택하여 Text를 추가한 후 이름을 Planet Name Text로 변경합니다. 인스펙터 창에서 Text Input에 [Planet name]을 입력합니다.
- Add Button 하위의 메인 메뉴에서 GameObject | UI | Button을 선택하여 Button 를 추가한 후 이름을 Info Button로 변경합니다. Info Button 하위의 Text를 선택하여 설정합니다.
- Add Button 하위의 메인 메뉴에서 GameObject | UI | Text을 선택하여 Text 를 추가한 후 Text를 선택하여 설정합니다.
④ Main UI 하위에 메인 메뉴에서 GameObject | UI | Panel 을 선택하여 Panel 을 추가하고 이름을 Details Panel로 변경합니다
Details Panel 하위에 메인 메뉴에서 GameObject | UI | Text 을 선택하여 Text 을 추가하고 이름을 Details Text로 변경합니다
Hierarchy 창에서 UI Canvas를 선택하고 인스펙터 창에서 Add Component 버튼을 클릭하여 UIController.cs 스크립트를 추가합니다.
UIController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIController : MonoBehaviour
{
private Dictionary<string, CanvasGroup> uiPanels = new Dictionary<string, CanvasGroup>();
CanvasGroup currentPanel;
private static UIController Instance = null;
public CanvasGroup[] canvasGroups;
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 하위에 오브젝트들을 설정합니다.
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] ARTrackedImageManager imageManager;
void OnEnable()
{
UIController.ShowUI("Startup");
}
void Update()
{
if (ARSession.state == ARSessionState.Unsupported)
{
InteractionController.EnableMode("NonAR");
}
else if (ARSession.state >= ARSessionState.Ready)
{
if (imageManager.trackables.count > 0)
{
InteractionController.EnableMode("Main");
}
}
}
}
- Hierarchy 창에서 Interaction Controller 오브젝트 하위에 GameObject | Create Empty 메뉴를 선택하여 빈 오브젝트를 생성하고 이름을 MainMode로 설정합니다. Transform은 초기화합니다. Inspector 창에 Add Component 버튼을 클릭하여 PlanetsMainMode.cs 컴포넌트를 추가합니다.
PlanetsMainMode.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using TMPro;
using UnityEngine.UI;
public class PlanetsMainMode : MonoBehaviour
{
[SerializeField] ARTrackedImageManager imageManager;
[SerializeField] TMP_Text planetName;
[SerializeField] Toggle infoButton;
[SerializeField] GameObject detailsPanel;
[SerializeField] TMP_Text detailsText;
private Dictionary<string, GameObject> planetPrefabs = new Dictionary<string, GameObject>();
[SerializeField] private GameObject[] gameObjects;
Camera camera;
int layerMask;
void Awake()
{
planetPrefabs.Add("Earth", gameObjects[0]);
planetPrefabs.Add("Mars", gameObjects[1]);
}
void Start()
{
camera = Camera.main;
layerMask = 1 << LayerMask.NameToLayer("PlacedObjects");
}
void OnEnable()
{
UIController.ShowUI("Main");
planetName.text = "";
infoButton.interactable = false;
detailsPanel.SetActive(false);
foreach (ARTrackedImage image in imageManager.trackables)
{
InstantiatePlanet(image);
}
imageManager.trackedImagesChanged += OnTrackedImageChanged;
}
void OnDisable()
{
imageManager.trackedImagesChanged -= OnTrackedImageChanged;
}
void Update()
{
if (imageManager.trackables.count == 0)
{
Debug.Log("PlanetsMainMode no trackables, going to Scan mode");
InteractionController.EnableMode("Scan");
}
else
{
Ray ray = new Ray(camera.transform.position, camera.transform.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask))
{
Planet planet = hit.collider.GetComponentInParent<Planet>();
planetName.text = planet.planetName;
detailsText.text = planet.description;
infoButton.interactable = true;
}
else
{
planetName.text = "";
detailsText.text = "";
infoButton.interactable = false;
}
}
}
void OnTrackedImageChanged(ARTrackedImagesChangedEventArgs eventArgs)
{
foreach (ARTrackedImage newImage in eventArgs.added)
{
InstantiatePlanet(newImage);
}
}
void InstantiatePlanet(ARTrackedImage image)
{
string name = image.referenceImage.name.Split('-')[0];
if (image.transform.childCount == 0)
{
//Debug.Log($"adding {name}");
GameObject planet = Instantiate(planetPrefabs[name]);
planet.transform.SetParent(image.transform, false);
}
else
{
Debug.Log($"{name} already instantiated");
}
}
}
PlanetPrefabDictionary.cs의 Planet Prefab 속성값의 프리팹만들기
[Earth Prefab]
- Hierarchy 창에서 메인메뉴 GameObject | Create Empty 메뉴를 선택하여 빈 오브젝트를 생성하고 이름을 Earth Prefab로 설정합니다. Transform은 초기화합니다.
- Earth Prefab 하위에 메인메뉴 GameObject | Create Empty 메뉴를 선택하여 빈 오브젝트를 생성하고 이름을 Incline로 설정합니다. Transform은 초기화합니다.
- Incline 하위에 메인메뉴 GameObject | 3D Object | Sphere 메뉴를 선택하여 Sphere 를 추가하고 이름을 Planet로 설정합니다. Transform은 초기화합니다. earth 재질을 설정합니다.
- Earth Prefab를 선택한 Inspector 창에 Add Component 버튼을 클릭하여 Planet.cs 컴포넌트를 추가합니다.
Planet.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Planet : MonoBehaviour
{
public string planetName = "Earth";
public string description;
[SerializeField] private float inclineDegrees = 23.4f;
[SerializeField] private float rotationPeriodHours = 24f;
[SerializeField] private Transform incline;
[SerializeField] private Transform planet;
public float animationHoursPerSecond = 1.0f;
void Start()
{
incline.Rotate(0f, 0f, inclineDegrees);
}
void Update()
{
float speed = rotationPeriodHours * animationHoursPerSecond;
planet.Rotate(0f, speed * Time.deltaTime, 0f);
}
}
- Description: Earth is the third planet from the Sun and the only astronomical object known to harbor and support life.
- Hierarchy 창에서 Earth Prefab 를 프리팹으로 만들고, 삭제합니다.
[Mars Prefab]
- Hierarchy 창에서 메인메뉴 GameObject | Create Empty 메뉴를 선택하여 빈 오브젝트를 생성하고 이름을 Mars Prefab로 설정합니다. Transform은 초기화합니다.
- Mars Prefab 하위에 메인메뉴 GameObject | Create Empty 메뉴를 선택하여 빈 오브젝트를 생성하고 이름을 Incline로 설정합니다. Transform은 초기화합니다.
- Incline 하위에 메인메뉴 GameObject | 3D Object | Sphere 메뉴를 선택하여 Sphere 를 추가하고 이름을 Planet로 설정합니다. Transform은 초기화합니다. mars 재질을 설정합니다.
- Mars Prefab를 선택한 Inspector 창에 Add Component 버튼을 클릭하여 Planet.cs 컴포넌트를 추가합니다.
- Description: Mars is the fourth planet from the Sun and the second-smallest planet in the Solar System
- Hierarchy 창에서 Mars Prefab 를 프리팹으로 만들고, 삭제합니다.
- Hierarchy 창에서 Interaction Controller 오브젝트를 선택하고 Inspector 창에 Add Component 버튼을 클릭하여 InteractionController.cs 컴포넌트를 추가합니다.
InteractionController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InteractionController : MonoBehaviour
{
private Dictionary<string, GameObject> interactionModes = new Dictionary<string, GameObject>();
[SerializeField] private GameObject[] gameObjects;
GameObject currentMode;
private static InteractionController Instance = null;
void Awake()
{
interactionModes.Add("Startup", gameObjects[0]);
interactionModes.Add("Main", gameObjects[1]);
if (null == Instance)
{
Instance = this;
}
ResetAllModes();
}
void Start()
{
_EnableMode("Startup");
}
public static void EnableMode(string name)
{
// Instance?._EnableMode(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);
}
}
실행하기
'증강현실(Augmented Reality) > ARCore 사용하기' 카테고리의 다른 글
12. 얼굴 메이커 만들기 (0) | 2023.11.11 |
---|---|
10. 다중 이미지 추적하기(Multiple Image Tracking) (0) | 2023.10.12 |
09. AR 갤러리 만들기 (0) | 2023.10.06 |
08. 다중 오브젝트 배치하기(Multiple Object Placement) (0) | 2023.10.03 |
07. 얼굴 필터 만들기(Face Filter) (0) | 2023.09.29 |