Slide 1

Slide 1 text

簡単なAR機能とUI実装を組み合わせてみた記録 Mobile勉強会 Wantedly × チームラボ × Sansan #14 2024/05/21 Fumiya Sakai AR関連ハッカソンに参加した際の記録

Slide 2

Slide 2 text

自己紹介 ・Fumiya Sakai ・Mobile Application Engineer アカウント: ・Twitter: https://twitter.com/fumiyasac ・Facebook: https://www.facebook.com/fumiya.sakai.37 ・Github: https://github.com/fumiyasac ・Qiita: https://qiita.com/fumiyasac@github 発表者: ・Born on September 21, 1984 これまでの歩み: Web Designer 2008 ~ 2010 Web Engineer 2012 ~ 2016 App Engineer 2017 ~ Now iOS / Android / sometimes Flutter

Slide 3

Slide 3 text

iOSのUI実装本を執筆しています! 書籍に掲載したサンプルのバージョンアップや続編等に現在着手中です。 少しの工夫で実現できるTIPS集やライブラリ表現の活用集をはじめとした、iOSア プリ開発の中でも特にUI実装やUIKitを利用した画面の中で特徴を与える様な表現 という題材に焦点を当てた書籍となっております。 現在は電子書籍版のみとなります。 こちらは全て¥1,000となっております。 https://just1factory.booth.pm/ 概要: https://book-tech.com/ 価格: 📖 Booth 📖 Book Tech

Slide 4

Slide 4 text

UI実装であると嬉しいレシピブックの最新情報 UI実装であると嬉しいレシピブックVol.3として昨年10月に商業化しました! Still WIP これまでの同人誌として頒布したものに加えて、Vol.1及びVol.2に頒布したものの 中で書籍に載せきれなかったものや表現や動きが特徴的でユーザーにもほんの少し 遊び心を与える様なUI実装を紹介したものをVol.3としています。 概要: これからの構想: こちらで購入可能です: Amazon / Google Play / Apple Books / KINOKUNIYA / Rakuten BOOKS etc.. 🏊 iOS: SwiftUIを利用したUI実装や動画関連の実装 🏊 Android: Jetpack Composeの基本やその他気になるUI表現の考察

Slide 5

Slide 5 text

AR関連の実装体験ハッカソン参加からの学びの記録 全く何もわからない状態から「ほんの少しだけ」でも触って試してみたいへ 基本的な知識とこれまで得た知見を組み合わせる実装を自分で試したものになります。 1. これまでも登壇等の機会を利用して知見を拝聴する機会があったが…: 業務内ではAR関連のトピックスに触れる経験はほとんどなかったのが本音の所ではありました。と同時に「どこかで少しでも触 れる機会が欲しい」という思いもありましたので、ハッカソン参加を試みました。 2. まずは試しやすい&馴染みがありそうな部分から動かしてみる: どんなにシンプルなアイデアや初歩的な実装でも構わないので、まずは簡単なものや実装サンプル等に触れる所から始めてみた いなと思いました。最初は海外YouTubeの方(kavsoft様)のUI実装と組み合わせたサンプル実装を調査していました。 3. 最初は自分が慣れ親しんだ技術の組み合わせで実現できないか?という観点: 普段の割合としてはUIKit・SwiftUIを利用したUI実装に触れる機会の方が圧倒的に多かったので、まずはARモデルを画面表示さ せる所から始めて、その後に見せ方を少し工夫する様なサンプルに仕上げてみる目標で進めました。

Slide 6

Slide 6 text

あれ?「AR 1day Hackathon/お試し会」ですと…!!! 1日時間をしっかりと使って、AR関連の事に触れていくチャンスと思いました 感想を発表する時間の中で様々なプロトタイプが誕生したり、難しかった点を交換できたり、と刺激の多い時間でした。

Slide 7

Slide 7 text

まずはARモデルを手に入れてXcodeで動かしてみよう! developers.apple.comの拡張現実のページからUSDZファイルを入手する まずは3Dモデル(USDZ形式)を手に入れてXcode上で表示してみる所から始める

Slide 8

Slide 8 text

ハッカソンで利用した無料素材はどこから利用する? Blender等を利用してUSDZ形式のモデルを作成するスキルはない… 無料の3Dモデル(USDZ形式)を提供しているサービスを利用する事にしました! Sketchfab: https://sketchfab.com/

Slide 9

Slide 9 text

