20210428のUnityに関する記事は9件です。

【Unity3D】Rayを使って壁越しにプレイヤーを検知しない敵を作ってみる

はじめに Unityの有料アセットであるBehavior Designer でプレイヤーを検知する敵を作っていましたが、ジャンプしている間は検知してくれなかったので、壁がないときにのみプレイヤーを検知する処理を勉強も兼ねて作ってみました。 ※Unityのバージョンは2019.4.18f1を使用しています。 Ray について Unityの機能の中にRayというものがあります。 これは、指定した位置と方向から光線を飛ばす機能で、光線に当たったオブジェクトの情報を取得したり衝突判定を行うことができます。Rayの当たり判定はRaycastという関数で調べることができ、RaycastHitという構造体にRayと接触したオブジェクトの情報が格納されます。 実装の手順 プレイヤーの座標の取得 敵の位置からプレイヤーの位置へRayを飛ばす 最初にRayが接触したオブジェクトを調べる という手順で進めていきます。 プレイヤーの座標の取得 まず、プレイヤーの座標を取得するために、OnTriggerStay()でコライダーと接触したオブジェクトを取得します。その後、コライダーからタグを調べて、"Player"という名前のタグがついていれば、そのオブジェクトの座標をプレイヤーの座標として利用します。 プレイヤーの座標を取得する他のやり方としては、Find()でプレイヤーのオブジェクトを見つけたり、public変数などでインスペクターにオブジェクトを直接入れる方法でも良いと思います。 敵の位置からプレイヤーの位置へRayを飛ばす Rayを飛ばす位置については敵の視点となる位置(transform.position)を指定するだけです。方向を決めるためには、Rayを飛ばす先(プレイヤーの座標)から、Rayを飛ばす元(敵の座標)を引いて正規化する必要があります(参考:ひとつのオブジェクトから別のオブジェクトへの向きと距離)。 Rayを飛ばす位置と方向が決まったらnewで新しいRayを作成します。 最初にRayが接触したオブジェクトを調べる Raycastを使う方法とRaycastAllを使う方法があります。 Raycastを使う方法 Raycastは、「Rayがオブジェクトに当たったかどうか」というbool値を返します。また、Rayがオブジェクトに当たった場合は、out修飾子を用いることでRayが当たったオブジェクト(RaycastHit)を取得することができます。複数のオブジェクトにRayが当たった場合は、RaycastHitには最初に当たったオブジェクトが格納されます。 よって、RaycastHitに入ったオブジェクトを調べ、それがプレイヤーオブジェクトだった場合は、敵とプレイヤーとの間に物体がないということになるので「プレイヤーを見つけた」と判断します。 RaycastAllを使う方法 Raycastが「Rayがオブジェクトに当たったかどうか」のbool値を返すのに対して、RaycastAllは「Ray がヒットしたオブジェクト(RaycastHit)全てのリスト」を返す関数です。そこでLINQのFirst()メソッドを使ってRaycastAllの最初の要素を調べ、それがプレイヤーだった場合に「プレイヤーを発見した」という判定を行うようにすると、壁がないときにのみプレイヤーを検知するようになります。 ソースコード Raycastを使う方法で記述しています。RaycastAllを使う方法も後述しています。 using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyView : MonoBehaviour { Ray ray; RaycastHit hit; Vector3 direction; // Rayを飛ばす方向 float distance = 10; // Rayを飛ばす距離 private void OnTriggerStay(Collider other) { if (other.CompareTag("Player")) { // Rayを飛ばす方向を計算 Vector3 temp = other.transform.position - transform.position; direction = temp.normalized; ray = new Ray(transform.position, direction); // Rayを飛ばす Debug.DrawRay(ray.origin, ray.direction * distance, Color.red); // Rayをシーン上に描画 // Rayが最初に当たった物体を調べる if (Physics.Raycast(ray.origin, ray.direction * distance, out hit)) { if (hit.collider.CompareTag("Player")) { Debug.Log("プレイヤー発見"); } else { Debug.Log("プレイヤーとの間に壁がある"); } } } } } RayCastAllを使う場合 基本的には上記のスクリプトと同じなので、変更点だけを記載します。 LINQを使うためのusingディレクティブ using System.Linq; を先頭に書いておき、OnTriggerStayの中の if (Physics.Raycast(ray.origin, ray.direction * distance, out hit)) を消して hit = Physics.RaycastAll(ray).First(); を書くと同じように動作します。 プロジェクトの設定 簡単なプロジェクトを作って動作確認をしました。 床をPlane, 壁(青い直方体)と敵(緑の立方体)をCube, プレイヤー(赤いカプセル)をCapsuleで作成しました。 また、Rayを飛ばす際にプレイヤーより先に床や敵自身のオブジェクトにRayが当たると正しく判定されないことがあるので、これら二つのオブジェクトのLayerを"Ignore Raycast"に変更しました。LayerMaskの設定は、デフォルトでは"Ignore Raycast"に指定されたものをRayの接触判定の対象外とします。Raycast内でLayerMaskを指定する方法もあるようです。 プレイヤーオブジェクトの設定 プレイヤーオブジェクトは、タグを"Player"としておき、子要素にMainCameraを持たせます。また、矢印キーで移動できるようにスクリプトも書いてアタッチしておきます。 参考までにプレイヤーのスクリプトも載せておきます。 using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { [SerializeField] private float speed = 0.1f; void Update() { if (Input.GetKey(KeyCode.UpArrow)) { transform.position += Vector3.forward * speed; } if (Input.GetKey(KeyCode.LeftArrow)) { transform.position += Vector3.left * speed; } if (Input.GetKey(KeyCode.DownArrow)) { transform.position += Vector3.back * speed; } if (Input.GetKey(KeyCode.RightArrow)) { transform.position += Vector3.right * speed; } } } 敵オブジェクトの設定 敵オブジェクトは、子要素に空のゲームオブジェクトを持たせて、そこに視界の範囲となるコライダーと、EnemyViewスクリプト(上記のスクリプト)をアタッチします。 コライダーは3Dで使えるものであれば何でもよいと思いますが、今回は敵の視界を表すので円錐のような形のコライダーを使いたいと思い、コーンコライダーというアセットをお借りしました。使い方はこちらの記事などで紹介されています。 動作確認 左がシーンで右がゲーム画面です。 プレイヤーがコライダー内に入ったときに、壁があるときは壁との接触を、壁がないときはプレイヤーとの接触を取れていることが確認できました。 おわりに 今回は、Rayを使って壁越しにプレイヤーを検知しない方法を書いてみました。 記事の作成自体初めてで、読みづらかったり分かりにくい部分もあったかもしれません。質問等ございましたらコメントの方でお願いします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UNITYの鏡面反射を使ってみる

はじめに UNITYで風景的なものを作っているのですが、鏡面反射というものがあるのを知ったので使ってみました 使用した環境 パソコン:Acer AS5750 Core(R) i3 2310M メモリ8GB Win10 UNITY:2018.4.34f1 準備 ↓元となる風景は下記のような住宅地で、カーブミラーに鏡面効果を設定してみます (赤マルで囲った部分がカーブミラーです) 作業手順 ↓現在のカーブミラーのマテリアルは、Metallic:0.76、Smoothness:0.68というアルミニウムっぽい設定にしてありますが、何も反射していません ↓ミラー部分のマテリアルを、Metallic:1、Smoothness:1に変更し、[Reflections]をチェックしておきます ↓これでミラーが光沢のある金属面になります さらに、ヒエラルキーのミラーのオブジェクトの場所で右クリックし、[Light]-[Reflection Probe]を選択し、反射させるための機能を追加します ↓現在[Baked]になっている[Type]を、それぞれ下記の画像のように変更します つづいて[Box Projection]をチェックし、[Box Size]を調整します 私の場合、X、Y、Zの値を、それぞれ[10、10、10]から[1、2、1.2]に変更するといい感じになりました [Resolution]も、128から512に変更します 確認してみます ↓[Game]タブで確認してみます ↓丁字路のカーブミラーも同様の修正でこんな感じです プレファブに書き戻し ↓画面左下のカーブミラーだけ鏡面効果を設定したので、右上の赤マルで囲ったカーブミラーはまだ何も反射していません インスペクタのプレファブから、[Overrides]-[Apply All]を実行して、プレファブを更新し、他のオブジェクトにも同じ効果を設定します [Apply All]は影響範囲が広いので、十分確認してから実行してください ↓右上のミラーにも反映されました! さいごに 第二世代のCore i3では、さすがにUNITYは重い印象です クロックが高いのがいいのか?、コア数が多いのがいいのか?、それともGPUの性能が高いものを選ぶべきか? どれが一番効果的なんでしょう
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HoloLens2 QRコード読み取りのやり方

Microsoft.MixedReality.QRを使用したQRCodeの読み取り#MRTK #HoloLens2 pic.twitter.com/ZzVaJp1j7S— 原口昂弥 (@k_haraguchi55) April 28, 2021 開発環境 HoloLens2 Windows 10 pc Unity 2019.4.1f1 MRTK ver2.5.3 やり方 QRCodeReader.cs using UnityEngine; using Microsoft.MixedReality.QR; using UnityEngine.UI; public class QRCodeReader : MonoBehaviour { [SerializeField] Text text = null; QRCodeWatcher qrCodeWatcher; // Start is called before the first frame update async void Start() { Debug.Log(QRCodeWatcher.IsSupported()); text.text = QRCodeWatcher.IsSupported().ToString(); if (QRCodeWatcher.IsSupported()) //サポートされているか確かめる。 { await QRCodeWatcher.RequestAccessAsync(); //アクセス許可を取る。 qrCodeWatcher = new QRCodeWatcher(); qrCodeWatcher.Added += AddedQRCode; //QRCodeを発見した時の処理を追加。 qrCodeWatcher.Start(); //スキャンを開始。 } } // QRCodeを発見した時の処理。 private void AddedQRCode(object sender, QRCodeAddedEventArgs e) { text.text = e.Code.Data; } // スキャンを止める。 public void Stop() { qrCodeWatcher.Stop(); //スキャンを停止 qrCodeWatcher.Added -= AddedQRCode; //QRCodeを発見した時の処理を削除 } } ※ QRCodeWatcher.Addedに追加できるデリゲートの型は void(object,QRCodeAddedEventArgs)のみ。 上のスクリプトをプロジェクトに追加し、適当なオブジェクトに追加。 textプロパティを設定してビルド、実機で実行。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity Editor拡張] File IDの取得

File IDとは? UnityのアセットはGuidで管理されています。SceneやPrefab内(Hierarchy上)ではFile IDで管理されています。 samle.unity --- !u!4 &1781688880 Transform: m_GameObject: {fileID: 1781688879} 2019.2以降でのFile IDの取得 GlobalObjectIdを使うと楽です。もちろんエディタ上でしか動作しません。 UnityEngine.Object targetObject = Selection.activeObject; // GlobalObjectIdに変換 var id = GlobalObjectId.GetGlobalObjectIdSlow(targetObject); // File ID id.targetObjectId // PrefabならInstance IDが入る Prefabで無ければ0 id.targetPrefabId // GUID Prefabなら参照元(親)のGuidがIDが入る id.assetGUID // アセットの種別 0 = Null, 1 = Imported Asset, 2 = Scene Object, 3 = Source Asset id.identifierType シリアライズ、デシリアライズ シリアライズ ToString()がオーバーライドされていてGlobalObjectIdを文字列にしてくれるので便利。Editor拡張に優しいですね。 下記のようなフォーマットで出力されます。 GlobalObjectId_V1-{identifierType}-{assetGUID}-{targetObjectId}-{targetPrefabId} デフォルト GlobalObjectId_V1-0-00000000000000000000000000000000-0-0 var id = GlobalObjectId.GetGlobalObjectIdSlow(targetObject); var idString = id.ToString(); Debug.Log(idString); // [Console] GlobalObjectId_V1-x-x-x-x デシリアライズ 上記で言うidStringをTryParseにそのまま突っ込むだけでOK。便利 if (GlobalObjectId.TryParse(idString, out GlobalObjectId result)) { switch (result.identifierType) { // プロジェクト内のアセッは簡単 case 1: var obj = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(result); Debug.Log(obj.name); break; // シーン上のアセットは取得が面倒だし重い case 2 : // 多分、シーンが開いていないと取得できません。 // 1. シーン上のすべてのgameObjectをGlobalObjectIdに変換 var sceneObjects = GameObject.FindObjectsOfType<GameObject>(); var sceneObjectIds = new GlobalObjectId[sceneObjects.Length]; GlobalObjectId.GetGlobalObjectIdsSlow(sceneObjects, sceneObjectIds); // 2. 一致するものを探す for (var i = 0; i < sceneObjectIds.Length; i++) { if (sceneObjectIds[i].Equals(result)) { Debug.Log(sceneObjects[i].name); break; } } break; } } 2019.2未満でのFile IDの取得 取得できるだけありがたいですが、触れてはいけない部分から取得してる気がして若干怖いです。 m_LocalIdentfierInFileがスペルミスしてるので気をつけてください。 var inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance); var serializedObject = new SerializedObject(Selection.activeObject); inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null); var localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile"); //File ID Debug.Log(localIdProp.intValue); 参考 How to get the Local Identifier In File for scene objects - Unity Foru
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity] File IDの取得

