이번 글은 2개의 다른 마커 위에 각각 다른 가상화 객체를 만드는 방법을 다루었다. 기본적으로 nreal glasses에 대한 이해가 조금 필요하다.

 

1. NRCameraRig, NRInput 을 Hierarchy 창에 드래그&드랍

2. NRInput에서 Override Camera Center 부분을 NRCameraRig의 CenterCamera 드래그&드랍

 

3. 캔버스 추가 후 이벤트 시스템 제거

그리고 캔버스에서 Graphic Raycaster를 제거하고 Canvas Raycast Target을 추가한다.

캔버스에 버튼 등 인터렉션이 필요없으면 할필요 없다.

캔버스는 월드스페이스로 하고 nreal에서 제공하는 move with camera 스크립트를 컴포넌트로 주면 사용자 화면에 고정되게 된다. 거리 조정은 유니티 내에 실행하면서 해주어야 할 것이다. 

 

 

4. empty gameobject 추가후 Tracking Image Visualizer 이름의 속성으로 추가

 

Tracking Image Example Controller를 컴포넌트로 가져온다.

Text : 이미지의 인덱스를 화면에서 확인하기 위한 객체

tracking Image Visualize에서 위에는 엔진 아래는 자동차

Fit To Scan Overlay는 이미지를 탐색할 때 나오는 텍스트이다.

 

위 컨트롤러는 글쓴이가 수정한 코드이다. 월래라면 등록된 이미지가 탐지되면 그위에 가상화할 객체를 하나만 보여주는 것이지만 글쓴이는  2개의 이미지에 각각 서로 다른 객체를 가상화 하고 싶었다. 

아래는 수정된 코드이다. 

namespace NRKernal.NRExamples
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using UnityEngine;
    using UnityEngine.UI;


    /// <summary>
    /// Controller for TrackingImage example.
    /// </summary>
    [HelpURL("https://developer.nreal.ai/develop/unity/image-tracking")]
    public class TrackingImageExampleController : MonoBehaviour
    {


        public Text text;

        // A prefab for visualizing an TrackingImage.
        public TrackingImageVisualizer TrackingImageVisualizerPrefab_1;
        public TrackingImageVisualizer TrackingImageVisualizerPrefab_2;

        // The overlay containing the fit to scan user guide.
        public GameObject FitToScanOverlay;

        private Dictionary<int, TrackingImageVisualizer> m_Visualizers
            = new Dictionary<int, TrackingImageVisualizer>();

        private List<NRTrackableImage> m_TempTrackingImages = new List<NRTrackableImage>();

        public void Update()
        {
#if !UNITY_EDITOR
            // Check that motion tracking is tracking.
            if (NRFrame.SessionStatus != SessionState.Running)
            {
                return;
            }
#endif
            // Get updated augmented images for this frame.
            NRFrame.GetTrackables<NRTrackableImage>(m_TempTrackingImages, NRTrackableQueryFilter.New);

            // Create visualizers and anchors for updated augmented images that are tracking and do not previously
            // have a visualizer. Remove visualizers for stopped images.
            foreach (var image in m_TempTrackingImages)
            {
/*                UnityEngine.Debug.Log("image.GetDataBaseIndex() : " + image.GetDataBaseIndex());
                UnityEngine.Debug.Log("image.GetTrackableType() : " + image.GetTrackableType());
                UnityEngine.Debug.Log("image.GetTrackingState() : " + image.GetTrackingState());*/

                TrackingImageVisualizer visualizer = null;
                m_Visualizers.TryGetValue(image.GetDataBaseIndex(), out visualizer);
                if (image.GetTrackingState() == TrackingState.Tracking && visualizer == null)
                {
                    NRDebugger.Log("Create new TrackingImageVisualizer!");
                    // Create an anchor to ensure that NRSDK keeps tracking this augmented image.
                    
                    try
                    {
                        text.text = "Image Index : " + image.GetDataBaseIndex();
                        if (image.GetDataBaseIndex() == 4)
                        {
                            visualizer = (TrackingImageVisualizer)Instantiate(TrackingImageVisualizerPrefab_1, image.GetCenterPose().position, image.GetCenterPose().rotation);
                        }
                        else 
                        {
                            visualizer = (TrackingImageVisualizer)Instantiate(TrackingImageVisualizerPrefab_2, image.GetCenterPose().position, image.GetCenterPose().rotation);
                        }
                    }
                    catch(NullReferenceException e) {
                     }
                    visualizer.Image = image;
                    visualizer.transform.parent = transform;
                    m_Visualizers.Add(image.GetDataBaseIndex(), visualizer);
                }
                else if (image.GetTrackingState() == TrackingState.Stopped && visualizer != null)
                {
                    m_Visualizers.Remove(image.GetDataBaseIndex());
                    Destroy(visualizer.gameObject);
                }

                FitToScanOverlay.SetActive(false);
            }

        }

        public void EnableImageTracking()
        {
            var config = NRSessionManager.Instance.NRSessionBehaviour.SessionConfig;
            config.ImageTrackingMode = TrackableImageFindingMode.ENABLE;
            NRSessionManager.Instance.SetConfiguration(config);
        }

        public void DisableImageTracking()
        {
            var config = NRSessionManager.Instance.NRSessionBehaviour.SessionConfig;
            config.ImageTrackingMode = TrackableImageFindingMode.DISABLE;
            NRSessionManager.Instance.SetConfiguration(config);
        }
    }
}

 