ARモデルを利用した表現とUI実装の組み合わせ例 SwiftUIを活用したUI実装と組み合わせた事例やコードに触れてみよう ① SwiftUI 2.0 SceneKit - SwiftUI Loading 3D Objects/Models Using SceneView - SwiftUI 2.0 Tutorials: https://www.youtube.com/watch?v=v8j121DiUfg ② SwiftUI 3.0 Pizza Animation Challenge - Complex Animations - Pizza App UI - Xcode: SwiftUI Tutorials: https://www.youtube.com/watch?v=4fSwN48eSfU ③ SwiftUI 3D Shoe App UI - SceneKit - 3D Objects - Complex UI - Xcode 14 - SwiftUI Tutorials: https://www.youtube.com/watch?v=d4ciSOLvIH8

Slide 10

Slide 10 text

今回のハッカソンで作成したUI実装サンプルはこちら 実際のコードとして実装を当てはめるとこのような形にできる(Presentation層) 無料の3Dモデル(USDZ形式)をSceneKitで表示可能(SCN形式)にしてSwiftUIに組み込んでみました 今回のサンプルにおけるポイント: ① 3DモデルをSceneKitで表示できる形にする点 ② SceneKitはUIKitベースなのでSwiftUIで利用可能にする点 ③ SwiftUIのAnimation表示やInteraction操作の実装

Slide 11

Slide 11 text

