์๋ ํ์ธ์. ์ด๋ฒ ๊ธ์ Unity AR ํ๊ฒฝ์์ ์ค์๊ฐ์ผ๋ก ์ค๋ธ์ ํธ์ ์ง์ "์"์ผ๋ก ์ํธ์์ฉํ ์ ์๊ฒ ํ๋๋ก ๋ง๋ค์ด๋ณด๊ณ ์ ํฉ๋๋ค. Unity ์์ฒด์์๋ "์ ์ถ์ " ๊ด๋ จํ ํด์ ์ ๊ณตํ์ง ์๊ธฐ์ ์ธ๋ถ SDK์ธ ManoMotion์ ์ด์ฉํฉ๋๋ค. ํ๊ฒฝ์ ๊ตฌ์ถํ๋๋ฐ ๋ชจ๋ ๊ณผ์ ์ ๋ด์ผ๋ ค๋ฉด ๊ธ ํ๋๋ก๋ ๋ฒ ์ฐฐ ์ ์๊ธฐ์ ํต์ฌ์ ์ธ ๋ถ๋ถ๊ณผ ์ ๊ฐ ์ฐธ๊ณ ํ ์์์ ์ฒจ๋ถํ๊ฒ ์ต๋๋ค. ์์์ ๋ชจ๋ ๊ณผ์ ์ ๋ด์์ฃผ๊ธฐ์ ๋๊ตฌ๋ ์ฝ๊ฒ ์ฐธ๊ณ ํ์ค ์ ์์ ๊ฒ์ ๋๋ค.
https://youtube.com/shorts/viodtUDVm_4?feature=share
ManoMotion ๋ฌด์์ธ๊ฐ?
ManoMotion์ ์ ์ธ์ ๊ธฐ์ ์ ๊ฐ๋ฐํ๋ ํ์ฌ๋ก, ์ ๋ชจ์ ๋ฐ ์ ์ค์ฒ๋ฅผ ์ฌ์ฉํ์ฌ ์ธํฐ๋์ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ๊ธฐ ์ํ SDK๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ชจ๋ฐ์ผ ๊ธฐ๊ธฐ์ ์นด๋ฉ๋ผ๋ฅผ ํตํด์๋ ์ฌ์ฉ์์ ์์ ์์น, ์์ง์, ๋์ ๋ฑ์ ์ค์๊ฐ์ผ๋ก ์ถ์ ํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๋ฌํด ์ค๋๋ค. Unity ๋ฐ Unreal ๊ฐ์ ๊ฒ์ ์์ง์๋ ํตํฉ๋์ด ์ฝ๊ฒ ์ฑ ๋๋ ๊ฒ์์๋ ํตํฉํ ์ ์์ต๋๋ค.
Unity ์์์ "์ ์ถ์ " ์ ์ํด MediaPipe๋ฅผ ์ฌ์ฉํ ์๋ ์์ง๋ง, ManoMotion์ ์ ์ธ์๊ณผ ์ ์ค์ฒ ๊ธฐ๋ฅ์ ์ค์ ์ ๋์์ง๋ง MediaPipe๋ ๊ฐ์ฒด ์ถ์ , ๋์ ์ธ์, ์ผ๊ตด ๊ฐ์ง ๋ฑ ๋ค์ํ ๋น์ ๋ฐ ์ค๋์ค ์ฒ๋ฆฌ ์๊ณ ๋ฆฌ์ฆ์ ์ ๊ณตํ๊ณ ์์ด ๋์ ๋ชฉ์ ๊ณผ ์ง์ํ๋ ค๋ ๊ธฐ๋ฅ์์ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
๋ํ, ManoMotion SDK๋ ์ด๋ฏธ ๊ฐ๋ฐ๋ ์๊ณ ๋ฆฌ์ฆ๊ณผ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ๋ฉด, MediaPipe๋ ์ ๊ณต๋ ๋๊ตฌ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด ๊ฐ๋ฐ์๊ฐ ํ์ํ ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํํด์ผ ํฉ๋๋ค. ๋ง๋ค๊ณ ์ ํ๋ ์ฑ์ "์"์ผ๋ก ์ํธ์์ฉ ๊ด๋ จ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ณ ์ถ๋ค. ๋น ๋ฅด๊ฒ Start ํ๋ ๋ฐ์๋ ManoMotion SDK๊ฐ ์ ๋ฆฌํ ์ ์๊ฒ ๋๋ ๊ฒ์ด์ฃ .
Unity์ ManoMotion ํ๊ฒฝ ๊ตฌ์ถ
https://developer.manomotion.com/
๋จผ์ ManoMotion ์น ์ฌ์ดํธ ํ์๊ฐ์ ์ ํด์ค๋๋ค.
ํ์๊ฐ์ ์ ๋ํ๋๋ ์ฐฝ์ ๋๋ค. ์ฃผ๋ชฉํด์ผ ํ๋ ๊ฑด ๋นจ๊ฐ์ ๋ค๋ชจ๋ก ๊ทธ๋ ค์ง Get Started / ๋ผ์ด์ผ์ค๊ฐ ์์ต๋๋ค.
Get Started๋ฅผ ํด๋ฆญํด์ SDK๋ฅผ ๋ค์ด๋ฐ์ ์ค๋๋ค.
๋ผ์ด์ผ์ค ์ ๋ณด์ ๋๋ค. SDK๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ผ์ด์ ์ค Key๊ฐ ํ์ํ๊ฒ ๋๋๋ฐ, ๋ง๋ฃ๋๋ฉด ์ฌ์ฉํ ์ ์๋ ๊ฒ๋ ์ฐธ๊ณ ํ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ์ ๋ ์ด ๊ธ์ ์ธ ๋ ์ง๊ธ ๋ผ์ด์ ์ค๊ฐ ๋ง๋ฃ๋์ด ๋ผ์ด์ ์ค๋ฅผ ํ์ธํ ์๊ฐ ์๋ ์ํฉ์ ๋๋ค..
์ฌ๋ฐ๊ธ์ ๋ํ ์ ๋ณด๋ฅผ ๋ชป ์ฐพ๊ณ ์์ด์.. ํน์ ์์๋ ๋ถ ์์ผ์๋ฉด ๋๊ธ๋ก ๊ผญ ์๋ ค์ฃผ์ธ์!!
https://www.youtube.com/watch?v=wQlNT-oDreQ&t=351s
Hand Gesture๋ก ์ค๋ธ์ ํธ ์์ฑ
AR ํ๊ฒฝ์ ์ํด AR Session Origin๊ณผ AR Session์ ์์ฑํด ์ค๋๋ค. ๊ทธ๋ฆฌ๊ณ ARManomotionManager ๊ณผ ManomotionCanvas Prefab์ ์์ฑํด ์ค๋๋ค. SDK๋ฅผ ๋ค์ด๋ฐ์ผ์ จ๋ค๋ฉด ๊ฒ์์ฐฝ์ ๋ฐ๋ก ์ฐพ์ผ์ค ์ ์์ต๋๋ค.
ARManomotionManager ์ธ์คํํฐ ๋ชจ์ต์ ๋๋ค. ์ ์ฌ์ง์ฒ๋ผ ์ฐ๊ฒฐํด ์ค๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ฐ์ ๋ฐ๊ธ๋ฐ์๋ ๋ผ์ด์ผ์ค Key๋ฅผ ๋ฃ์ด์ค๋๋ค.
Project Settings๋ฅผ ์ด์ด Player ํญ๋ชฉ์ผ๋ก ๋์ด๊ฐ ์ ๊ณต๋ฐ์๋ Bundle ID๋ ์จ๋ฃ์ด ์ค๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnObjcectOnClick : MonoBehaviour
{
[SerializeField] private GameObject[] arObject;
private int currentIndex = 0;
// GameObject[] childObjects = new GameObject[arObject.transform.childCount];
// Update is called once per frame
void Update()
{
ManomotionManager.Instance.ShouldCalculateGestures(true);
GestureInfo gestureInfo = ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info;
ManoGestureTrigger currentGesture = gestureInfo.mano_gesture_trigger;
if (currentGesture == ManoGestureTrigger.CLICK)
{
SpawnObject();
}
}
private void SpawnObject()
{
ManomotionManager.Instance.ShouldCalculateSkeleton3D(true);
TrackingInfo trackingInfo = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info;
float depthEstimation = trackingInfo.depth_estimation;
Vector3 jointPosition = ManoUtils.Instance.CalculateNewPositionSkeletonJointDepth(new Vector3(trackingInfo.skeleton.joints[8].x, trackingInfo.skeleton.joints[8].y, trackingInfo.skeleton.joints[8].z), depthEstimation);
//Instantiate(arObject, jointPosition, Quaternion.identity);
Instantiate(arObject[currentIndex], jointPosition, Quaternion.identity);
Handheld.Vibrate();
currentIndex++;
}
}
|
cs |
SpawnObjcectOnClick ํด๋์ค๋ ์ฌ์ฉ์๊ฐ ํด๋ฆญ ์ ์ค์ฒ๋ฅผ ์ํํ ๋๋ง๋ค ์๋ก์ด ๊ฒ์ ์ค๋ธ์ ํธ๋ฅผ ์์ฑํ๊ณ , ์์ฑ๋ ์ค๋ธ์ ํธ๋ฅผ ์์ฐจ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ฉด์ ์์ฑํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
1. Updata() ํจ์์์ ๋งค ํ๋ ์๋ง๋ค Manomotion ์ ์ค์ฒ ์ธ์์ ํ์ฑํํ๊ณ , ํ์ฌ ์ธ์๋ ์ ์ค์ฒ๋ฅผ ํ์ธํฉ๋๋ค.
ํ์ฌ ์ ์ค์ฒ๊ฐ ManoGestureTrigger.CLICK์ธ ๊ฒฝ์ฐ SpawnObject() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์๋ก์ด ์ค๋ธ์ ํธ๋ฅผ ์์ฑํฉ๋๋ค.
2. SpawnObject() ๋ฉ์๋๋ Manomotion 3D ์ค์ผ๋ ํค ์ถ์ ์ ํ์ฑํํ๊ณ , ์์ ๊น์ด ์ถ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
์ถ์ ๋ ๊น์ด์ ์์ ๊ด์ ์์น๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ฑ ์์น๋ฅผ ๊ณ์ฐํ์ฌ 'arObject' ๋ฐฐ์ด์์ ํ์ฌ ์ธ๋ฑ์ค์ ํด๋นํ๋ ์ค๋ธ์ ํธ๋ฅผ ์์ฑํฉ๋๋ค.
3. ์์ฑ๋ ์ค๋ธ์ ํธ๋ฅผ ์ง๋์ํค๊ณ , ๋ฐฐ์ด ์ธ๋ฑ์ค๋ฅผ ์ฆ๊ฐ์ํต๋๋ค.
์์๊ณผ๋ ๋ค๋ฅด๊ฒ ์ ๋ Ar Object ๋ณ์๋ฅผ ๋ฐฐ์ด๋ก ๋ง๋ค์ด ์ฌ๋ฌ ๊ฐ์ ์ค๋ธ์ ํธ๋ฅผ ๋ฃ์ด์ฃผ์์ต๋๋ค.
https://www.youtube.com/watch?v=9PRYIxb3tYk&list=PLSc07dYXbtBl8PTbnWSjbvREVmkbebPOv&index=4
"์"์ผ๋ก ์ง์ ์ค๋ธ์ ํธ๋ฅผ ์ก๊ณ ์ฎ๊ธฐ๊ธฐ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrabInteraction : MonoBehaviour
{
[SerializeField] private GameObject handPointer;
private float skeletonConfience = 0.0001f;
// Update is called once per frame
void Update()
{
bool hasConfience = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.confidence > skeletonConfience;
if (hasConfience )
{
var palmCenter = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.palm_center;
var depthEstimation = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.depth_estimation;
Vector3 positionPointer = ManoUtils.Instance.CalculateNewPositionDepth(palmCenter, depthEstimation);
handPointer.transform.position = positionPointer;
handPointer.SetActive(true);
}
else
{
handPointer.transform.DetachChildren();
handPointer.SetActive(false);
}
}
}
|
cs |
GrabInteraction ํด๋์ค๋ ์ ์ถ์ ์ ๊ธฐ๋ฐ์ผ๋ก Hand Pointer๋ฅผ ์ ๋ฐ์ดํธ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
1. hasConfience ๋ณ์๋ ์์ ์ถ์ ์ ๋ณด์์ ์ค์ผ๋ ํค์ ์ ๋ขฐ๋๊ฐ skeltonConfience ๋ณด๋ค ํฐ์ง ์ฌ๋ถ๋ฅผ ํ์ธํฉ๋๋ค.
2. ๋ง์ฝ ์ ๋ขฐ๋๊ฐ ์ถฉ๋ถํ ํฌ๋ค๋ฉด ์์ ์ค์ฌ(palmCenter)๊ณผ ๊น์ด ์ถ์ ์ ๋ณด(depthEstimation)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ ํฌ์ธํฐ์ ์์น(positionPointer)๋ฅผ ๊ณ์ฐํฉ๋๋ค.
3. ๊ณ์ฐ๋ ์์น๋ก ์ ํฌ์ธํฐ์ ์์น๋ฅผ ์ด๋ํ๊ณ , ์ ํฌ์ธํฐ๋ฅผ ํ์ฑํํฉ๋๋ค.
4. ๋ง์ฝ ์ ๋ขฐ๋๊ฐ ์ถฉ๋ถํ์ง ์๋ค๋ฉด, ์ ํฌ์ธํฐ์์ ๋ถ๋ชจ-์์ ๊ด๊ณ๋ฅผ ํด์ ํ๊ณ ์ ํฌ์ธํฐ๋ฅผ ๋นํ์ฑํํฉ๋๋ค.
GrabInteraction ์ปดํฌ๋ํธ๋ฅผ ๋ฃ์ด์ฃผ๊ณ , Hand Pointer๋ก ์ฌ์ฉํ ์ค๋ธ์ ํธ๋ฅผ ๋ฃ์ด์ค๋๋ค.
์ด์ Hand Pointer ์ค๋ธ์ ํธ๊ฐ ์์ ์ค์ฌ์ ์์นํ๊ณ , ์์ด ์์ง์ผ ๋๋ง๋ค Hand Pointer๋ ๋ฐ๋ผ์ ์์ง์ด๊ฒ ๋ฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(BoxCollider), typeof(Rigidbody))]
public class ObjectManipulator : MonoBehaviour
{
[SerializeField] private Material[] materials = new Material[2];
private Renderer objcectRenderer;
private string handTag = "Player";
private bool isGrabbing;
private float skeletonConfidence = 0.0001f;
// Start is called before the first frame update
void Start()
{
objcectRenderer= GetComponent<Renderer>();
}
// Update is called once per frame
void Update()
{
ManomotionManager.Instance.ShouldCalculateGestures(true);
var currentGesture = ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_trigger;
if(currentGesture == ManoGestureTrigger.GRAB_GESTURE)
{
isGrabbing = true;
}
else if (currentGesture == ManoGestureTrigger.RELEASE_GESTURE)
{
isGrabbing = false;
transform.parent = null;
}
bool hasConfidence = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.confidence > skeletonConfidence;
if(!hasConfidence)
{
objcectRenderer.sharedMaterial = materials[0];
}
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.CompareTag(handTag))
{
objcectRenderer.sharedMaterial = materials[1];
Handheld.Vibrate();
}
else if(isGrabbing)
{
transform.parent = other.gameObject.transform;
}
}
private void OnTriggerStay(Collider other)
{
if(other.gameObject.CompareTag(handTag) && isGrabbing)
{
transform.parent = other.gameObject.transform;
}
}
private void OnTriggerExit(Collider other)
{
transform.parent = null;
objcectRenderer.sharedMaterial = materials[0];
}
}
|
cs |
ObjectManipulator ํด๋์ค๋ "์" ๊ณผ์ ์ถฉ๋์ ๊ฐ์งํ์ฌ ์ค๋ธ์ ํธ๋ฅผ ์ก๊ณ ๋๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
RequireComponent() ์ํด ์ปดํฌ๋ํธ ์์ฑ ์ `BoxCollider`์ `Rigidbody` ์ปดํฌ๋ํธ๊ฐ ์๋ ์์ฑ๋ฉ๋๋ค.
1. `materials`๋ผ๋ `Material` ๋ฐฐ์ด๊ณผ ์ฌ๋ฌ ๋ณ์๋ค์ด ์ ์ธ๋์์ต๋๋ค. `objcectRenderer`๋ ๋ ๋๋ฌ ์ปดํฌ๋ํธ๋ฅผ ์ฐธ์กฐํ๊ณ , `handTag`๋ ์์ ๋ํ๋ด๋ ํ๊ทธ๋ฅผ ์ ์ฅํฉ๋๋ค. `isGrabbing`์ ์ค๋ธ์ ํธ๋ฅผ ์ก๊ณ ์๋์ง ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ๋ถ๋ฆฌ์ธ ๋ณ์์ ๋๋ค. `skeletonConfidence`๋ ์ค์ผ๋ ํค์ ์ ๋ขฐ๋ ์๊ณ๊ฐ์ ๋ํ๋ ๋๋ค.
2. `Start()` ๋ฉ์๋์์ `objcectRenderer`๋ฅผ ์ด๊ธฐํํฉ๋๋ค.
3. `Update()` ๋ฉ์๋๋ ๋งค ํ๋ ์๋ง๋ค ํธ์ถ๋๋ฉฐ, Manomotion ์ ์ค์ฒ ์ธ์์ ํ์ฑํํ๊ณ ํ์ฌ ์ธ์๋ ์ ์ค์ฒ๋ฅผ ํ์ธํฉ๋๋ค.
4. ํ์ฌ ์ ์ค์ฒ๊ฐ `ManoGestureTrigger.GRAB_GESTURE`์ธ ๊ฒฝ์ฐ `isGrabbing`์ true๋ก ์ค์ ํฉ๋๋ค.
5. ํ์ฌ ์ ์ค์ฒ๊ฐ `ManoGestureTrigger.RELEASE_GESTURE`์ธ ๊ฒฝ์ฐ `isGrabbing`์ false๋ก ์ค์ ํ๊ณ , ์ค๋ธ์ ํธ์ ๋ถ๋ชจ๋ฅผ null๋ก ์ค์ ํ์ฌ ์ค๋ธ์ ํธ์ ๋ถ๋ชจ-์์ ๊ด๊ณ๋ฅผ ํด์ ํฉ๋๋ค.
6. `hasConfidence` ๋ณ์๋ ์์ ์ถ์ ์ ๋ณด์์ ์ค์ผ๋ ํค์ ์ ๋ขฐ๋๊ฐ `skeletonConfidence`๋ณด๋ค ํฐ์ง ์ฌ๋ถ๋ฅผ ํ์ธํฉ๋๋ค.
7. ๋ง์ฝ ์ ๋ขฐ๋๊ฐ ์ถฉ๋ถํ์ง ์๋ค๋ฉด, `objcectRenderer`์ `sharedMaterial`์ `materials[0]`์ผ๋ก ์ค์ ํ์ฌ ์ค๋ธ์ ํธ์ ๋จธํฐ๋ฆฌ์ผ์ ๋ณ๊ฒฝํฉ๋๋ค.
8. `OnTriggerEnter()` ๋ฉ์๋๋ ํธ๋ฆฌ๊ฑฐ ์ถฉ๋์ด ๋ฐ์ํ์ ๋ ํธ์ถ๋ฉ๋๋ค. ๋ง์ฝ ์ถฉ๋ํ ๊ฒ์ ์ค๋ธ์ ํธ์ ํ๊ทธ๊ฐ `handTag`์ ์ผ์นํ๋ค๋ฉด, `objcectRenderer`์ `sharedMaterial`์ `materials[1]`๋ก ์ค์ ํ๊ณ , ์ง๋์ ๋ฐ์์ํต๋๋ค. 9. ๊ทธ๋ ์ง ์๊ณ `isGrabbing`์ด true์ธ ๊ฒฝ์ฐ, ์ค๋ธ์ ํธ์ ๋ถ๋ชจ๋ฅผ ์ถฉ๋ํ ๊ฒ์ ์ค๋ธ์ ํธ๋ก ์ค์ ํ์ฌ ์ค๋ธ์ ํธ๋ฅผ ์ก์ ์ํ๋ก ์ ์งํฉ๋๋ค.
10. `OnTriggerStay()` ๋ฉ์๋๋ ํธ๋ฆฌ๊ฑฐ ์ถฉ๋์ด ์ง์๋๋ ๋์ ํธ์ถ๋ฉ๋๋ค. ์ถฉ๋ํ ๊ฒ์ ์ค๋ธ์ ํธ์ ํ๊ทธ๊ฐ `handTag`์ ์ผ์นํ๊ณ `isGrabbing`์ด true์ธ ๊ฒฝ์ฐ, ์ค๋ธ์ ํธ์ ๋ถ๋ชจ๋ฅผ ์ถฉ๋ํ ๊ฒ์ ์ค๋ธ์ ํธ๋ก ์ค์ ํ์ฌ ์ค๋ธ์ ํธ๋ฅผ ์ก์ ์ํ๋ก ์ ์งํฉ๋๋ค.
11. `OnTriggerExit()` ๋ฉ์๋๋ ํธ๋ฆฌ๊ฑฐ ์ถฉ๋์ด ์ข ๋ฃ๋ ๋ ํธ์ถ๋ฉ๋๋ค. ์ค๋ธ์ ํธ์ ๋ถ๋ชจ๋ฅผ null๋ก ์ค์ ํ๊ณ , `objcectRenderer`์ `sharedMaterial`์ `materials[0]`์ผ๋ก ์ค์ ํ์ฌ ์ค๋ธ์ ํธ์ ๋จธํฐ๋ฆฌ์ผ์ ์ด๊ธฐ ์ํ๋ก ๋๋๋ฆฝ๋๋ค.
GrabInteraction ํด๋์ค์์ handPointer๋ก ์ง์ ํ ์ค๋ธ์ ํธ Tag๋ฅผ Player๋ก ๋ณ๊ฒฝํฉ๋๋ค.
์ด์ ์ก์ ์ค๋ธ์ ํธ์ ObjectManipulator ์ปดํฌ๋ํธ๋ฅผ ๋ฃ์ด์ค๋๋ค. Materials[0]์๋ ์ค๋ธ์ ํธ์ ์๋ Material์ ๋ฃ์ด์ฃผ๊ณ , Materials[1]์๋ ์์ผ๋ก ์ก์ ๋ ๋ณํ Material์ ๋ฃ์ด์ฃผ๋ฉด ๋ฉ๋๋ค.
https://www.youtube.com/watch?v=RY_IbVgqPS0