こんにちは!Safie第2開発部のAndroidエンジニアのジェローム(@yujiro45)です。
Androidで3D/ARモデルを表示するのは難しそうに見え、技術的に大変そうですね。
この記事では、Sceneview-androidを使用して簡単に3DとARモデルを表示する方法を紹介します。
SceneViewとは
SceneViewはGoogle FilamentとARCoreを使用して3Dモデルを表示するライブラリです。
Thomas Gorisse(トーマス・ゴリス)と彼のチームによって開発されました。
- Google Filament:Googleが開発している物理ベースのリアルタイムレンダリングエンジンです。
- ARCore:Googleが開発したAndroid端末向けのARフレームワークです。
SceneViewは、以前のライブラリであるSceneformのKotlinバージョンであり、完全にKotlinで書き直されています。Sceneformはもはやメンテナンスされていません。
技術的には、SceneViewは3Dスペースで、カメラは中央に位置しており、座標はx=0、y=0、z=1です。該当部分のコード
導入
この記事では、KotlinとJetpack Composeを利用する導入方法について説明します。ただし、SceneViewはAndroidのxml layoutやFlutterやReact Nativeでも利用可能です。
SceneViewは2つのビューを提供します。
- ARSceneView : Google FilamentとARCoreの両方を使用して、3DおよびARを表示する目的で利用されます。
- SceneView : Google Filamentを使用して3Dモデルを表示するために利用されます。
SceneViewを追加するには、必要に応じてGradleファイルに適切な依存関係を追加するだけです。
ARSceneView
dependencies {
implementation("io.github.sceneview:arsceneview:X.X.X")
}
SceneView
dependencies {
implementation("io.github.sceneview:sceneview:X.X.X")
}
💡 GradleファイルにARSceneViewの依存関係を追加すると、ARSceneViewとSceneViewの両方を使用できます。ただし、SceneViewの依存関係のみを追加した場合は、SceneViewのみを使用できます。
実装
SceneViewは現在、GLTFおよびGLBファイルをサポートしています。3Dモデルのファイルをres/rawフォルダに入れてください。3Dモデルを表示するには、ModelNodeを使用する必要があります。これにより、3Dモデルから3Dノードを作成することができます。
*glbとgltfファイルは以下のサイトで無料でダウンロード出来ます。
3Dファイルを追加したら、以下のコードを使用して表示できます。
ARSceneView
SceneviewexampleTheme { val engine = rememberEngine() val modelLoader = rememberModelLoader(engine) // 3Dモデルの読み込み val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance(R.raw.android) ).apply { // 3Dモデルの初期設定 scale = Scale(1 / 40f) position = Position(0f) } ARScene( modifier = Modifier.fillMaxSize(), engine = engine, modelLoader = modelLoader, childNodes = rememberNodes { // モデルノードの追加 add(modelNode) } ) }
SceneView
SceneviewexampleTheme { val engine = rememberEngine() val modelLoader = rememberModelLoader(engine) // 3Dモデルの読み込み val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance(R.raw.android) ).apply { // 3Dモデルの初期設定 scale = Scale(1 / 40f) position = Position(0f) } Scene( modifier = Modifier.fillMaxSize(), engine = engine, modelLoader = modelLoader, childNodes = rememberNodes { // モデルノードの追加 add(modelNode) } ) }
ビルドが通ったら、3Dモデルが表示されました! 🎉
ARSceneView | SceneView |
---|---|
出典:Sketchfab, https://sketchfab.com/3d-models/android-7c30eda007684abbb78ea4b99d22fc2c (2024/10/07アクセス)
SceneViewにノードを追加するとき、ドキュメントによれば、ノードのデフォルトの位置は(x=0.0f, y=0.0f, z=0.0f)で、軸は下の画像のようになります。
カメラを別の位置に移動したい場合は、以下のように指定します。
SceneviewexampleTheme { //... Scene( //... cameraNode = rememberCameraNode(engine).apply { position = Position(z=5f) } //... ) }
アニメーション
ModelNodeのtransform()というメソッドを使用して、位置や回転やScaleを変更することができます。
https://github.com/SceneView/sceneview-android/blob/1e303adf92f1f7b67eb9aa4f9fc731d75213ac97/sceneview/src/main/java/io/github/sceneview/node/Node.kt#L620-L633
fun transform( position: Position = this.position, quaternion: Quaternion = this.quaternion, scale: Scale = this.scale, smooth: Boolean = isSmoothTransformEnabled, smoothSpeed: Float = smoothTransformSpeed ) = transform(Transform(position, quaternion, scale), smooth, smoothSpeed)
前のコードでは、3Dモデルを表示する事が出来ましたので、モデルをタップしたときに180度回転させるようにしましょう。
ARSceneView
SceneviewexampleTheme { val engine = rememberEngine() val modelLoader = rememberModelLoader(engine) // 3Dモデルの読み込み val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance(R.raw.android) ).apply { // 3Dモデルの初期設定 scale = Scale(1 / 40f) position = Position(0f) } ARScene( modifier = Modifier.fillMaxSize(), engine = engine, modelLoader = modelLoader, childNodes = rememberNodes { // モデルノードの追加 add(modelNode) }, // タッチイベントのリスナー onGestureListener = rememberOnGestureListener( onSingleTapConfirmed = { _, node -> if (node == modelNode) { // モデルノードの回転 modelNode.transform( rotation = Rotation(z = 180f), smooth = true ) } } ) ) }
SceneView
SceneviewexampleTheme { val engine = rememberEngine() val modelLoader = rememberModelLoader(engine) // 3Dモデルの読み込み val modelNode = ModelNode( modelInstance = modelLoader.createModelInstance(R.raw.android) ).apply { // 3Dモデルの初期設定 scale = Scale(1 / 40f) position = Position(0f) } Scene( modifier = Modifier.fillMaxSize(), engine = engine, modelLoader = modelLoader, childNodes = rememberNodes { // モデルノードの追加 add(modelNode) }, // タッチイベントのリスナー onGestureListener = rememberOnGestureListener( onSingleTapConfirmed = { _, node -> if (node == modelNode) { // モデルノードの回転 modelNode.transform( rotation = Rotation(z = 180f), smooth = true ) } } ) ) }
結果を見てみましょう!
ARSceneView | SceneView |
---|---|
ARで動画を表示する
3Dモデルの表示方法がわかったので、以下の動画をExoPlayer x Sceneviewで表示できるように実装していきましょう!
こちらで無料動画を入手できます。
Sceneviewのソースコードを見ると、VideoNodeが無効になっていることがわかりました。
また、Nodeのテクスチャを変更するには、Google FilamentのMaterialInstanceを作成し、SceneviewのMaterialLoaderを使用して新しいテクスチャを適用する必要があります。そのためには、以下の手順を実行する必要があります。
こちらがコードです!✨
class ExoPlayerVideoMaterial( engine: Engine, exoPlayer: ExoPlayer, private val materialLoader: MaterialLoader, ) { // SurfaceTexture作成 private val surfaceTexture = SurfaceTexture(0).apply { detachFromGLContext() } // SurfaceTexture→Surface作成 private val surface = Surface(surfaceTexture) // Textureのために、FilamentのStream作成 private val stream = Stream.Builder() .stream(surfaceTexture) .build(engine) // Texture作成 private val texture = VideoTexture.Builder() .stream(stream) .build(engine) // VideoTextureを使ったMaterialInstance作成 val videoInstance get() = materialLoader.createVideoInstance(videoTexture = texture).apply { setExternalTexture(texture) } init { // ExoPlayerのSurface設定 exoPlayer.setVideoSurface(surface) } }
Sceneview側では、作成したExoPlayerVideoMaterialを使いましょう!
SceneviewexampleTheme { // ExoPlayerの設定... val player = ExoPlayer... // さっきの作成したExoPlayerVideoMaterial val videoMaterial = ExoPlayerVideoMaterial(engine, player, materialLoader) val videoNode = PlaneNode( engine = engine, // 動画は16:9のため size = Size(16f, 9f), // NodeのMaterialInstance設定 materialInstance = videoMaterial.videoInstance, ) ARScene( //... childNodes = rememberNodes { // ノードの追加 add(videoNode) }, ) }
結果を見てみましょう!
ARで動画を表示出来ました!😀
まとめ
Sceneviewは、3DやARコンテンツを表示するための非常に便利なライブラリです。設定や使用がとても簡単です。しかし、私の個人的な経験から言うと、ドキュメントがあまり多くないため、もう少し複雑なことをしようとすると、Githubのソースコードを見る必要があります。アプリに3Dを追加したい場合は、ぜひ試してみてください!
モバイルチームは開発する仲間を募集しています!