File IDとは? UnityのアセットはGuidで管理されているのはご存知だと思いますが、SceneやPrefabなどHierarchy上はFile IDで管理されています。 samle.unity --- !u!4 &1781688880 Transform: m_GameObject: {fileID: 1781688879} 2019.2以降でのFile IDの取得 GlobalObjectIdを使うと楽です。もちろんエディタ上でしか動作しません。 UnityEngine.Object targetObject = Selection.activeObject; // GlobalObjectIdに変換 var id = GlobalObjectId.GetGlobalObjectIdSlow(targetObject); // File ID id.targetObjectId // PrefabならInstance IDが入る Prefabで無ければ0 id.targetPrefabId // GUID Prefabなら参照元(親)のGuidがIDが入る id.assetGUID // アセットの種別 0 = Null, 1 = Imported Asset, 2 = Scene Object, 3 = Source Asset id.identifierType シリアライズ、デシリアライズ シリアライズ ToString()がオーバーライドされていてGlobalObjectIdを文字列にしてくれるので便利。Editor拡張に優しいですね。 下記のようなフォーマットで出力されます。 GlobalObjectId_V1-{identifierType}-{assetGUID}-{targetObjectId}-{targetPrefabId} デフォルト GlobalObjectId_V1-0-00000000000000000000000000000000-0-0 var id = GlobalObjectId.GetGlobalObjectIdSlow(targetObject); var idString = id.ToString(); Debug.Log(idString); // [Console] GlobalObjectId_V1-x-x-x-x デシリアライズ 上記で言うidStringをTryParseにそのまま突っ込むだけでOK。便利 if (GlobalObjectId.TryParse(idString, out GlobalObjectId result)) { switch (result.identifierType) { // プロジェクト内のアセッは簡単 case 1: var obj = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(result); Debug.Log(obj.name); break; // シーン上のアセットは取得が面倒だし重い case 2 : // 多分、シーンが開いていないと取得できません。 // 1. シーン上のすべてのgameObjectをGlobalObjectIdに変換 var sceneObjects = GameObject.FindObjectsOfType<GameObject>(); var sceneObjectIds = new GlobalObjectId[sceneObjects.Length]; GlobalObjectId.GetGlobalObjectIdsSlow(sceneObjects, sceneObjectIds); // 2. 一致するものを探す for (var i = 0; i < sceneObjectIds.Length; i++) { if (sceneObjectIds[i].Equals(result)) { Debug.Log(sceneObjects[i].name); break; } } break; } } 2019.2未満でのFile IDの取得 取得できるだけありがたいですが、触れてはいけない部分から取得してる気がして若干怖いです。 m_LocalIdentfierInFileがスペルミスしてるので気をつけてください。 var inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance); var serializedObject = new SerializedObject(Selection.activeObject); inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null); var localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile"); //File ID Debug.Log(localIdProp.intValue); 参考 How to get the Local Identifier In File for scene objects - Unity Foru
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity] AddressableAssetSystemの同期読み込み(Synchronous Addressables API)を試す

