[20250309] AR 간단히 물체 올려보기

SmartBear·2026년 3월 9일
post-thumbnail

AR 이론

AR 이란?

  • 증강현실(Augmented Reality)
  • 현실 세계 위에 디지털 컨텐츠를 겹쳐 보여주는 기술.
  • 카메라로 촬영한 사진 위에 가상의 오브젝트를 합성하는 기술.
구분ARVR
현실보임안보임(완전한 가상현실)
컨텐츠현실 위에 합성가상 세계
대표 기기스마트폰, AR 글래스VR 헤드셋

AR Core / AR Kit

  • 유니티에서 AR 기능을 활용할 수 있도록 지원하는 패키지

AR Core

  • 안드로이드 / iOS 호환
  • AR Kit 대비 상대적으로 성능이 좋지 않음.

AR Kit

  • iOS 전용
  • 바디 트래킹

AR Foundation

  • Unity 와 AR 패키지 간의 다리 역할

AR 개발환경 세팅

기기 호환 체크

Android 개발자 모드 활성화

  • 시스템 설정 -> 휴대전화 정보 -> 소프트웨어 정보 -> 빌드 번호 연속 터치 -> 개발자 모드 활성화
  • 시스템 설정 -> 개발자 옵션(활성화 됨) -> USB 디버깅 활성화
  • USB 연결 -> 연결(데이터 전송) 허용

Unity Project

해상도 설정

  • Game View -> Free Aspect -> 커스텀 해상도 설정 (해두면 편함)

패키지 설치

  • Unity Registry
    • AR Foundation
    • Google AR Core XR Plugin

Build Setting

  • Switch Android Platfarm

Project Settings

XR Plug-in Management

  • Android Tab -> Google ARCore 체크
  • Project Validation -> 경고 및 에러 Fix All

Player

  • Graphics API -> Vulkan 제외
  • Identification -> Minimum API Level 확인
  • Configuration
    • Scripting Backend -> IL2CPP
    • (GPS 사용 한다면) Active Input Handling -> Both 로 변경. (Unity 6 버전 Input System 에는 아직 GPS 를 handling 할 수 없음)
  • Android Application Configuration
    • Target Architectures -> ARM64 체크.

Graphics

  • Default Render Pipeline -> Mobile RP Asset

카메라를 Background 로 하는 방법

  • Assets -> Setting -> Mobile_Renderer -> Add Renderer Feature -> AR Background Render Feature 추가

Scene

  • Main Camera 삭제
  • Create -> XR -> AR Session 추가
    • 모바일 기기와 통신하면서 AR 서비스가 유지되도록 함
  • Create -> XR -> XR Origin
    • 유티니틀 기준으로 동작하는 오브젝트

AR 실습

예제 코드

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using Random = UnityEngine.Random;

public class PinSpawner : MonoBehaviour
{
    [SerializeField] private GameObject prefabF;
    [SerializeField] private GameObject prefabM;
    [SerializeField] private List<RuntimeAnimatorController> animatorsF;
    [SerializeField] private List<RuntimeAnimatorController> animatorsM;
    
    [SerializeField] private ARRaycastManager raycastManager;
    
    private ArAction _arAction;
    private Transform _currentPin;
    List<ARRaycastHit> hits = new();

    private void Awake() => Init();
    private void OnDestroy() => Dispose();
    private void OnEnable() => SubscribInputAction();
    private void OnDisable() => UnscriptInputAction();

    private void Init()
    {
        _arAction = new();
    }
    
    private void Dispose()
    {
        _arAction.Dispose();
    }

    private GameObject InstantiatePrefab()
    {
        int choiceFM = Random.Range(0, 1);
        int choiceDance = Random.Range(0, 6);
        RuntimeAnimatorController dance;
        GameObject pin;
        switch (choiceFM)
        {
            case 0:
                dance = animatorsM[choiceDance];
                pin = Instantiate(prefabM);
                pin.GetComponent<Animator>().runtimeAnimatorController = dance;
                break; 
            default:
                dance = animatorsF[choiceDance];
                pin = Instantiate(prefabF);
                pin.GetComponent<Animator>().runtimeAnimatorController = dance;
                break;
        }
        return pin;
    }

    private void CreatePin(InputAction.CallbackContext context)
    {
        if (_currentPin != null) return;
        _currentPin = InstantiatePrefab().transform;
    }

    private void HandlePinTransform(InputAction.CallbackContext context)
    {
        if (_currentPin == null) return;
        Vector2 touchPostion = context.ReadValue<Vector2>();
        SetArRaycastManager(touchPostion);
    }

