미디어 콘텐츠 스터디
12. 얼굴 메이커 만들기 본문
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/ 폴더에 이름을 ARFaceMaker로 저장합니다.
② Hierarchy 창에서 Main Camera를 삭제합니다.
③ GameObject | XR | AR Session 메뉴를 선택하여 Hierarchy 창에 AR Session을 추가합니다.
④ GameObject | XR | XR Origin 메뉴를 선택하여 Hierarchy 창에 XR Origin 을 추가합니다.
1.1 AR Face Manager 설정하기
① Hierarchy 창에서 XR Origin오브젝트를 선택하고 Inspector 창에 Add Component 버튼을 클릭하여 AR Face Manager 컴포넌트를 추가합니다.
② Hierarchy 창에서 GameObject | XR | AR Default Face을 선택하여 오브젝트를 추가하고 Inspector 창에서 Trasform 초기화하고 Mesh Collider 컴포넌트 삭제합니다.
- AR Default Face를 선택하고 Inspector 창에서 Add Componet 버튼을 클릭하여 ChangeableFace 스립트를추가합니다.
ChangeableFace.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
public class ChangeableFace : MonoBehaviour
{
GameObject currentPosePrefab;
GameObject poseObj;
Dictionary<GameObject, GameObject> accessories = new Dictionary<GameObject, GameObject>();
ARFaceMeshVisualizer meshVisualizer;
MeshRenderer renderer;
private void Start()
{
meshVisualizer = GetComponent<ARFaceMeshVisualizer>();
meshVisualizer.enabled = false;
renderer = GetComponent<MeshRenderer>();
renderer.enabled = false;
}
public void SetPosePrefab(GameObject prefab)
{
if (prefab == currentPosePrefab)
return;
if (poseObj != null)
Destroy(poseObj);
currentPosePrefab = prefab;
if (prefab != null)
poseObj = Instantiate(prefab, transform, false);
}
public void AddAccessory(GameObject prefab)
{
GameObject obj;
if (accessories.TryGetValue(prefab, out obj) && obj.activeInHierarchy)
{
obj.SetActive(false);
return;
}
else if (obj != null)
{
obj.SetActive(true);
}
else
{
obj = Instantiate(prefab, transform, false);
accessories.Add(prefab, obj);
}
}
public void ResetAccessories()
{
foreach (GameObject prefab in accessories.Keys)
{
accessories[prefab].SetActive(false);
}
}
public void SetMeshMaterial(Material mat)
{
if (mat == null)
{
meshVisualizer.enabled = false;
renderer.enabled = false;
return;
}
renderer.material = mat;
meshVisualizer.enabled = true;
renderer.enabled = true;
}
}
- AR Default Face를 선택하고 Inspector 창에서 Add Componet 버튼을 클릭하여 FaceRegionAttachments스립트를추가합니다.
FaceRegionAttachments.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using UnityEngine.XR.ARFoundation;
#if UNITY_ANDROID
using UnityEngine.XR.ARCore;
#endif
public class FaceRegionAttachments : MonoBehaviour
{
ARFaceManager faceManager;
ARFace face;
Dictionary<ARCoreFaceRegion, GameObject> prefabs = new Dictionary<ARCoreFaceRegion, GameObject>();
Dictionary<ARCoreFaceRegion, GameObject> objs = new Dictionary<ARCoreFaceRegion, GameObject>();
#if UNITY_ANDROID && !UNITY_EDITOR
NativeArray<ARCoreFaceRegionData> faceRegions;
#endif
private void Start()
{
faceManager = FindObjectOfType<ARFaceManager>();
face = GetComponent<ARFace>();
}
public void SetRegionAttachment(ARCoreFaceRegion region, GameObject prefab)
{
GameObject obj;
if (objs.TryGetValue(region, out obj))
{
GameObject currentPrefab = prefabs[region];
Destroy(obj);
prefabs.Remove(region);
objs.Remove(region);
if (prefab == currentPrefab)
return;
}
obj = Instantiate(prefab);
prefabs.Add(region, prefab);
objs.Add(region, obj);
}
public void Reset()
{
foreach (ARCoreFaceRegion region in objs.Keys)
{
Destroy(objs[region]);
}
objs.Clear();
prefabs.Clear();
}
private void Update()
{
#if UNITY_ANDROID && !UNITY_EDITOR
var subsystem = (ARCoreFaceSubsystem)faceManager.subsystem;
if (subsystem == null)
return;
subsystem.GetRegionPoses(face.trackableId, Allocator.Persistent, ref faceRegions);
for (int i = 0; i < faceRegions.Length; ++i)
{
GameObject obj;
if (objs.TryGetValue(faceRegions[i].region, out obj))
{
obj.transform.localPosition = faceRegions[i].pose.position;
}
}
#endif
}
void OnDestroy()
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (faceRegions.IsCreated)
faceRegions.Dispose();
#endif
}
}
③ Hierarchy 창에서 Project 창의 Prefabs 폴더로 AR Default Face 오브젝트를 드래그하여 프리팹으로 만듭니다.
④ Hierarchy 창에서 AR Default Face 오브젝틀르 삭제합니다.
⑤ Hierarchy 창에서 XR Origin 오브젝트를 선택하고 Inspector 창에서 AR Face Manager 의 Face Prefab에 AR Default Face 프리팹을 설정합나다.
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 : Face Maker
③ 메인 메뉴에서 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 을 추가한후 이름을 MainMenu Panel로 변경합니다.
- Info Panel 하위에 메인 메뉴에서 GameObject | UI | Scroll View 을 선택하여 Scroll View를 추가한 후 Scroll View를 선택하고 Inspector 창에 Image 컴포넌트를 삭제합니다.
- Scroll View 하위에 Viewport를 선택하고 Inspector 창에 Image 컴포넌트를 삭제합니다.
- Scroll View하위에 Scrollbar Horizontal와 Scrollbar Vertical 오브젝트를 삭제합니다.
⑤ Scroll View=> Viewport 하위에 Content를 선택하고 Inspector 창에 Horizontal Layout Group와 Content Size Filter 컴포넌트를 추가합니다.
⑥ Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 Reset Button으로 변경하고 Inspector창에서 Image 컴포넌트를 삭제하고 Reset Button하위의 Text에 Reset을 입력합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 PlasticHead Button으로 변경하고 PlasticHead Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 FacetHead Button으로 변경하고 FacetHead Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 HatAccessory Button으로 변경하고 HatAccessory Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 SunglassesAccessory Button으로 변경하고 SunglassesAccessory Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 DefaultFace Button으로 변경하고 DefaultFace Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 PhotoFace Button으로 변경하고 PhotoFace Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 PopFace Button으로 변경하고 PopFace Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 RobotFace Button으로 변경하고 RobotFace Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 Eyebrows Buttonn으로 변경하고 Eyebrows Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 Mustache Button으로 변경하고 Mustache Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
- Scroll View=> Viewport=> Content 하위에 GameObject | UI | Button를 선택하여 Button를 추가한후 이름을 Lips Button으로 변경하고 Lips Button 하위의 Text를 삭제합니다。 Inspector 창에 Image 컴포넌트에 Source Image를 설정합니다.
⑤ 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 하위에 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
{
void OnEnable()
{
UIController.ShowUI("Startup");
}
void Update()
{
if (ARSession.state == ARSessionState.Unsupported)
{
InteractionController.EnableMode("Startup");
}
else if (ARSession.state >= ARSessionState.Ready)
{
InteractionController.EnableMode("Main");
}
}
}
③ 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;
using UnityEngine.XR.ARFoundation;
#if UNITY_ANDROID
using UnityEngine.XR.ARCore;
#endif
public class FaceMainMode : MonoBehaviour
{
[SerializeField] ARFaceManager faceManager;
void OnEnable()
{
UIController.ShowUI("Main");
}
public void ChangePosePrefab(GameObject prefab)
{
foreach (ARFace face in faceManager.trackables)
{
ChangeableFace changeable = face.GetComponent<ChangeableFace>();
if (changeable != null)
{
changeable.SetPosePrefab(prefab);
}
}
}
public void AddAccessory(GameObject prefab)
{
foreach (ARFace face in faceManager.trackables)
{
ChangeableFace changeable = face.GetComponent<ChangeableFace>();
if (changeable != null)
{
changeable.AddAccessory(prefab);
}
}
}
public void ChangeMaterial(Material mat)
{
foreach (ARFace face in faceManager.trackables)
{
ChangeableFace changeable = face.GetComponent<ChangeableFace>();
if (changeable != null)
{
changeable.SetMeshMaterial(mat);
}
}
}
public void ResetFace()
{
foreach (ARFace face in faceManager.trackables)
{
ChangeableFace changeable = face.GetComponent<ChangeableFace>();
FaceRegionAttachments regionAttachments = face.GetComponent<FaceRegionAttachments>();
if (changeable != null)
{
changeable.SetPosePrefab(null);
changeable.ResetAccessories();
changeable.SetMeshMaterial(null);
regionAttachments.Reset();
}
}
}
public void SetNoseAttachment(GameObject prefab)
{
SetRegionAttachment(ARCoreFaceRegion.NoseTip, prefab);
}
public void SetForeheadLeftAttachment(GameObject prefab)
{
SetRegionAttachment(ARCoreFaceRegion.ForeheadLeft, prefab);
}
public void SetForeheadRightAttachment(GameObject prefab)
{
SetRegionAttachment(ARCoreFaceRegion.ForeheadRight, prefab);
}
private void SetRegionAttachment(ARCoreFaceRegion region, GameObject prefab)
{
foreach (ARFace face in faceManager.trackables)
{
FaceRegionAttachments regionAttachments = face.GetComponent<FaceRegionAttachments>();
if (regionAttachments != null)
{
regionAttachments.SetRegionAttachment(region, 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);
}
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 항목에 +버튼을 클릭하여 항목을 추가합니다.
ARCoreOnly.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ARCoreOnly : MonoBehaviour
{
private void Awake()
{
#if !UNITY_ANDROID
gameObject.SetActive(false);
#endif
#if UNITY_EDITOR
Button button = GetComponent<Button>();
button.interactable = false;
#endif
}
}
4. UI의 Button에 Onclick() 이벤트 설정하기
② Hierarchy 창에서 Main UI=>...=> Reset Button를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
- Hierarchy 창에서 Main UI=>...=> FacetHead Button 를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
- Hierarchy 창에서 Main UI=>...=> HatAccessory Button 를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
-Hierarchy 창에서 Main UI=>...=> HatAccessory Button를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
- Hierarchy 창에서 Main UI=>...=> SunglassesAccessory Button 를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
- Hierarchy 창에서 Main UI=>...=> DefaultFace Button 를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
Hierarchy 창에서 Main UI=>...=> PhotoFace Button를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
- Hierarchy 창에서 Main UI=>...=>PopFace Button를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
- Hierarchy 창에서 Main UI=>...=> RobotFace Button를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
Hierarchy 창에서 Main UI=>...=> Eyebrows Button를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
- Hierarchy 창에서 Main UI=>...=>Mustache Button를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
- Hierarchy 창에서 Main UI=>...=> Lips Button를 선택하고 Inspector 창에서 On Click() 이벤트에 다음과 같이 설정합니다.
'증강현실(Augmented Reality) > ARCore 사용하기' 카테고리의 다른 글
11. 행성 카드 만들기 (0) | 2023.11.05 |
---|---|
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 |