Uintyブログを見ているとAddressableAssetSystemにしれっと同期読み込みが追加されていることに気付く。 https://blogs.unity3d.com/jp/2021/04/14/find-out-whats-new-for-the-addressable-asset-system/ 試してみることにした。 環境 Unity2019.4.22f1 Addressables 1.17.17 Addressableのインストール いつもどおりPackageManagerから 環境の準備 今回はCubeのPrefabをAddressableで同期読み込みしてみる。 PrefabをクリックしAddressableにチェックを入れ、アドレスをいい感じに設定する Cubeという名前にした Groupウィンドウにも登録されているのを一応確認しておく 読み込み処理を書いてみる 早速読み込みのコードを書いてみる AddressableTest.cs using UnityEngine; using UnityEngine.AddressableAssets; /// <summary> /// Addressableのテストクラス /// </summary> public class AddressableTest : MonoBehaviour { private void Update() { if (Input.GetKeyDown(KeyCode.A)) { var cube_prefab = Addressables.LoadAssetAsync<GameObject>("Cube").WaitForCompletion(); if (cube_prefab == null) return; Instantiate(cube_prefab, Vector3.zero, Quaternion.identity); } } } .WaitForCompletion() をつけてやると読み込み完了まで同期で待ってくれる。 このスクリプトをMainCameraにでもくっつけて実行してみる。 Aキーを押したらPrefabがInstantiateされた。動いてそうである。 AssetReferenceにしてみる 文字列でのアドレス指定ではなくAssetReferenceでも読み込めるか一応確認してみる AddressableTest.cs using UnityEngine; using UnityEngine.AddressableAssets; /// <summary> /// Addressableのテストクラス /// </summary> public class AddressableTest : MonoBehaviour { [SerializeField] private AssetReference cubeAssetReference = null; private void Update() { if (Input.GetKeyDown(KeyCode.A)) { var cube_prefab = Addressables.LoadAssetAsync<GameObject>(cubeAssetReference).WaitForCompletion(); if (cube_prefab == null) return; Instantiate(cube_prefab, Vector3.zero, Quaternion.identity); } } } InspectorからCubeを指定し読み込ませてみる 同様に動作した。特に今までのAddressableの使い方を変えずに対応できそうだ ローカルに無いDLが必要なアセットを同期読み込みしてみる ユーザー体験的には絶対やっちゃ駄目なのだが、DLが発生する場合のリソース読み込みを同期でできるのか、試してみた。 Downloadというグループを作りそこにCubeを移動させる そしてBuildPathをRemoteBuildPath,LoadPathをRemoteLoadPathにする AWSのS3にバケットを作成し、publicな状態でファイルをアップロードできるようにしておく(検証用なので雑設定) AddressableのProfileのRemoteLoadPathをS3のファイルDLURLにしておく そしてAssetBundleをビルドする プロジェクト直下のServerDataフォルダにプラットフォームフォルダとアセットバンドルが生成される このプラットフォームフォルダごとS3にアップロードする 最後にEditorで実行した際に実際のAssetBundleを読みに行くように設定を変更する 先程のコードのままこれで実行してみる Aキーを押したところ1秒ほど立ってから表示された(画像じゃわからんね) DLされてそうだ 一度実行するとキャッシュされちゃうのでキャッシュ削除処理をStartに追加して何度か試してみる AddressableTest.cs private void Start() { Addressables.ClearDependencyCacheAsync("Cube"); } 押す度に時間がかかるようになってるので再DLされてそうだ。 最後にS3からデータを消して落とせなくしてみる バッチリ例外が出まくってる。これで今まで確実にDLしてたのが明らかになった。 DLする必要があってもちゃんと同期読み込みが可能であった。 UX的には不親切極まりないので非推奨だが覚えておいて損は無さそうだ。 まとめ Addressableは出た当初、非同期読み込みが一切できないという事が発覚しフォーラムが大変盛り上がっていたがUnity側も理解してくれてちゃんと同期APIが提供されたのは嬉しい限り。 起動時に設定ファイルを読み込む、みたいなユースケースだと非同期だと気にする範囲が多く、どうしても使いにくさを感じていたがこれにより解消された感がある。 今回のアップデートでAddressableがいよいよ実用的になったと感じる。 Resources.Loadをプロジェクトから完全に撲滅できるという人も多そうである。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity(C#)】Google Cloud Speech-to-TextをUnityで使用できるGoogle Cloud Speech Recognitionの使い方

