Unity AR iOS LiDAR 활용

Minseung Kim·2023년 10월 28일
0

Unity-AR

목록 보기
6/8

이전 글에서 순순스튜디오님의 영상을 활용하여 iOS의 LiDAR의 거리값을 가져오는 방법에 대해 적었다. 이번에는 여러 위치의 LiDAR 거리 값을 가져오고 거리가 특정값보다 작을 경우 빨간색으로 나타내는 방법에 대한 글이다.


이전의 경우 화면 가운데 위치의 LiDAR값만 가져왔었다. 그러나 좀 더 넓은 범위의 정보를 가져올 필요가 있었다. 초기 구성은 다음과 같다.

사진의 파란 위치가 LiDAR 포인트를 가져올 위치이다. 총 11개 point의 위치를 가져와야 하는데 이전처럼 하나하나 위치를 지정해서 코드를 짜는 것은 매우 비효율적이라 판단했다. 그래서

위와 같이 가운데를 기준으로 가로X축, 세로Y축으로 설정하고 for문을 작성하기로 하였다.
여러 위치에 대해 한번에 변수를 선언하기 위해 List형태인
/위치를 가질 변수 
    public List<Vector2> posVec = new List<Vector2>();

다음과 같이 작성하였으며, 해당 변수에 값 대입은

//화면에 표기할 obj 위치 지정
        // i는 point 갯수 지정 
        for (int i = 0; i < 11; i++)
        {
            // z는 point의 높이 설정
            for (float z = 0.5f; z > 0.2; z = z - 0.1f)
            {
                if (z == 0.5f)
                {
                    //j는 x축 위치 설정 
                    for (float j = 0.1f; j < 1; j = j + 0.2f)
                    {
                        // 화면 넓이를 이용하여 point 위치를 지정 
                        posVec[i] = new Vector2(Screen.width * j, Screen.height * z);
                        i++;
                    }

                }

                else if (z == 0.4f)
                {

                    for (float j = 0.2f; j < 1; j = j + 0.2f)
                    {
                        posVec[i] = new Vector2(Screen.width * j, Screen.height * z);
                        i++;
                    }
                }
                else if (z == 0.3f)
                {
                    for (float j = 0.3f; j < 1; j = j + 0.4f)
                    {
                        posVec[i] = new Vector2(Screen.width * j, Screen.height * z);
                        i++;
                    }
                }

            }
        }

위와 같이 11개의 포인트 위치를 for문으로 작성하였다.
각 point에 표시될 모양 또한 List 형태인

// 화면의 LiDAR 사용 위치에 표시될 object
    public List<Transform> obj = new List<Transform>();

로 선언하였으며


다음과 같이 구성된 obj의 pivot 11개를

다음과 같이 연결해주었다.
해당 방법은

순순스튜디오님의 영상에서 확인할 수 있었다.
이제 각 point의 거리 값을 가져와야 하는데,
이전 처럼

 void Update()
    {
        if (m_RaycastManager.Raycast(_centerVec, s_Hits))
        {
            Quaternion tRot = Quaternion.Euler(90f, 0, 0);
            // s_Hits의 위치를 저장 
            var hitPose = s_Hits[0].pose;
            // s_Hits의 거리를 저장
            float hitDis = s_Hits[0].distance;
            // 가져온 거리를 화면에 표시 
            c_resouceText.text = hitDis.ToString("#.##") + "m";

            _pivot.localScale = new Vector3(hitDis, hitDis, hitDis);
            _pivot.position = Vector3.Lerp(_pivot.position, hitPose.position, 0.2f);
            //디버깅을 위해 rotation값을 Quaternion.Lerp에 넣어 자연스럽게 회전하게 만듦 
            _pivot.rotation = Quaternion.Lerp(_pivot.rotation, hitPose.rotation, 0.2f);

            //s_Hits의 값 초기화
            s_Hits.Clear();
        }
    }
}

일일이 작성하기는 너무 많은 양이므로

// LiDAR의 정보를 저장할 list
    static List<List<ARRaycastHit>> Hits = new List<List<ARRaycastHit>>();

다음과 같이 이중 List를 이용하였다.
11개의 List를 사용하기 위해 Start 부분에

 for (int k = 0; k < 11; k++)
        {
            List<ARRaycastHit> A = new List<ARRaycastHit>();
            Hits.Add(A);
        }

for문을 이용하여 내용을 추가했다.

LiDAR 거리값을 가져오는 방식은 이전과 같으나

if (RaycastManager.Raycast(posVec[i], Hits[i]))
            {

                Quaternion tRot = Quaternion.Euler(90f, 0, 0);

                // s_Hits의 위치를 저장 
                var hitPose_1 = Hits[i];
                var hitPose = hitPose_1[0].pose;
                // s_Hits의 거리를 저장
                var hitDis_1 = Hits[i];
                float hitDis = hitDis_1[0].distance;

                //Debug.Log(i+"의 거리" + hitDis);
               

                obj[i].localScale = new Vector3(hitDis, hitDis, hitDis);
                obj[i].position = Vector3.Lerp(obj[i].position, hitPose.position, 0.2f);

                //디버깅을 위해 rotation값을 Quaternion.Lerp에 넣어 자연스럽게 회전하게 만듦
                obj[i].rotation = Quaternion.Lerp(obj[i].rotation, hitPose.rotation, 0.2f);
                // 거리가 1.3m보다 짧을 경우 원을 빨간색으로 변경 
                if (hitDis < 1.3f)
                {
                    color[i].material.color = Color.red;
                }
                else
                {
                    color[i].material.color = Color.white;
                }
            }


            else
            {
                Quaternion tRot = Quaternion.Euler(90f, 0, 0);
                obj[i].localScale = new Vector3(0.5f, 0.5f, 0.5f);
                obj[i].rotation = Quaternion.Lerp(obj[i].rotation, tRot, 0.5f);
                obj[i].localPosition = Vector3.Lerp(obj[i].localPosition, Vector3.zero, 0.5f);

            }

위와 같이 이중 List에서 값을 가져오는 형식으로 변경하였으며, 거리에 따라 표시되는 원의 색이 변하게 만들었다.

색에 대한 변수는

public List<Renderer> color = new List<Renderer>();

Render 정보를 가져와서 내부의 색을 변경해주는 방식으로 작성했다!!
실행 결과 (사진 클릭 시 유튜브 영상으로 이동합니다.)
Video Label

제대로 작동하는 것을 확인할 수 있었다!!
이제 남은 문제점은

  1. 여전히 존재하는 화면 딜레이
  2. 임시로 적용한 classification model의 정확성 문제
  3. 최적의 화면 추출 위치 설정

이 있으며, 남은 문제점도 열심히 연구해 봐야겠다!!

To Be Continued...
profile
꾸준히, 열심히, 즐겁게

0개의 댓글