SwiftUI製の画面でSceneKitを利用した3Dモデル表示 Xcodeで変換した.scn形式の3Dモデル表示部分SceneKitを利用しています UIViewRepresentableを利用してSCNViewをSwiftUIで表示させる方針を取る struct DetailCustomSceneView: UIViewRepresentable { // MARK: - `@Binding` Property @Binding var scene: SCNScene? // MARK: - Function func makeUIView(context: Context) -> SCNView { let view = SCNView() view.allowsCameraControl = false view.autoenablesDefaultLighting = true view.antialiasingMode = .multisampling2X view.scene = scene view.backgroundColor = .clear return view } func updateUIView(_ uiView: SCNView, context: Context) {} } // 表示対象SCNScene(SceneKit)をStateとして定義 @State private var scene: SCNScene? // ※ initializer内での調整処理 // 👉 少し拡大&少し手前側に斜めにして見やすく self.scene?.rootNode.rotation = SCNVector4( 1, // X軸 0, // Y軸 0, // Z軸 0.1 * Float.pi // 角度(ラジアン) ) self.scene?.rootNode.scale = SCNVector3Make( 1.28, // X軸 1.28, // Y軸 1.28 // Z軸 ) 3Dモデル表示と調整対応部分 ※標準が水平で見ずらい

Slide 12

Slide 12 text

SceneKitを利用した3Dモデル表示を回転可能にする SwiftUIのDragGesture処理を応用する事で強引ではあるが実現可能 DragGestureでの変化量を保持しておき、SCNTransactionを利用したAnimation処理と連動する .gesture( // DragGestureと連動して回転する様な形を実現する DragGesture() .updating($temporaryOffsetValue, body: { currentValue, outputValue, _ in // MEMO: -64.0をしているのは調整のため outputValue = currentValue.location.x - 64.0 }) ) .onChange(of: temporaryOffsetValue) { // MEMO: 変数「offset」が変更されるので、配置要素が合わせて回転する rotateSceneViewObject(animate: temporaryOffsetValue == .zero) } // Drag処理変化量に合わせて水平方向回転を実施する private func rotateSceneViewObject(animate: Bool = false) { // ① Transition処理を開始する if animate { SCNTransaction.begin() SCNTransaction.animationDuration = commonDurationValue } // 👉 この様な条件分岐にしないと綺麗に回転しなかったんですよねー...😇 scene?.rootNode.eulerAngles.y = Float((temporaryOffsetValue * .pi) / 180.0) // ② Transition処理を実行する if animate { SCNTransaction.commit() } } スライダー要素のModifier処理部分の抜粋 // DragGesture発動時に一時的に格納するための変数 @GestureState private var temporaryOffsetValue: CGFloat = 0

Slide 13

Slide 13 text

一覧から詳細画面へ遷移する様に見せる構成のポイント 実は画面の状態に合わせて表示対象の内容を切り替えているだけに過ぎない キーワードになるのは「.matchedGeometryEffect」Modifierの活用: var body: some View { NavigationStack { // 全体をZStackにして表示要素を重ねている // 👉 AndroidやFlutter等でよく見る「Hero」Animationの様なイメージ ZStack { // `@State`で定義した変数の状態を元にして表示状態を決定する if selectedMaterial == nil { // 一覧表示時のView全体要素 (全体はScrollView + Grid表示構成) } else { // 拡大時のView全体要素 } } .frame(width: screenWidth) .navigationTitle("3Dモデルを表示して回転させよう♻ ") .navigationBarTitleDisplayMode(.inline) } } @State private var selectedMaterial: MaterialEntity? = nil 表示対象Entityを格納するState値 Animation処理で切替 View要素の表示切り替 え処理に対して連続性 がある形になる様な工 夫を加える。 一覧表示をしている矩形をタップし た際に表示対象のEntityを選出して 適用する事で状態変化を起こす。 .matchedGeometryEffectを利用する方針 矩形とテキスト要素に対して適用する。

Slide 14

Slide 14 text

.matchedGeometryEffectを利用したAnimation処理 // Grid正方形の表示要素 HStack { VStack { Text(name) .foregroundColor(.white) // 👉 ① Animation対象となるテキスト要素(遷移元) .matchedGeometryEffect(id: effectTitleID, in: namespace) } .frame(width: standardRectangle, height: standardRectangle) .background( Rectangle() // 👉 ② Animation対象となる矩形要素(遷移元) .matchedGeometryEffect(id: effectShapeID, in: namespace) .onTapGesture { withAnimation(springAnimation) { selectedMaterial = material } } ) Spacer() } // 拡大時のView全体要素 VStack { // (1) ヘッダー表示をするためのView要素を配置する HStack { Text(name) .foregroundColor(.white) // 👉 ① Animation対象となるテキスト要素(遷移先) .matchedGeometryEffect(id: effectTitleID, in: namespace) .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) .padding(.top, 20.0) Spacer() Button(action: { withAnimation(springAnimation) { selectedMaterial = nil } } label: { Text("× 閉じる") }) } .padding(.horizontal, 8.0) // (2) SceneKitを仕込んだView要素を配置する DetailView(scene: materialScene) } // 表示エリアは「横幅いっぱい&縦400px」を確保する .frame(maxWidth: .infinity, maxHeight: 400.0) .background( Rectangle() // 👉 ② Animation対象となる矩形要素(遷移先) .matchedGeometryEffect(id: effectShapeID, in: namespace) ) 一意なID名と@Namespaceで定義する名前空間との紐付けをしている点がポイント(矩形&テキストが対象) LazyVGrid(columns: gridColumns, spacing: 8.0) { ForEach(MaterialFactory.getMaterials()) { material in // … 紐づけるID名を組み立てる + 一覧表示処理(省略) } } 補足: 一覧表示部分の処理イメージ 嬉しいポイント 複数要素にAnimation 処理を適用させたい場 合でも名前空間と一意 なIDがあれば実現可能 であること。

Slide 15

Slide 15 text

今回の経験を自分の知見として繋げていくために この時に調べた過程や抱いた疑問等を整理しておくと良さそうに感じました 🤔 具体例に触れた経験や解説を聞いた際に出た疑問やアイデアを記録する ①3Dモデルの管理について 結構重たいファイルなので、これら もGitで管理しているのか? Xcodeプロジェクト内に保持してお く以外の管理方法ってあるのか? 実際の業務ではこの様な3Dモデルは どの様なツールで作成されている? ③実務や機能の使われ方 平素でよく利用しているアプリの中 でAR機能を有するものはある? 機能内でARに関連する機能が生まれ たきっかけや着想は? 実務において機能開発において大変 だった点はどの部分か? ②AR関連実装の学び方 実務にキャッチアップするにあたっ てまずはどこから勉強したか? 普段から参考にしているサイトや学 習教材等はあったりする?

Slide 16

Slide 16 text

まとめ 以前から抱いていた「難しそう」という名の壁を少しだけ突破できた 組み合わせて実現できる「可能性」に目を向ける事で楽しく取り組む事を忘れないで! 1. 簡単な作業をしたり実際に動かしてみることが壁を越える第一歩: 最初からある程度まとまった物を作る事は難しいので、最初はサンプルコードとして提示されているものを動かしてみる事が大 切だと改めて実感しました。また、自分が試した事を言語化して整理する事もしておくと良さそうに思いました。 2. 既存の技術や慣れ親しんだ実装と組み合わせてみる: 今回のUI実装はSwiftUIを利用したAnimation実装やInteraction操作とSceneKitで3Dモデルを表示する方法を組み合わせたものに 過ぎませんが、簡単な事例を作って応用する際の大事な視点を持つヒントを発見する事にもつながると感じました。 3. 常に「余白」を持つ様にしてみよう: 一朝一夕で簡単に結果につながらずとも、この体験で得た「学び」の機会を応用していくためには、事例から情報を得たり試行 錯誤を繰り返す事も多いので、自分の中に常に余裕と新しい事を知る前のワクワクする気持ちを大切にしたいです。 ゆっくりと時間を持って取り組んでみる事の大切さ

Slide 17

Slide 17 text

謝辞: 株式会社メルカリ&参加者の皆様への感謝 会場提供やサポート対応は勿論、参加者との交流ができた良き機会でした! 国籍・技術バックグラウンド・職業を越えての交流や開発ができるのは久しぶりの体験でした

Slide 18

Slide 18 text

Thank you for listening ! GitHub: https://github.com/fumiyasac/ARDemoSample