본문 바로가기
안드로이드 자바

[JAVA][Android] AR core 앱 빠르게 만들기

by teamnova 2021. 8. 20.
728x90

이번 포스팅에선 AR core 라이브러리를 사용하여 간단한 AR 앱을 만들어 보겠습니다.

그 전에 먼저 아래 조건을 전부 만족하는지 확인이 필요합니다.

 

  • API 레벨 24 이상
  • 안드로이드 스튜디오 3.1 이상

 

그러나 3.6 버전 이상에선 AR core 작동에 필요한 Sceneform 라이브러리 1.15.0 버전이 작동하지 않는 문제가 있어서, 3.5.x 버전의 안드로이드 스튜디오를 다운받아 이 예제를 공부하시는 걸 추천드립니다.

옛날 버전의 안드로이드 스튜디오는 아래 링크에서 다운받을 수 있습니다.

https://developer.android.com/studio/archive

 

Android 스튜디오 다운로드 자료실  |  Android 개발자  |  Android Developers

이 페이지에는 Android 스튜디오 출시 관련 다운로드 자료실이 포함되어 있습니다.

developer.android.com

 

안드로이드 스튜디오가 준비되었다면 먼저 매니페스트에 아래 문장들을 추가해줍니다.

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.ar" />
<meta-data android:name="com.google.ar.core" android:value="required" />

<meta-data> 태그는 <application> 안의 아무 곳에나 넣어주면 됩니다. 태그 밖에 입력하면 안됩니다.

그리고 앱 수준 gradle 파일에 아래의 의존성 문구를 넣어줍니다.

implementation 'com.google.ar:core:1.21.0'
implementation "com.google.ar.sceneform.ux:sceneform-ux:1.15.0"

또한 앱 수준 gradle 파일의 android 안에 아래 문구를 넣어줍니다.

compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

 

그리고 File > Settings > Plugins에 들어가서 Google Sceneform Tools (Beta)를 설치합니다.

설치가 완료되면 IDE를 재시작합니다.

 

그리고 아래 링크에서 필요한 3D assets 들을 가져와야 합니다. 코드 전체를 다운로드받아서 samples/hellosceneform/app/models 폴더 안의 4개 파일들만 갖고 오면 됩니다.

 

  • andy.mtl
  • andy.obj
  • andy.png
  • andy.sfa

 

https://github.com/google-ar/sceneform-android-sdk/tree/v1.15.0

 

google-ar/sceneform-android-sdk

Sceneform SDK for Android. Contribute to google-ar/sceneform-android-sdk development by creating an account on GitHub.

github.com

 

이제 app 패키지 밑에 sampledata 라는 폴더를 만들어줍니다. app 폴더 우클릭 > New > Directory를 누르고 sampledata를 입력하면 됩니다.

그리고 그 안에 models 폴더를 만들고, 이 models 폴더 안에 위에서 가져온 4개 파일들을 넣어줍니다.

아래 형태로 보이면 됩니다.

 

다음으로 메인 액티비티의 XML 파일을 만들어줍니다.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment android:name="com.google.ar.sceneform.ux.ArFragment"
        android:id="@+id/ux_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

 

그리고 자바 파일은 아래와 같이 만들어줍니다.

public class MainActivity extends AppCompatActivity
{
    private static final String TAG = MainActivity.class.getSimpleName();
    private static final double MIN_OPENGL_VERSION = 3.0;

    private ArFragment arFragment;
    private ModelRenderable andyRenderable;

    @Override
    @SuppressWarnings({"AndroidApiChecker", "FutureReturnValueIgnored"})
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // AR 사용 가능 여부 체크
        if (!checkIsSupportedDeviceOrFinish(this)) {
            return;
        }
        setContentView(R.layout.activity_main);

        arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);

        ModelRenderable.builder()
                .setSource(this, Uri.parse("andy.sfb"))
                .build()
                .thenAccept(renderable -> andyRenderable = renderable)
                .exceptionally(
                        throwable -> {
                            Toast toast =
                                    Toast.makeText(this, "andy renderable을 불러올 수 없습니다", Toast.LENGTH_LONG);
                            toast.setGravity(Gravity.CENTER, 0, 0);
                            toast.show();
                            return null;
                        });

        // 화면을 탭해서 3D 객체 생성
        arFragment.setOnTapArPlaneListener(
                (HitResult hitResult, Plane plane, MotionEvent motionEvent) -> {
                    if (andyRenderable == null) {
                        return;
                    }

                    Anchor anchor = hitResult.createAnchor();
                    AnchorNode anchorNode = new AnchorNode(anchor);
                    anchorNode.setParent(arFragment.getArSceneView().getScene());

                    TransformableNode andy = new TransformableNode(arFragment.getTransformationSystem());
                    andy.setParent(anchorNode);
                    andy.setRenderable(andyRenderable);
                    andy.select();
                });
    }

    public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            Log.e(TAG, "Sceneform은 누가 버전 이상에서만 사용할 수 있습니다");
            activity.finish();
            return false;
        }
        String openGlVersionString =
                ((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE))
                        .getDeviceConfigurationInfo()
                        .getGlEsVersion();
        if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) {
            Log.e(TAG, "Sceneform은 OpenGL ES 3.0 이상 버전을 요구합니다");
            activity.finish();
            return false;
        }
        return true;
    }

}

 

이렇게 한 후 앱을 실행하면 아래와 같이 작동합니다.

평면(바닥)을 인식해야 하기 때문에 평평한 곳에서 실행하는 게 좋을 것 같습니다.