20210403のUnityに関する記事は4件です。

UnityでGif動画を撮影したい

概要 Unity上でGif動画を読み込む方法はいくつかありますが、Gif動画を撮影するとなるとあまり情報が出てきません。 今回は「UnityでGif動画を撮影する方法」を紹介します。 紹介するライブラリ - Moments Moments カメラにコンポーネントをアタッチして、Record()を呼び出すだけでGif動画の作成および書き出しを実行してくれるライブラリです。 Zlibライセンスです。 使い方 1. カメラに Moments Recorder をアタッチする カメラにMoments Recorderコンポーネントをアタッチします。 インスペクタから録画するGif動画の設定を行うことができます。 (解像度やフレームレート、圧縮の設定ができる) なお、 Record Timeの値は「最大で録画できる時間(秒数)」を表しています。 ここで設定した時間を超えて録画することはできないので、実際に録画する秒数より少し長めにしておくとよいでしょう。 2. スクリプトから録画処理を呼び出す ちょっとAPIにクセがあるので注意です。 Recorder.StateがRecorderState.PreProcessing(前の録画データの書き出し準備中)だったらいったん待つ Recorder.Record()を呼び出して録画を開始する 任意の秒数自分で待つ Recorder.Pause()を呼び出して録画を完了する Recorder.Save()を呼び出してファイルに書き出す(RecorderState.PreProcessingステートになる) 書き出しが完了する using System.Collections; using Moments; using UnityEngine; public class RecordSample : MonoBehaviour { [SerializeField] private Recorder _recorder; private void Start() { // 1回録画した後に、次の録画準備が整ったことを伝えるコールバック _recorder.OnPreProcessingDone += () => { Debug.Log("録画準備が完了しました"); }; // ファイルの書き出しが完了したコールバック _recorder.OnFileSaved += (i, s) => { Debug.Log($"{s} に保存しました"); }; StartCoroutine(RecordeCoroutine()); } IEnumerator RecordeCoroutine() { _recorder.SaveFolder = Application.dataPath; // 録画準備が整うまで待つ yield return new WaitWhile(() => _recorder.State == RecorderState.PreProcessing); // 録画開始 _recorder.Record(); // 2秒間録画する yield return new WaitForSeconds(2.0f); // 録画停止 _recorder.Pause(); // 保存 _recorder.Save(filename: "RecordedFile"); } } 3. Gifファイルができあがる Moments、すごい。けどちょっと物足りない。 たったこれだけでGif動画が記録できるので、すごい便利です。 ファイル書き出しも別スレッドで実行してくれます。 こんなすごいMomentsですが、ちょっと足りない部分があります。 それはAPIが同期しかないところです。 UnityGifRecorder - Momentsをラップして使いやすくしたライブラリ UnityGifRecorder ということで、Momentsをラップする形で非同期APIを提供するライブラリを作ってみました。 (といっても本当に数行APIをラップしただけなので、こんな大層な名前つけるほどでも無いんですが…。ライセンスもいっちょ前にMITライセンスですが、正直中身の9割9分はMomentsそのまんまです) UniTaskに依存しているのでこちらとセットで導入してください。 使い方 基本はMomentsRecorderと同じです。 というか中身はMomentsRecorderそのもので、それをUnityGifRecorderが薄くラップしてるだけです。 違いとしては録画と書き出しが非同期APIになっているところです。 public class RecordSample : MonoBehaviour { // MomentsRecorder と UnityGifRecorder をセットでカメラに貼り付けてね [SerializeField] private UnityGifRecorder _recorder; private async UniTaskVoid Start() { var ct = this.GetCancellationTokenOnDestroy(); // 録画パス指定 _recorder.SaveFolder = Path.Combine(Application.dataPath, "TORISOUP", "UnityGifRecorder", "Demo", "output"); // 指定秒数、録画する await _recorder.RecordAsync(seconds: 2.0f, DelayType.DeltaTime, token: ct); // ファイルに書き出す await _recorder.SaveAsync(fileName: "TestGifRecord"); } } まとめ Momentsを使えば簡単にUnityでGif動画が撮影できる 非同期APIが恋しい人はUnityGifRecorderと合わせて使ってみるといいかも
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】InputSystemのInputControlから「押されているか」を簡単に検知したい

※ InputSystemのPreview版を使用している記事です。 正式バージョンでは使用方法が変更されている可能性があります まず、UnityのInputSystemとは キーボードの左キーを押したとき ゲームパッドの左キーを押したとき uGUIで作った左移動ボタンを押したとき などなど.. 入力側が異なってもコード側で意識せずに処理できる新しい入力システムです InputSystem自体は素晴らしい記事が沢山あるのでカット 今回は InputSystem を使用している場合の 「キー(orボタン)が押されているか」 判定取得の記事になります。 しかも従来のInput.GetKeyライクに扱いたい。(つまりinterfaceを継承したりせずに簡単に扱いたい) 単純に「Updateメソッドで"押され続けているか"」を取りたいときあると思うんですよね // Input時代の書き方 void Update() { if (Input.GetKey(KeyCode.LeftArrow)) { // 左キー(orボタン)が押されている } } InputSystemのInputControlを使用している場合、該当するものがどれかわからずに悩みました... まず、以下のような移動に関するaInputControlを作成しました。 「キーボードの左を押したとき」と「画面上の左ボタンを押した時」に同じ処理をさせたいので ActionType は Button にしています。 結果として、InputSystem v1.0.x の時は以下の形で取得することができました void Update() { // moveはInputControl if (move.Left.ReadValue<float>() > 0f) { // 左キー(orボタン)が押されている } } ActionTypeがボタンの場合floatでReadValueができるようなクラス設計になっていました。 なので、キーやボタンが押されている場合 ReadValue<float>() で値が返ってくるので判定ができます。 しかし、 直感的でもなく気持ち悪さが残る.. (float... 現在の最新である InputSystem v1.1.0-preview3 を入れた所、以下のような形で取得できるようになっていました。 (リファレンス) https://docs.unity3d.com/Packages/com.unity.inputsystem@1.1/manual/Actions.html void Update() { // moveはInputControl if (move.Left.IsPressed()) { // 左キー(orボタン)が押されている } } IsPressed!! すごくスマート、そして直感的な形でとれるようになりました。 終わり 以前も isPressed 変数自体はあり外からはアクセスできないようになっていましたが IsPressed() メソッドとして公開されるようになっていました。 リポジトリ覗いてみても v1.1.0 で中身大幅に変わってますね。 これ以外にも沢山機能が追加されていそうです。 今回の内容はブログにも書いてあります https://toshizabeth.hatenablog.com/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

はじめに 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 Microsoft Translator 先ほどのアプリで利用した翻訳の部分はMicrosoft Translatorを利用しています。 登録の手順を覚えている範囲でメモします。 この手順に関してですが、2021/04/03時点の情報となります。 私も使い方がわからなかったため、過去に執筆された記事等手掛かりに進めてましたが、UIや手順に変更があり、そこそこ苦労しました。 この記事もそうなる可能性が高いのでご注意ください。 まずは下記からMicrosoft AzureのHome画面を開きます。 ログインしたらHome画面上部からTranslatorを検索し、 Marketplaceの欄のTranslatorを選び、登録に進みます。 登録画面で必要な項目を選択します。ここでPricing tierの欄をfreeにしておけば無料で使えるはずです。(たぶん) 設定完了したらAPIを利用する際に必要な値を下記画面から確認できます。 翻訳デモ 翻訳VRアプリ内のコードは他のAPIに置換できるよう、モジュール化しているためわかりにくいかなと思い、シンプルな翻訳デモを作りました。 英語→日本語、日本語→英語が翻訳可能です。 もちろんMicrosoft Translatorが対応している言語であれば他の言語でも翻訳可能です。 【参考リンク】:Language and region support for text and speech translation バージョン 念のため使ったライブラリ等のバージョンも書いときます。 Unity 2019.4.8f1 UniTask.2.2.4 UniRx 7.1.0 コード 翻訳デモのコードです。 using System; using System.Linq; using System.Text; using System.Threading; using Cysharp.Threading.Tasks; using UniRx; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; /// <summary> /// MSTranslatorの最小構成サンプル /// </summary> public class SimpleTranslation : MonoBehaviour { [SerializeField] private Dropdown fromLanguageDd; [SerializeField] private Dropdown toLanguageDd; [SerializeField] private Button translateButton; [SerializeField] private InputField inputField; [SerializeField] private Text translationText; /// <summary> /// レスポンスを格納する構造体 /// </summary> [Serializable] public struct TranslateData { public Translations[] translations; [Serializable] public struct Translations { public string text; public string to; } } /// <summary> /// リクエストを格納する構造体 /// </summary> [Serializable] public struct SpeechData { public string Text; } private const string SUBSCRIPTION_KEY = "登録キー"; private const string ENDPOINT = "https://api.cognitive.microsofttranslator.com/"; private const string LOCATION = "登録時に設定したLocation"; /// <summary> /// 設定言語 /// </summary> private enum Language { ja, en } private Language fromLanguage = Language.ja; private Language toLanguage = Language.en; 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> /// <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 = "translate?api-version=3.0"; requestInfo += $"&from={from}&to={to}"; var request = UnityWebRequest.Post(ENDPOINT + requestInfo, "Post"); //リクエストに使用するJSON作成 var speechData = new SpeechData {Text = speechText}; var jsonData = "[" + JsonUtility.ToJson(speechData) + "]"; var bodyRaw = Encoding.UTF8.GetBytes(jsonData); request.uploadHandler = new UploadHandlerRaw(bodyRaw); request.downloadHandler = new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/json"); //ヘッダーに必要な情報を追加 request.SetRequestHeader("Ocp-Apim-Subscription-Region", LOCATION); request.SetRequestHeader("Ocp-Apim-Subscription-Key", SUBSCRIPTION_KEY); //結果受け取り var second = TimeSpan.FromSeconds(3); var result = await request.SendWebRequest().ToUniTask(cancellationToken: ct).Timeout(second); var rawJson = result.downloadHandler.text; var json = rawJson.Substring(1, rawJson.Length - 2); var data = JsonUtility.FromJson<TranslateData>(json); return data.translations[0].text; } } APIのリクエスト用のJson、APIのレスポンス用のJsonのそれぞれをシリアライズ、デシリアライズするための構造体を用意する必要があります。 リクエスト用のJsonはルートが配列でないとAPIの都合上だめだったのでごり押ししています。 var jsonData = "[" + JsonUtility.ToJson(speechData) + "]"; 【参考リンク】:【Unity(C#)】WebAPIで返ってきたJSONデータの扱いでつまったところ EnumをDropDownに反映 全然関係ない内容ですが、知らなかったのでメモします。(下記参考リンクのまんまですが...) 【参考リンク】:UnityでDropDownのOptionリストに、enumの定義値をラベルとしてスクリプトからセットする /// <summary> /// 設定言語 /// </summary> private enum Language { ja, en } private Language fromLanguage = Language.ja; private Language toLanguage = Language.en; private void Start() { //ドロップダウンメニュー作成 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); } Enumの値をvar languages = Enum.GetNames(typeof(Language));で配列化してDropDownの値に追加します。 あとはDropDownの値変更を監視して、変更時にenumに値を設定してあげればOKです。 おわりに 記事内にも書いた通り、翻訳APIの箇所はモジュール化しているので他の無料で使えるAPIと比較して精度など試してみようと思います。 次は音声認識機能について書きます。 参考リンク Microsoft Translator テキスト API で、日本語を英語に翻訳するサンプル UniTaskの使い方2020 / UniTask2020 Quickstart: Get started with Translator
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RenderTexture間のRay変換

メインカメラ(Persepective)からのオブジェクトへのRayによる当たり判定 をRenderTextureを描画しているSubCamera(Orthographic)のRay へと変換するものです public ray TransformRay(Ray ray,GameObject TargetScreen) { Plane QuadPlane = new Plane(-TargetScreen.transform.forward, TargetScreen.transform.position); float enter = 0; TargetPlane.Raycast(ray, out enter); Vector3 HitPoint = ray.GetPoint(enter); Vector3 shift=transform.position-TargetScreen.transform.position; float scale=transform.lossyScale.magnitude/TargetScreen.lossyScale.magnitude; Hitpoint=(HitPoint-shift)*scale; return new Ray(HitPoint,transform.forward); } ・なんの意味があるのか? 主にLive2Dを描画するために使います。Live2DはOrthographicのカメラにしか写りません。 そこでPersepectiveのカメラに写したい場合は一度Live2DモデルをRenderTextureに描画して、それをマテリアルにして3D空間のオブジェクトに反映させます。 ですがこの方法だと基準点が違うため当たり判定用のRayの変換が必要になります。そのためのスクリプトです。 RenderTextureに描画してPersepectiveカメラに写すことでズーム、スクロール、半透明化が可能になります
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む