はじめに UnityからGoogle Cloud Speech-to-Textを使用する方法をメモします。 OculusQuestでも問題なく動作しました。 Google Cloud Speech-to-Text Googleの提供する音声認識APIです。 下記リンクより登録に進みAPIキーを取得します。 【参考リンク】:Speech-to-Text 登録後、下記ダッシュボードの画面からAPIキーを取得可能です。 料金は従量課金制ですが、1月当り60分までは無料で使えるようです。(精度の検証でしゃべりまくってたら42円請求されてしまいました。) こちらのAPIを使うには少し複雑で、ただ、APIをUnityから叩けばよいという訳ではありません。 かといっていろいろと面倒なことを自前で実装するのも億劫なので、 今回はアセットを使いました。 下記のページでも紹介されている、Google Cloud Speech Recognitionを使用しました。 【参考リンク】:【Unity】自分の声をテキスト化する方法【Google Cloud Speech Recognition 】 バージョン 念のため使ったライブラリ等のバージョンも書いときます。 Unity 2019.4.8f1 UniTask.2.2.4 UniRx 7.1.0 Google Cloud Speech Recognition 4.1.2 準備 アセットをプロジェクトにインポートしたら任意のシーンのヒエラルキーに 適当なオブジェクトを作って下記のように設定します。APIキーは先ほど取得したものです。 GoogleSpeechTestは後述のサンプルコードです。 コード Unityから使用するサンプルです。 using FrostweepGames.Plugins.GoogleCloud.SpeechRecognition; using UniRx; using UniRx.Triggers; using UnityEngine; using UnityEngine.UI; /// <summary> /// Google音声認識テスト /// </summary> public class GoogleSpeechTest : MonoBehaviour { [SerializeField] private Button recButton; [SerializeField] Text resultText; private GCSpeechRecognition _speechRecognition; void Start() { _speechRecognition = GCSpeechRecognition.Instance; _speechRecognition.FinishedRecordEvent += OnFinishedRecordEvent; _speechRecognition.RecognizeSuccessEvent += OnRecognizeSuccessEvent; if (_speechRecognition.HasConnectedMicrophoneDevices()) { _speechRecognition.SetMicrophoneDevice(_speechRecognition.GetMicrophoneDevices()[0]); } recButton.OnPointerDownAsObservable() .Subscribe(_ => _speechRecognition.StartRecord(false)).AddTo(this); recButton.OnPointerUpAsObservable() .Subscribe(_ => _speechRecognition.StopRecord()).AddTo(this); } private void OnDestroy() { _speechRecognition.FinishedRecordEvent -= OnFinishedRecordEvent; _speechRecognition.RecognizeSuccessEvent -= OnRecognizeSuccessEvent; } /// <summary> /// 音声認識成功時のコールバックイベント /// </summary> /// <param name="recognitionResponse">認識結果のレスポンス</param> private void OnRecognizeSuccessEvent(RecognitionResponse recognitionResponse) { string r = ""; foreach (var result in recognitionResponse.results) { foreach (var alternative in result.alternatives) { if (recognitionResponse.results[0].alternatives[0] != alternative) { r = alternative.transcript; } } } resultText.text = r; } /// <summary> /// 録音終了時のコールバックイベント /// </summary> /// <param name="clip">音声クリップ</param> /// <param name="raw">生データ</param> private void OnFinishedRecordEvent(AudioClip clip, float[] raw) { if (clip == null) return; RecognitionConfig config = RecognitionConfig.GetDefault(); config.languageCode = Enumerators.LanguageCode.ja_JP.Parse(); config.audioChannelCount = clip.channels; GeneralRecognitionRequest recognitionRequest = new GeneralRecognitionRequest() { audio = new RecognitionAudioContent() { content = raw.ToBase64() }, config = config }; _speechRecognition.Recognize(recognitionRequest); } } デモ 下記のように動作します。若干レスポンスが遅いです。送信するAudioデータの容量に比例して遅くなる?ようです。 pic.twitter.com/6bjyZGlG6y— KENTO⚽️XRエンジニア?Shader100記事マラソン挑戦中30/100 (@okprogramming) April 24, 2021 おわりに 音声データをストリームしながらリアルタイムでしゃべった言葉を認識するような形式を取れば サクサク動くのかもしれません。 何やら複雑なことをやってそれを成し遂げている海外の方がいらっしゃいました。(料金ヤバそう) 【参考リンク】:Streaming recognition 【参考リンク】:[Announce] Google Cloud Streaming Speech Recognition [VR\AR\Desktop]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity(C#)】DeepL Translatorの使い方

