해당 글은 SceneView 0.9.10를 사용했습니다. SceneView 0.10.0 버전에 대한 테스트는 이루어지지 않았으며 이전 글에서 밝힌 position이 제대로 먹히지 않는 문제에 대해서는 아직도 해결방법을 찾지 못했습니다.
+2023.08.07 확인 결과 SceneView 0.10.0 버전에서 정상작동합니다.
이전까지 글에서는 그래픽 파일을 구해 화면에 띄우는 것까지 다루었다. 그도 그럴게 나도 거기까지만 알아냈고 해당 라이브러리의 README에 적힌 커스터마이징 안내를 봤지만 Renderable에 TextView나 ImageView를 사용하라는 말만 있고 정확한 코드가 나와있지는 않았다.
당장 AR 위에 이름표처럼 정보를 표시해야 하는데 이전 버전이나 마찬가지인 Sceneform에서 사용한 코드만 나오고 막상 적용하면 에러가 넘쳐났다. 밑져야 본전이라는 마음가짐으로 Chat GPT4에게도 물어봤지만, 마찬가지였다.
안 그래도 생으로 배우고 있는데 더 생으로 배우자는 의미로 제발 Renderable에 대해서 버그가 발생했고 누군가 깃허브의 issue나 discuss에 올려뒀으면 좋겠다는 생각으로 깃허브 다이빙을 했다.
그리고 정말로 Renderable에 버그가 있었던 기록이 있었고 거기서 코드를 가져오는데 성공했다. 그렇게 온갖 뻘짓이 공식 깃허브 탐방으로 해결되었다.
이전 글을 통해 ArModelNode를 화면에 띄우는데에 성공했다고 가정하고 과정 설명이 진행된다.
또 정확하게 말하자면 이건 이름표가 아니라 커스텀 렌더링 객체를 만드는 과정이다.
내 편의로 이렇게 이름을 붙였을 뿐 명확한 명칭은 ViewNode이다. 커스텀 렌더링 객체, 즉 ViewNode라는 건 말그래도 사용자가 만든 레이아웃을 렌더링하여 보여주는 객체라고 생각하면 된다.
그러니 굳이 이름표가 아니라 다른 xml 레이아웃 파일(View)을 AR과 함께 그래픽으로 보여주고 싶을 때도 충분히 사용 가능한 방법이라는 것이다.
본격적인 과정에 들어가기 앞서서 간단하게 과정을 설명하자면 이렇다.
1. AR로 띄울 뷰의 xml 파일을 작성한다. (layout 작성)
2. ViewRenderable를 builder를 통해 사용할 View를 지정해주고 build한다. (ViewRenderable 작성)
3. build된 ViewRenderable에 thenAccept를 통해 ViewNode를 생성한다. (ViewNode 작성)
4. ViewNode의 Renderable, parent, position를 설정한다. (ViewNode 설정)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/monster_info"
android:paddingHorizontal="30dp"
android:paddingVertical="10dp"
android:text="test monster info xml"
android:textColor="@color/white"
android:textSize="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
특별한 건 없다. ViewNode가 생각보다 잘 안 보일 가능성이 있어서 크기가 커도 된다.
ViewRenderable.builder()
.setView(this, arTextViewBinding.root)
.build()
.thenAccept {
//build가 이루어지고나서 적용되는 것들을 작성하는 구간이다.
//3, 4번의 과정이 여기서 이루어진다.
}
Android Studio에서 ViewRenderable에 대한 설명을 보면 View의 크기는 250dp마다 1m라는 설명을 볼 수 있다. 즉 250dp가 실제 카메라에서 1m로 보인다.
또한, ViewRenderable은 2D Android View를 렌더링한다는 설명도 확인할 수 있다.
자세히 확인하면 글이 끝도 없이 길어지기에 중요하다 생각되는 부분만 언급하자면 옛날 RelativeLayout처럼 연결된 노드를 중심으로 ViewRenderable의 위치를 정해줄 수 있다.
setVerticalAlignment()는 수직에서의 ViewRenderable의 위치를 정하는 메소드로 기본 값은 BOTTOM이다. 이 메소드에 사용되는 값은 ViewRenderable 내부에 존재하는 열거형 VerticalAlignment에 존재한다.
setHorizontalAlignment()도 존재한다. Vertical과 다르게 수평상에서의 ViewRenderable의 위치를 정하며 기본값은 CENTER이다. 이 또한 ViewRenderable의 내부에 존재하는 열거형 HorizontalAlignment에 메소드에 사용되는 값이 존재한다.
마지막으로 ViewRenderable는 3D 공간에서 ModelNode의 setModelInstance를 이용해 Node로 연결하여 렌더링을 하는 기본 클래스인 Renderable을 상속받은 자식 클래스이다.
ViewRenderable.builder()
.setView(this, 커스텀한_뷰노드의viewBinding.root)
.setVerticalAlignment(ViewRenderable.VerticalAlignment.TOP)
.build()
.thenAccept { renderable: ViewRenderable ->
val viewNode = ViewNode()
viewNode?.parent = modelNode //부모 노드를 설정한다.
viewNode?.setRenderable(renderable) //사용할 Renderable을 설정한다.
viewNode?.position = Position(x = 0.0f, y = 5.0f, z = 0.0f) //위치는 부모 노드를 기준으로 설정된다.
}
위 코드가 거의 최종 코드이다.
viewBinding을 적용했기에 커스텀한 ViewNode의 viewBinding 내용을 가진 변수를 만들어 작성해주었다. viewBinding을 사용하지 않고 R.layout.커스텀한_뷰노드_id로 setView의 View 설정도 가능하다.
아직 viewBinding으로 설정한 커스텀 뷰의 내용 변경이 순서에 따라 어디까지 반영되는지는 확인하지 않았지만, 렌더링 작업 이전에 변경한 내용이 무사히 반영되는 것은 확인을 마쳤다.
안녕하세요, 블로그 잘보고 있습니다.
혹시, 커스텀한_뷰노드의viewBinding.root 이게 의미하는게 무엇인지 알려주실수 있나요?