    private void SetArRaycastManager(Vector2 touchPostion)
    {
        Ray ray = Camera.main.ScreenPointToRay(touchPostion);
        hits.Clear();
        if (raycastManager.Raycast(ray, hits, TrackableType.PlaneWithinPolygon))
        {
            Pose hitPose = hits[0].pose;
            _currentPin.transform.position = hitPose.position;
            _currentPin.transform.rotation = hitPose.rotation;
        }
    }
    
    private void FixPinPosition(InputAction.CallbackContext context)
    {
        if (_currentPin == null) return;
        _currentPin = null;
    }

    private void SubscribInputAction()
    {
        _arAction.TouchAction.Enable();
        _arAction.TouchAction.TouchClick.started += CreatePin;
        _arAction.TouchAction.TouchClick.canceled += FixPinPosition;
        _arAction.TouchAction.TouchTracking.performed += HandlePinTransform;
    }

    private void UnscriptInputAction()
    {
        _arAction.TouchAction.Disable();
        _arAction.TouchAction.TouchClick.started -= CreatePin;
        _arAction.TouchAction.TouchClick.canceled -= FixPinPosition;
        _arAction.TouchAction.TouchTracking.performed -= HandlePinTransform;
    }
    
}

결과

https://youtube.com/shorts/ZoTkGCc7XdU?si=n2AAiqqevgO8qnCu

유투브에 올렸더니 알아서 Short 로 넘어갔음...🫣

추가 내용 IL2CPP vs Mono

참고 블로그

IL2CPP

Unity에서 개발한 방식으로 다양한 플랫폼에서 Unity 앱의 성능을 개선하였습니다.
IL(Intermediate Language) 2(to) CPP(C++)의 약자로 MSIL(MicroSoft IL)을 C++ 코드로 전환하고, 타겟 플랫폼에서 직접 실행될 수 있는 적합한 네이티브 바이너리 파일로 컴파일합니다.

AOT 컴파일을 사용하며 실행 전에 전체 애플리케이션을 컴파일합니다.
Mono나 JIT 컴파일을 지원하지 않는 플랫폼에 적합합니다.(일부 플랫폼은 런타임 코드 생성을 지원하지 않아 타겟 디바이스에서 JIT 컴파일에 의존하는 일부 관리 코드가 작동하지 않습니다)
?
IL2CPP의 장점

  • IL 코드를 사용할 수 있는(.NET Framework나 Mono 런타임 환경을 지원하는) 플랫폼보다 C++ 코드를 지원하는 플랫폼이 더 많기 때문에 다양한 플랫폼을 지원할 수 있습니다.
  • 타겟 플랫폼에 최적화된 C++ 코드를 생성하기 때문에 VM에서 IL 코드를 실행하는 것보다 성능이 향상됩니다.
  • IL 코드 대신 역설계(Reverse-engineering)하기 어려운 컴파일된 C++로 대체하여 보안성을 개선하였습니다.

Mono

개발자가 Cross-platform 앱을 쉽게 만들 수 있도록 설계된 소프트웨어 플랫폼입니다.
Micorosoft가 후원하는 오픈 소스로 .NET Framework의 implementation입니다. 일반적으로는 JIT(Just-In-Time)1 컴파일러에서 사용되지만 AOT(Ahead-Of-Time)2 컴파일러도 지원합니다.

Unity 에서의 Mono
Unity는 오픈 소스인 Mono 프로젝트의 포크를 사용합니다.
(오픈 소스 Mono와는 다르게 게임 개발에 맞게 최적화된 부분이 있고 JIT 컴파일러만 지원하는 것 같습니다)

C#으로 작성된 스크립트가 IL(Intermediate Language)코드로 컴파일된 후 Momo 런타임 환경에서 실행됩니다. Mono 런타임은 IL코드를 실행하고 메모리 > 관리, 가비지 콜렉터, 스레드 같은 기능이 있는 VM(Virtual Machine)을 제공합니다.

Mono 스크립팅 백엔드는 JIT 컴파일을 사용하여 런타임 시점에 요청 시 코드를 컴파일합니다.
플랫폼이 JIT과 Mono를 지원하고 AOT도 지원하는 경우 Mono가 기본값입니다.
Unity Editor 에서는 빠른 실행을 위해 Mono를 사용합니다.
AOT 컴파일을 지원하지 않는 플랫폼에 적합합니다.

비교

MonoIL2CPP
CompilerJITAOT
PerformanceSlowerFaster
SecurityWeakerBetter
Memory footprintmoreless
Build timesFasterSlower
Build file sizelessmore
profile
Python Dev with Infra -> Game Programmer

0개의 댓글