はじめに UnityからDeepL Translatorを使用する方法をメモします。 DeepL Translator DeepLの提供する翻訳WebAPIです。 下記リンクより登録に進みAPIキーを取得します。 【参考リンク】:DeepL Pro 登録後、下記ダッシュボードの画面からAPIキーを取得可能です。 料金は従量課金制ですが、1月当り500,000文字までは無料で使えるようです。(GoogleTranslationと一緒でした) バージョン 念のため使ったライブラリ等のバージョンも書いときます。 Unity 2019.4.8f1 UniTask.2.2.4 UniRx 7.1.0 コード Unityから使用するサンプルです。 GIFにおいては使用しているAPIは異なりますが、下記と同様に動作します。 【参考リンク】:【Unity(C#)】Microsoft Translatorの使い方 適当なオブジェクトにアタッチ using System; using System.Linq; using System.Threading; using Cysharp.Threading.Tasks; using UniRx; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; /// <summary> /// DeepLの最小構成サンプル /// </summary> public class DeepLTest : MonoBehaviour { [SerializeField] private Dropdown fromLanguageDd; [SerializeField] private Dropdown toLanguageDd; [SerializeField] private Button translateButton; [SerializeField] private InputField inputField; [SerializeField] private Text translationText; private const string API_KEY = "APIキー"; private const string ENDPOINT = "https://api-free.deepl.com/v2/translate?"; /// <summary> /// レスポンスを格納する構造体 /// </summary> [Serializable] public struct TranslateData { public Translations[] translations; [Serializable] public struct Translations { public string detected_source_language; public string text; } } private void Start() { var token = this.GetCancellationTokenOnDestroy(); //ドロップダウンメニュー作成 var languages = Enum.GetNames(typeof(Language)); fromLanguageDd.ClearOptions(); fromLanguageDd.AddOptions(languages.ToList()); toLanguageDd.ClearOptions(); toLanguageDd.AddOptions(languages.ToList()); fromLanguageDd.value = (int) fromLanguage; toLanguageDd.value = (int) toLanguage; //翻訳元言語 fromLanguageDd.OnValueChangedAsObservable() .Subscribe(value => { fromLanguage = (Language) value; }) .AddTo(this); //翻訳後言語 toLanguageDd.OnValueChangedAsObservable() .Subscribe(value => { toLanguage = (Language) value; }) .AddTo(this); //翻訳ボタン押下 translateButton.OnClickAsObservable() .Subscribe(async _ => { //結果が送られてくるまで待ってから表示 var result = GetTranslation(fromLanguage, toLanguage, inputField.text, token); translationText.text = await result; }) .AddTo(this); } /// <summary> /// 設定言語 /// </summary> private enum Language { JA, EN } private Language fromLanguage = Language.EN; private Language toLanguage = Language.JA; /// <summary> /// 翻訳結果を返す /// </summary> /// <param name="from">翻訳前の言語設定</param> /// <param name="to">翻訳語の言語設定</param> /// <param name="speechText">翻訳したい文字列</param> /// <param name="ct">CancellationToken</param> /// <returns>翻訳結果</returns> private async UniTask<string> GetTranslation(Language from, Language to, string speechText, CancellationToken ct) { //POSTメソッドのリクエストを作成 var requestInfo = ENDPOINT + API_KEY; requestInfo += $"&text={speechText}&source_lang={from}&target_lang={to}"; var request = UnityWebRequest.Post(requestInfo, "Post"); //結果受け取り var second = TimeSpan.FromSeconds(3); var result = await request.SendWebRequest().ToUniTask(cancellationToken: ct).Timeout(second); var json = result.downloadHandler.text; Debug.Log(json); var data = JsonUtility.FromJson<TranslateData>(json); return data.translations[0].text; } } リクエストパラーメーターとして渡す言語情報の文字列は下記に載っています。 【参考リンク】:Translating text おわりに いろいろな翻訳API使ってみての感想ですが、GoogleもMSも申し分なく精度が高いですが、DeepLはやっぱり一番精度が高いなと感じました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity(C#)】Google Cloud Translationの使い方

はじめに UnityからGoogle Cloud Translationを使用する方法をメモします。 Google Cloud Translation Googleの提供する翻訳WebAPIです。 下記リンクより登録に進みAPIキーを取得します。 【参考リンク】:Translation 登録後、下記ダッシュボードの画面からAPIキーを取得可能です。 料金は従量課金制ですが、1月当り500,000文字までは無料で使えるようです。 バージョン 念のため使ったライブラリ等のバージョンも書いときます。 Unity 2019.4.8f1 UniTask.2.2.4 UniRx 7.1.0 コード Unityから使用するサンプルです。 GIFにおいては使用しているAPIは異なりますが、下記と同様に動作します。 【参考リンク】:【Unity(C#)】Microsoft Translatorの使い方 適当なオブジェクトにアタッチ using System; using System.Linq; using System.Threading; using Cysharp.Threading.Tasks; using UniRx; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; /// <summary> /// GoogleTranslationの最小構成サンプル /// </summary> public class GoogleTranslationTest : MonoBehaviour { [SerializeField] private Dropdown fromLanguageDd; [SerializeField] private Dropdown toLanguageDd; [SerializeField] private Button translateButton; [SerializeField] private InputField inputField; [SerializeField] private Text translationText; private const string API_KEY = "APIキー"; private const string ENDPOINT = "https://translation.googleapis.com/language/translate/v2?"; /// <summary> /// レスポンスを格納する構造体 /// </summary> [Serializable] public struct TranslateData { public Data data; [Serializable] public struct Data { public Translations[] translations; [Serializable] public struct Translations { public string translatedText; public string detectedSourceLanguage; } } } private void Start() { var token = this.GetCancellationTokenOnDestroy(); //ドロップダウンメニュー作成 var languages = Enum.GetNames(typeof(Language)); fromLanguageDd.ClearOptions(); fromLanguageDd.AddOptions(languages.ToList()); toLanguageDd.ClearOptions(); toLanguageDd.AddOptions(languages.ToList()); fromLanguageDd.value = (int) fromLanguage; toLanguageDd.value = (int) toLanguage; //翻訳元言語 fromLanguageDd.OnValueChangedAsObservable() .Subscribe(value => { fromLanguage = (Language) value; }) .AddTo(this); //翻訳後言語 toLanguageDd.OnValueChangedAsObservable() .Subscribe(value => { toLanguage = (Language) value; }) .AddTo(this); //翻訳ボタン押下 translateButton.OnClickAsObservable() .Subscribe(async _ => { //結果が送られてくるまで待ってから表示 var result = GetTranslation(fromLanguage, toLanguage, inputField.text, token); translationText.text = await result; }) .AddTo(this); } /// <summary> /// 設定言語 /// </summary> private enum Language { ja, en } private Language fromLanguage = Language.en; private Language toLanguage = Language.ja; /// <summary> /// 翻訳結果を返す /// </summary> /// <param name="from">翻訳前の言語設定</param> /// <param name="to">翻訳語の言語設定</param> /// <param name="speechText">翻訳したい文字列</param> /// <param name="ct">CancellationToken</param> /// <returns>翻訳結果</returns> private async UniTask<string> GetTranslation(Language from, Language to, string speechText, CancellationToken ct) { //POSTメソッドのリクエストを作成 var requestInfo = ENDPOINT; requestInfo += $"key={API_KEY}&q={speechText}&detectedSourceLanguage={from}&target={to}"; var request = UnityWebRequest.Post(requestInfo, "Post"); //結果受け取り var second = TimeSpan.FromSeconds(3); var result = await request.SendWebRequest().ToUniTask(cancellationToken: ct).Timeout(second); var json = result.downloadHandler.text; Debug.Log(json); var jsonData = JsonUtility.FromJson<TranslateData>(json); return jsonData.data.translations[0].translatedText; } } リクエストパラーメーターとして渡す言語情報の文字列は下記に載っています。 【参考リンク】:言語サポート おわりに DeepLも試したのでまとめます。 試しました→【Unity(C#)】DeepL Translatorの使い方
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む