여기서 추가한 핵심 코드는 image.GetDataBaseIndex() 코드이다. 

GetDataBaseIndex() 코드는 데이터베이스에 등록된 이미지의 인덱스 번호를 반환하는 메소드이다.

여기서 주의할 점이 있다. 유니티 내부에서 실행했을 때 이미지의 인덱스 번호와 AR 안경을 착용하고 봤을 때 이미지의 인덱스 번호가 다르다는 점이다 . 따라서 ar 안경을 착용하고 이미지의 인덱스 번호를 확인하기 위해 유니티 캔버스에 Text를 이용하여 직접 인덱스 번호를 GetDataBaseIndex를 사용하여 확인하길 바란다.

 

5. 트래킹 이미지 벌추얼라이저 만들기

위 이미지 처럼 엠티 오브젝트에 추적된 이미지 위에 가상화할 객체를 자식으로 넣어준다. 그리고 엠티 오브젝트에 컴포넌트로 

를 넣어주어야 한다. Axis 값은 자식으로 주었던 객체를 넣어주면 된다.

글쓴이는 예제 코드를 조금 수정하였다.

 

namespace NRKernal.NRExamples
{
    using UnityEngine;

    /// <summary>
    /// Uses 4 frame corner objects to visualize an TrackingImage.
    /// </summary>
    public class TrackingImageVisualizer : MonoBehaviour
    {
        // The TrackingImage to visualize.
        public NRTrackableImage Image;

/*        // A model for the lower left corner of the frame to place when an image is detected.
        public GameObject FrameLowerLeft;

        // A model for the lower right corner of the frame to place when an image is detected.
        public GameObject FrameLowerRight;

        /// A model for the upper left corner of the frame to place when an image is detected.
        public GameObject FrameUpperLeft;

        // A model for the upper right corner of the frame to place when an image is detected.
        public GameObject FrameUpperRight;*/

        public GameObject Axis;

        public void Update()
        {
            if (Image == null || Image.GetTrackingState() != TrackingState.Tracking)
            {
/*                FrameLowerLeft.SetActive(false);
                FrameLowerRight.SetActive(false);
                FrameUpperLeft.SetActive(false);
                FrameUpperRight.SetActive(false);*/
                Axis.SetActive(false);
                return;
            }

/*            float halfWidth = Image.ExtentX / 2;
            float halfHeight = Image.ExtentZ / 2;*/
/*            FrameLowerLeft.transform.localPosition = (halfWidth * Vector3.left) + (halfHeight * Vector3.back);
            FrameLowerRight.transform.localPosition = (halfWidth * Vector3.right) + (halfHeight * Vector3.back);
            FrameUpperLeft.transform.localPosition = (halfWidth * Vector3.left) + (halfHeight * Vector3.forward);
            FrameUpperRight.transform.localPosition = (halfWidth * Vector3.right) + (halfHeight * Vector3.forward);*/

            var center = Image.GetCenterPose();
            transform.position = center.position;
            transform.rotation = center.rotation;

/*            FrameLowerLeft.SetActive(true);
            FrameLowerRight.SetActive(true);
            FrameUpperLeft.SetActive(true);
            FrameUpperRight.SetActive(true);*/
            Axis.SetActive(true);
        }
    }
}

 글쓴이는 모서리 부분을 알 필요없이 이미지 중앙에다가 객체만 띠우고 싶어서 위와 같이 소스코드를 수정하였다. 

그러면 원하는 객체만 이미지 위에 나타나게 된다. 

 

 

그외 글쓴이는 엔진을 가상화 하였는데 그림자 때문에 엔진이 잘 보이지 않았다 그래서 아래 블로그를 참조 하였다.

<그림자 지우기>

https://mingyu0403.tistory.com/56

 

[Unity] 그림자 지우기

ㅇ 그림자가 그려지지 않게 하기 Cast Shadows - 그림자가 그려질 것인가 Receive Shadows - 다른 물체의 그림자가 나한테 그려질 것인가

mingyu0403.tistory.com

 

그리고 엔진이 나타나면서 좀더 집중력을 올리는 요소를 넣고자 소리도 아래와 같은 컴포넌트를 엔진 객체에 넣어주어 봤다.

Play On Awake에 체크 되어있으면 객체가 생성될 때 오디오가 재생된다. Loop를 하게 되면 객체가 일단 지워저도 계속 실행되는 것을 관찰하여 일단 Loop는 선택하지 않았다.

+ Recent posts