업데이트:

카테고리:

/

태그: ,

ARCore

카메라를 이용해 사용자 기준으로 이미지를 띄우거나 상호작용

  1. manifest 설정

     <!-- 카메라 및 지도를 기반으로 위치를 띄워주기 위해 위치정보와 인터넷 권한 설정 -->
     <uses-permission android:name="android.permission.CAMERA"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
        
     <!-- ar 카메라와, 기본 카메라 사용 -->
     <uses-feature android:name="android.hardware.camera.ar" android:required="true"/>
     <uses-feature android:glEsVersion="0x00020000" android:required="true" />
     <uses-feature
         android:name="android.hardware.camera"
         android:required="true" />
        
     <!-- 구글 map를 사용하기 위해 api키 설정 -->
     <meta-data android:name="com.google.ar.core" android:value="required" />
     <meta-data
         android:name="com.google.android.ar.API_KEY"
         android:value="@string/GoogleCloudApiKey"/>
     <meta-data
         android:name="com.google.android.geo.API_KEY"
         android:value="@string/GoogleCloudApiKey" />
    
  2. gradle 설정

     implementation 'com.google.ar:core:1.33.0'
        
     implementation 'com.google.android.gms:play-services-auth:20+'
     implementation 'com.google.android.gms:play-services-location:19+'
     implementation 'com.google.android.gms:play-services-maps:18.0.2'
    
  3. activity.xml View 설정

     <android.opengl.GLSurfaceView
           android:id="@+id/surfaceview"
           android:layout_width="fill_parent"
           android:layout_height="fill_parent"
           android:layout_gravity="top" />
        
     	<!-- 지도에 터치해서  -->
       <com.google.ar.core.codelabs.hellogeospatial.helpers.MapTouchWrapper
           android:id="@+id/map_wrapper"
           android:layout_width="match_parent"
           android:layout_height="300dp"
           android:layout_alignParentBottom="true">
        		
     		<!-- 지도 뷰를 띄어주는 Fragment, google Map api 사용 -->
         <fragment
             android:id="@+id/map"
             class="com.google.android.gms.maps.SupportMapFragment"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:context=".HelloGeoActivity" />
        
         <TextView
             android:padding="8dp"
             android:textColor="@android:color/black"
             android:background="#AAFFFFFF"
             android:layout_width="wrap_content"
             android:fontFamily="monospace"
             android:layout_height="wrap_content"
             android:id="@+id/statusText"
             />
       </com.google.ar.core.codelabs.hellogeospatial.helpers.MapTouchWrappe
    
  4. ARCore 설정

    session으로 화면상태를 제어함

    • session 생성 (ARCoreSessionLifecycleHelper.kt)

        private fun tryCreateSession(): Session? {
            // 권한 체크
            if (!GeoPermissionsHelper.hasGeoPermissions(activity)) {
              GeoPermissionsHelper.requestPermissions(activity)
              return null
            }
              
            return try {
              // 설치 여부 확인
              when (ArCoreApk.getInstance().requestInstall(activity, !installRequested)!!) {
                ArCoreApk.InstallStatus.INSTALL_REQUESTED -> {
                  installRequested = true
                  // tryCreateSession will be called again, so we return null for now.
                  return null
                }
                ArCoreApk.InstallStatus.INSTALLED -> {
                  // Left empty; nothing needs to be done.
                }
              }
              
              // 설치되어 있으면 실행
              Session(activity, features)
            } catch (e: Exception) {
              exceptionCallback?.invoke(e)
              null
            }
          }
              
        // 앱 상태에 따른 session 상태관리
        override fun onResume(owner: LifecycleOwner) {
            val session = this.session ?: tryCreateSession() ?: return
            try {
              beforeSessionResume?.invoke(session)
              session.resume()
              this.session = session
            } catch (e: CameraNotAvailableException) {
              exceptionCallback?.invoke(e)
            }
          }
              
        override fun onPause(owner: LifecycleOwner) {
          session?.pause()
        }
              
        override fun onDestroy(owner: LifecycleOwner) {
          session?.close()
          session = null
        }
      
    • Activity ar 설정

        arCoreSessionHelper.beforeSessionResume = ::configureSession
        lifecycle.addObserver(arCoreSessionHelper)
              
        // AR renderer.
        renderer = HelloGeoRenderer(this)
        lifecycle.addObserver(renderer)
              
        // AR UI.
        view = HelloGeoView(this)
        lifecycle.addObserver(view)
        setContentView(view.root)
              
        SampleRender(view.surfaceView, renderer, assets)
              
        private fun configureSession(session: Session) {
            session.configure(
              session.config.apply {
                geospatialMode = Config.GeospatialMode.ENABLED
              }
            )
          }
      

      beforeSessionResume : Session을 만들기 전에 설정값 지정

      Render : AR을 구현할 때 실제 지도와 3D 모델을 매핑하는 역할

      View : 실제 화면에 보이는 뷰를 구성

    • Renderer.kt

        override fun onDrawFrame(render: SampleRender) {
          val session = session ?: return
        	// 지구 기준의 좌표를 가져온다.
        	val earth = session.earth
          if (earth?.trackingState == TrackingState.TRACKING) {
            // ARCore에서 요청한 지리정보 추가
            val cameraGeospatialPose = earth.cameraGeospatialPose
            // 요청한 정보를 계속 갱신
            activity.view.mapView?.updateMapPosition(
              latitude = cameraGeospatialPose.latitude,
              longitude = cameraGeospatialPose.longitude,
              heading = cameraGeospatialPose.heading
            )
          }
              
          // 맵에 앵커가 있다면 다시 랜더하여 보여준다. 
          earthAnchor?.let {
            render.renderCompassAtAnchor(it)
          }
              
          // 배경과 함계 보여줌
          backgroundRenderer.drawVirtualScene(render, virtualSceneFramebuffer, Z_NEAR, Z_FAR)
        }
              
        var earthAnchor: Anchor? = null
              
          fun onMapClick(latLng: LatLng) {
            val earth = session?.earth ?: return
            if (earth.trackingState != TrackingState.TRACKING) {
              return
            }
            // 이전앵커가 있는경우 없애고 새로만듬
            earthAnchor?.detach()
            // 실제 고도와 화면상의 고도의 차이가 있어 보정값 추가
            val altitude = earth.cameraGeospatialPose.altitude - 1
            // 앵커의 위치와 고도를 정함
            val qx = 0f
            val qy = 0f
            val qz = 0f
            val qw = 1f
            earthAnchor =
              earth.createAnchor(latLng.latitude, latLng.longitude, altitude, qx, qy, qz, qw)
            // 마커 위치 표시
            activity.view.mapView?.earthMarker?.apply {
              position = latLng
              isVisible = true
            }
          }