Android ARCore
업데이트:
카테고리: Android
/ARCore
카메라를 이용해 사용자 기준으로 이미지를 띄우거나 상호작용
-
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" />
-
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'
-
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
-
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 } }
-