20210405のUnityに関する記事は6件です。

Unity iOS TwitterKitを使用するとFirebase DynamicLinkが機能しなかった

以下のエラーがでる。(Analyticsを使用している場合) [Firebase/Analytics][I-ACS023001] Deep Link does not contain valid required params. URL params: { TwitterKitを使用しない場合は上手くいった。なぜ?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity VFX GraphのOutput Particle Meshで両面描画する方法。

前提 VFX Graphで、Output Particle Meshノードをそのまま使おうと思っても面の裏側が描画されないため、使えない。 Blenderなどでメッシュそのものを2枚重ねにするという方法もあるが、確実ではないし、結構面倒くさい。 やり方 Unityのカリングが効いてしまい片面になっているため、カリングを切ればいい。 Output Particle Meshノードをを選択した状態で、インスペクタ画面を開きCull ModeをOffにすることで両面が描画される。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityバグ取り生配信#01まとめ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swiftで開発を行なっているiOSアプリにUnityを組み込む(Unity as a Library)

TL;DR Swiftで新規開発を行なっているiOSアプリに、Unityを組み込んだ経験をまとめます。 公式のサンプルではObjective-Cでの実装のみである中で、Swiftでの実装事例の1つとなれば幸いです。 また自分の探し方の問題かもしれませんが、Unity as a Library (UaaL)をSwiftのiOSアプリに組み込む英語の資料があまり見つかりませんでした。何かおすすめがありましたら教えていただけると幸いです! ポイント Unityの起動時にローディングの時間がかかるので、アプリを立ち上げた時点でUnityを起動しバックグラウンドでローディング アプリの画面遷移をNavigationControllerで実現したかったため、UnityのViewControllerからViewのみを呼び出す 今回のアプリでは実装のメインがSwiftで、背景としてUnityを使うという方針にしたため、iOSアプリ→Unityの呼び出しのみ実装 参考にした記事 [Swift] Unity as a LibraryをSwiftから呼ぶ 主にこちらの記事を参考にしながら、iOSアプリのViewControllerからUnityのViewControllerのViewを呼び出す実装を進めました。 Unity as a LibraryのサンプルプロジェクトをSwiftで書き直した UaaLのサンプルをSwiftで書き換えてくださっているので、全体像を把握するために大いに活用させていただきました。 (今回、Unityの読み込み方法などがこちらとは異なります) その他の便利な参考はこちら 実装 前提 アプリのメインはSwiftで実装を行い、背景画像としてUnityの3Dモデルを読み込むようなアプリです。 また、メインのSwiftからUnityの関数を呼び出すことも行いました。 iOSアプリ設計パターン入門 開発に当たっては、こちらの書籍を参考にMVPのアーキテクチャパターンを選択しました。 アプリ起動時にUnityを呼び、バックグラウンドでローディング Unity Classの作成 様々な場所から呼び出せるよう、Unityをシングルトンオブジェクトとして実装します Unity.swift import Foundation class Unity: NSObject, UnityFrameworkListener { static let shared = Unity() private let unityFramework: UnityFramework override init() { let bundlePath = Bundle.main.bundlePath let frameworkPath = bundlePath + "/Frameworks/UnityFramework.framework" let bundle = Bundle(path: frameworkPath)! if !bundle.isLoaded { bundle.load() } // It needs disable swiftlint rule due to needs for unwrapping before calling super.init() // swiftlint:disable:next force_cast let frameworkClass = bundle.principalClass as! UnityFramework.Type let framework = frameworkClass.getInstance()! if framework.appController() == nil { var header = _mh_execute_header framework.setExecuteHeader(&header) } unityFramework = framework super.init() } func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) { unityFramework.register(self) unityFramework.setDataBundleId("com.unity3d.framework") unityFramework.runEmbedded(withArgc: CommandLine.argc, argv: CommandLine.unsafeArgv, appLaunchOpts: launchOptions) } var view: UIView { unityFramework.appController()!.rootView! } func sendMessageToUnity(objectName: String, functionName: String, argument: String) { unityFramework.sendMessageToGO(withName: objectName, functionName: functionName, message: argument) } func applicationWillResignActive(_ application: UIApplication) { unityFramework.appController()?.applicationWillResignActive(application) } func applicationDidEnterBackground(_ application: UIApplication) { unityFramework.appController()?.applicationDidEnterBackground(application) } func applicationWillEnterForeground(_ application: UIApplication) { unityFramework.appController()?.applicationWillEnterForeground(application) } func applicationDidBecomeActive(_ application: UIApplication) { unityFramework.appController()?.applicationDidBecomeActive(application) } func applicationWillTerminate(_ application: UIApplication) { unityFramework.appController()?.applicationWillTerminate(application) } } AppDelegateから呼び出す アプリが立ち上がったタイミングでUnityを呼び出します。こうすることで、バックグラウンドでローディングされるため、スプラッシュ画面がユーザーに表示されず、待ち時間も発生しません。 新規のアプリなので、パフォーマンスなどにも今のところは影響ありません。 AppDelegate.swift import Firebase import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { FirebaseApp.configure() // Unityを呼び出す Unity.shared.application(application, didFinishLaunchingWithOptions: launchOptions)      // Unityとは関係のない、sign inの画面 let singInViewController = SignInViewController(nibName: nil, bundle: nil) let navigationController = UINavigationController(rootViewController: singInViewController) let model = SignInModel() let presenter = SignInPresenter(view: singInViewController, model: model) singInViewController.inject(presenter: presenter) window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = navigationController window?.makeKeyAndVisible() return true } } UnityのViewControllerからViewのみを呼び出す Integrating Unity into native iOS applications Unity as a Libraryの仕組みとしては、メイン(ホスト)のiOSアプリのUIWIndowとは別に、Unity側でUIWindowを生成しています。そしてホスト側からUnity側のWindowに切り替える際には、showUnityWindowというUnityFrameworkの関数を呼び出す必要があります。(UIApplecation内に、複数のUIWindowが存在していて、最前面のUIWindowがアプリの画面として表示されているということになります。) つまりUnityの画面をiOSアプリ内で表示する公式な方法としては、UnityのUIWindowを最前面に出すということになります。 一方で今回は、アプリの画面遷移をNavigationControllerで実現する必要がありました。 その実現に当たって、以下の2つの方法を検討しました。 a. Unity側のWindowからViewだけを呼び出し、アプリの画面を表示しているViewControllerにaddSubViewする b. Unity側のWindowを後ろに置いたまま、アプリの画面を表示しているViewControllerの背景を透明にすることで、Unity側のWindowを背景にする 結論としては、a.を選択しました。やってみればすぐに分かることですが、b.のやり方だと、NavigatioControllerのアニメーションに対して、背景のUnity側Windowは動きません。つまり、NavigationControllerのアニメーションと連動せず違和感が発生することになるためです。 Unity ClassのViewにアクセスできるようプロパティを実装 先ほどの、AppDelegate.swiftから抜粋。 Unity.swift ...   var view: UIView { unityFramework.appController()!.rootView! } ... ホスト側ViewControllerへのaddSubViewと、そのsubViewを背面へ移動 HostViewController.swift import UIKit class HostViewController: UIViewController { // UnityのViewの読み込み private let unityView = Unity.shared.view private var presenter: HostPresenterInput! func inject(presenter: HostPresenterInput) { self.presenter = presenter } init() { super.init(nibName: nil, bundle: nil) // addSubView view.addSubview(unityView) // 追加したsubViewのサイズをViewControllerのViewのサイズに合わせる unityView.frame = view.frame // 追加したsubViewを背面へ(addSubViewは最前面に追加するため、ViewControllerのViewの後ろに設定する必要がある) view.sendSubviewToBack(unityView) } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.isNavigationBarHidden = true } } iOSアプリ→Unityの呼び出し (Calling C# back from native code) iOSアプリからUnityに対して、データの受け渡しや関数の呼び出しを行います。 メインの開発はSwiftを用いたiOSアプリの開発で、Unityは背景として読み込むという方針を取りました。そのため、Unity→iOSのやりとりは発生しません。 今回は、簡易なUnitySendMessageを選択しました。 Building plug-ins for iOS (Calling C# back from native code) 補足 今回Unity→iOSアプリの呼び出しが存在しなかったため、次の手順にあるNativeCallProxy.hのヘッダーファイルは存在しません。 Integrating Unity as a library into standard iOS app (5. Expose NativeCallProxy.h) UnityFrameworkのメソッドを呼び出す 今回MVPのアーキテクチャパターンを選択したため、Modelからの呼び出しになっています。 HostModel.swift import Foundation protocol HostModelInput { func sendData(data: [String?]) } final class HostModel: HostModelInput { func sendData(data: [String?]) { // 引数はStringなので、それに合わせる let dataText = """ {\"data0\": \(data[0]!), \"data1\": \(data[1]!), \"data2\": \(data[2]!), \"data3\": \(data[3]!), \"data4\": \(data[4]!), \"data5\": \(data[5]!)} """ // UnityFrameworkdのメソッドを呼び出す Unity.shared .sendMessageToUnity(objectName: "SampleData", functionName: "SetData", argument: dataText) } } その他の参考 iOSアプリ設計パターン入門 開発に当たっては、こちらの書籍を参考にMVPのアーキテクチャパターンを選択しました。(選択の過程をまとめた記事はこちら→PoCでiOSアーキテクチャにMVPを採用した話) iOSアプリ開発に限らず、設計パターンを学びたい方に損得抜きで強くおすすめです。歴史的経緯も含めた設計パターンの丁寧な解説、さらに各設計パターンのサンプルコードで構成されています。 【Unity】MirrativのEmbedding Unityを更新した話: 実践 Unity as a Library 【Unity】Mirrativのアバターがなんで動いているのか誰にもわからないので説明する 実際にサービスを運用されている事例から、実践的な説明がされています。 2本目はUnity as a Library (UaaL)が実装される前に、iOSアプリにembedを行なった方法を説明されています。 (Unityに詳しい先輩曰く、「黒魔術のようなものなので、今はUaaLを使うべき」とのことでした!) Integrating Unity into native iOS applications 公式のドキュメントで、iOSアプリから呼び出せるメソッドが説明されています。 こぼれ話 Using Unity as a Library in other applications Unity as a Library is intended for specialist users who use native platform technologies such as Java/Android, Objective C/iOS, or Windows Win32/UWP, and want to include Unity-powered features in their games or applications. Unity as a Libraryは、Java/Android、Objective C/iOS、Windows Win32/UWPなどのネイティブプラットフォーム技術を使用し、ゲームやアプリケーションにUnity搭載の機能を搭載したいと考えている専門家ユーザーを対象としています。 公式の紹介ページには、上記の脅し文句があります。iOSアプリ開発自体が初めての自分は最初少しひるみましたが、これ以外に方法がないので意を決して取り組みました。確かにUnityがiOSアプリの中でどのように読み込まれるのか、ライフサイクルにどのように組み込まれるべきなのかなど理解に時間がかかった部分もあります。しかしながら、この記事内で紹介している記事を一通り読んでいただければ、全体像は掴めるのではないかと思います。Unityをネイティブアプリに組み込みたくなった方は、不可能なことではないのでぜひ挑戦してみてください!また、不明点などがあれば一緒に学ばせていただければと思いますので、コメントください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vuforiaのインポート

1,custam packageからvuforiaをインポートする 2,maincameraを消して、ARcameraを選択 3,develop→lisencemanager→getdevelopmentを選択 4,appnameとチェックをつけてconfirmを押す。できたらライセンスキーをコピーする 5, ARcameraのopen vuforia engineを選択してライセンスキーを設定する 6,targetmanagerのadddatabaseを選択し、name,deviceを選択する 7,上記が終わったら、AddTagetを選択し、マーカーを選択していく 8,checkをつける 9,ダウンロードデータベースを選択し、Unityを選びダウンロードする
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity(C#)】OculusQuestでAndroidネイティブの音声認識機能を呼び出せるのか検証

はじめに VRヘビーユーザーからすれば当たり前のことかもしれませんが、 OculusQuestにマイクが搭載されているのはご存じでしたでしょうか。 ボイスチャットに利用されることがほとんどで、 その他の用途で使われている事例をあまり見たことがありませんでした。 (たぶん世の中にはたくさんある) しかし、最近目にした記事にボイスチャット以外の用途でマイクを使った事例がありました。 【参考リンク】:Synamon、ロゼッタと「リアルタイム多言語翻訳システム装備のVRオフィス」を共同開発 一言で説明すると、翻訳VRアプリです。 マイクを音声認識の受け口として利用しています。 そこで、私も勉強がてら"OculusQuestのマイクを利用したVRアプリ作りに挑戦してみたい"と思い、実際に作りました。 勉強がてら作成していた翻訳VRできました!?OculusQuestのマイクで拾った音声を音声認識APIに渡して、認識結果を翻訳APIに渡す、、、というやり方です?次はマルチ対応していきます?#OculusQuest #Unity pic.twitter.com/k95D73gEnh— KENTO⚽️XRエンジニア?Zenn100記事マラソン挑戦中29/100 (@okprogramming) April 3, 2021 Androidネイティブの音声認識機能 Androidには音声認識の機能が搭載されており、開発者がアプリに組み込めるようにその機能が公開されています。 【参考リンク】:RecognitionListener そして、そのAndroidのネイティブの機能をUnityからネイティブプラグインとして呼び出すことができます。 OculusQuestはAndroidベースであり、Androidアプリとしてビルドすることから、 "もしかしたら、Androidのネイティブプラグインを導入すれば動くんじゃないか?"という仮説に辿り着きました。 その検証を行った結果を記していきます。 ネイティブプラグイン作成 まずは下記リンクを参考にネイティブプラグインを作成します。 【参考リンク】:Unity向けAndroidネイティブプラグインの作り方 【参考リンク】: AndroidのSpeechRecognizerをネイティブプラグイン化してUnityで使う 記事の通りでほとんど詰まることなくいけました。 なんか動かん、という場合には地味にやることが多いので原因の特定はそこそこの苦行となります。 ですので面倒かもしれませんが最初からやり直した方が早い場合もあるかもしれません。 Javaで書いたプラグイン側のコードとC#で書いたUnity側のコードだけメモ残します。 プラグイン側のコード プラグイン側のコード package com.kento.speechtest; import java.util.ArrayList; import java.util.Locale; import android.content.Context; import android.os.Bundle; import android.speech.RecognitionListener; import android.speech.RecognizerIntent; import android.speech.SpeechRecognizer; import android.content.Intent; import static com.unity3d.player.UnityPlayer.UnitySendMessage; public class Speech { static public void StartRecognizer(Context context, final String callbackTarget, final String callbackMethod) { Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, Locale.JAPAN.toString()); intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, context.getPackageName()); SpeechRecognizer recognizer = SpeechRecognizer.createSpeechRecognizer(context); recognizer.setRecognitionListener(new RecognitionListener() { @Override public void onReadyForSpeech(Bundle params) { // On Ready for speech. UnitySendMessage(callbackTarget, callbackMethod, "onReadyForSpeech"); } @Override public void onBeginningOfSpeech() { // On begining of speech. UnitySendMessage(callbackTarget, callbackMethod, "onBeginningOfSpeech"); } @Override public void onRmsChanged(float rmsdB) { // On Rms changed. UnitySendMessage(callbackTarget, callbackMethod, "onRmsChanged"); } @Override public void onBufferReceived(byte[] buffer) { // On buffer received. UnitySendMessage(callbackTarget, callbackMethod, "onBufferReceived"); } @Override public void onEndOfSpeech() { // On end of speech. UnitySendMessage(callbackTarget, callbackMethod, "onEndOfSpeech"); } @Override public void onError(int error) { // On error. UnitySendMessage(callbackTarget, callbackMethod, "onError"); } @Override public void onResults(Bundle results) { ArrayList<String> list = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); String str = ""; for (String s : list) { if (str.length() > 0) { str += "\n"; } str += s; } UnitySendMessage(callbackTarget, callbackMethod, "onResults\n" + str); } @Override public void onPartialResults(Bundle partialResults) { // On partial results. UnitySendMessage(callbackTarget, callbackMethod, "onPartialResults"); } @Override public void onEvent(int eventType, Bundle params) { // On event. UnitySendMessage(callbackTarget, callbackMethod, "onEvent"); } }); recognizer.startListening(intent); } } Unity側のコード Unity側のコード using System; using UnityEngine; using UnityEngine.Android; using UnityEngine.UI; // <summary> /// Androidのネイティブ音声認識機能呼び出し /// </summary> public class AndroidNativeSpeech : MonoBehaviour { [SerializeField] private Text recText; [SerializeField] private Image microPhoneImage; private void Start() { #if UNITY_ANDROID if (!Permission.HasUserAuthorizedPermission(Permission.Microphone)) { Debug.Log("Request"); Permission.RequestUserPermission(Permission.Microphone); } #endif } private void Update() { if (Input.touchCount > 0) { Touch touch = Input.touches[0]; if (touch.phase == TouchPhase.Began) { StartSpeech(); } } } /// <summary> /// 認識開始 /// </summary> private void StartSpeech() { #if UNITY_ANDROID var nativeRecognizer = new AndroidJavaClass("com.kento.speechtest.Speech"); var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); var context = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); context.Call("runOnUiThread", new AndroidJavaRunnable(() => { nativeRecognizer.CallStatic("StartRecognizer", context,gameObject.name, "CallbackMethod"); })); #endif } /// <summary> /// 音声認識後のコールバックとして実行するメソッド /// </summary> /// <param name="message">認識したメッセージ</param> private void CallbackMethod(string message) { var messages = message.Split('\n'); //ユーザーが話すのを開始した際のコールバック if (messages[0] == "onBeginningOfSpeech") { microPhoneImage.enabled = true; } //認識した音量変化のコールバック if (messages[0] == "onRmsChanged") { recText.text = "認識中..."; } //ユーザーが話すのを終了した際のコールバック if (messages[0] == "onEndOfSpeech") { microPhoneImage.enabled = false; } //認識結果の準備が完了したコールバック if (messages[0] == "onResults") { var msg = ""; for (var i = 1; i < messages.Length; i++) { msg += messages[i] + "\n"; } Debug.Log(msg); recText.text = msg; } } } デモ 音声が無いのでアレですが、無事動作しました。 VRで検証 結果から言うと動きませんでした。 adb logcat -s Unity:*とコマンドプロンプトに入力することで 動作中のUnity製Androidアプリのログを出力できます。(教えてくださった方ありがとうございます!) その方法で実行中のVRアプリのログを確認しましたが、特にエラーを吐くことも無くただただ動いていませんでした。 同じ検証で四苦八苦している先駆者がOculusの公式コミュティに質問を記していました。 (そして、それらしい回答もなく終了していました) 【引用元】:On-device Speech Recognition on the Quest with Unity 冒頭の翻訳VRは下記リンクの手法で実現しました。 【参考リンク】:【Unity(C#)】Watson API × OculusQuestで音声認識 【参考リンク】:【Unity(C#)】Microsoft Translatorの使い方 ちなみに、海外ユーザーは音声入力や音声コマンドが利用可能なようです。 音声コマンドは「ヘイ、フェイスブック!」ってやつです。 【参考リンク】:音声コマンド・音声入力 そのうち、日本語にも対応して開発者に公開されるのを期待します。 2021/04/08 追記 下記アセットを使えばオフラインの音声認識も可能なようです。 【Asset】:Android Speech TTS ただし、日本語はまだ対応していません。 英語での認識についてデモAPKを落としてきて試しましたところなかなか良い精度でした。 通常のネイティブの音声認識機能ではなく、下記ライブラリを使用しているようです。 Kaldi Speech Recognition Toolkit (教えてくださった方、感謝です!) おわりに 今回の検証結果はOculusQuestでAndroidネイティブの音声認識機能は呼び出せないとなりました。 もし成功した方がいらっしゃったら遠慮なくツッコんでください。(あわよくば方法知りたい)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む