UnityのStreamingAssets内でPython環境構築してみた
Pythonで作られたライブラリなどをUnityでも流用したい!
ということで思いついたのがPythonに必要なファイルを全て StreamingAssets
に突っ込む方式でした。
その前にクライアント/サーバーでやり取りしろよ!って話ではあります。はい。その通りです!ただスタンドアローンで動かしたかったんです!!
PythonとC#のやり取りをする
C#との連携で他にもツールは出てきたのですが最終的にPythonのライブラリも使いたいと思っており、探すとPythonnetならできるという情報があったので選出しました。
GithubのWikiに導入方法などは書いておりスムーズに導入できました。dllをダウンロードしてPluginsディレクトリに入れるだけですね。
中身を弄る必要があればGitHubから簡単にcloneしてdefineを弄ればUnityで動かすカスタムができる印象でした。
突っ込むPythonの環境を取得する
Pythonの環境はAnacondaで取得した環境をStreamingAssetsに入れることにしました。 Pythonのインストールパスを確認してから
Python |---------DLLs |---------Lib |---------Scripts |-たくさんのdllとpyファイル
をUnityのStreamingsAssetsに入れます。基本的に必要なものは上記でした。他のディレクトリは無くても大丈夫です。
Editorでは動きます。
Editor/Buildの違い
Unity Editorでは Plugins
ディレクトリ以外にdllがあっても読み込んでくれます。そのため StreamingAssets
にPythonのすべてを入れておくだけでPythonが動きます。しかし、BuildをしてStreamingAssetsにPythonを入れてもdllを検知できません。そのため、Pythonを動かすのに必要なdllをPluginsにいれて他の.pyなどをStreamingAssetsに入れることで解決しました。
そのためdllを全てPluginsに入れて他をStreamingAssetsに入れるようにします。細かいことを気にしなければ全部 Plugins
と StreamingAssets
に入れてしまいます。
ちゃんと分けたい場合は
StreamingAssets
で
find . -name "*.dll" -type f | xargs rm
などをして必要な拡張子だけを残すようにします。
Plugins
だと exe
や py
など dll
以外を消す必要があります。(Windowsだと)
動かした結果
using周りは端折りますが以下のコードを動かしました。(.Net4.0環境)
public class PythonLifeCycle : IDisposable { public void Initialize() { var pythonHome = $"{Application.streamingAssetsPath}/PythonEnv"; var scripts = $"{pythonHome}/Scripts"; Environment.SetEnvironmentVariable("PATH", $"{pythonHome};{scripts}", EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("DYLD_LIBRARY_PATH", $"{pythonHome}/Lib", EnvironmentVariableTarget.Process); PythonEngine.PythonHome = $"{pythonHome}"; PythonEngine.PythonPath = $"{pythonHome}/Dlls;{pythonHome}/Lib;{pythonHome}/Lib/site-packages"; PythonEngine.Initialize(); } public void Dispose() { PythonEngine.Shutdown(); }
private readonly PythonLifeCycle lifeCycle = new PythonLifeCycle(); [SerializeField] private TextMeshProUGUI textUI; void Start() { lifeCycle.Initialize(); RunPython(); } private void RunPython() { using (Py.GIL()) { dynamic sysModule = Py.Import("sys"); textUI.text = sysModule.version; } } private void OnDestroy() { lifeCycle.Dispose(); }
シンプルにPythonの環境を構築してTextを出力するようにしています。
Editor | Windows |
---|---|
最低限Editor/Buildでの差は埋めれました。 他(WebGL/Android)はそのまま動かなかったので放置しています。一旦はWinのみで開発するつもりだったので。 触った感じだとデスクトッププラットフォームだと問題ないと思います。
WebGLで実行とエラーがでるのですがパッとうまい解決策が見つけれず放置 Androidでビルドしてgradleの処理の際にStreamingAssetsのファイルが多すぎてファイルをすべてgroovyのファイルに記述されていて、その記述されている数が多いことでエラーとなり失敗します。これはzipに纏めるなりの回避をすればなんとかなるとは思います。(メモ)
まとめ
今後はpythonのライブラリを導入してC#から使えるようにしていこうと思います。1プラットフォームでもPythonを内蔵して動いて良かったです。
magentaセットアップをwslでしたら躓いてDockerの良さを再認識したメモ
音の自動生成を試したい!
ということでgoogleさんが作っているmagentaというツールを使おうと思いセットアップをしてみました。結構躓いたのでメモ
↓の手順で触っていきました。
1 Windowsで行うためwslの設定から
pipでインストールすると新しいtensorflowのサポートがされておらず以下の公式サイトをみつつ情報をあつめ進めていきました。
2 ハンズオンを触っていく
ここから出会ったエラーと解決を書いていますが 3 本番はここからだった
へ飛べばスキップできるものです。さくさくセットアップしたい場合は飛ばしてください。
みたいなエラーとなる pipには既にtensorflow1系は提供されていないのでpipでインストールした場所 すると という別のエラーが出てきたので、さっきの箇所は通ったようです、同じようにエラーに対応していきます。 基本的には この調子で進めると ‘‘‘
AttributeError: module 'tensorflow' has no attribute 'contrib'
‘‘‘ というエラーで行き詰ってしまいました。調べると
Migrate your TensorFlow 1 code to TensorFlow 2 | TensorFlow Core 一切のサポートが切られていて、tensorflow-addonというのも試しましたがうまくいきませんでした。 そこで、ふとmagentaのReleaseを確認したらtensorflow2のサポートのsourcecodeが貼ってあり Releases · magenta/magenta · GitHub ひとまず pipでインストールしたmagenta自体を置き換えたので pipで pipで となりpygameというものでコケてしまう
調べると
Python - pythonのライブラリをインストールしたいのですが、エラーが出てしまい進みません|teratail を発見、Python3.8を使っているから良くないみたいなのでpyenvを使ってPython3.7に切り替えると無事成功 そして最初のコマンドは通ったので が再び浮上、今回はmagenta_sessionの方で出ているようだったのでmagenta_sessionのディレクトリを全検索して magenta_session/convert_to_melody_dataset.py at master · icoxfog417/magenta_session · GitHub
の にすることで解決 magenta_session/convert_to_melody_dataset.py at master · icoxfog417/magenta_session · GitHub
の tf.data.TFRecordDataset | TensorFlow Core v2.3.0 を使うようにするのが良いそうでした に置き換えて通った が出てきて初CUDA実行の気配 ここで色々躓いて、そもそも環境のセットアップがきちんと行えておらずwsl側でgpuを認識していないようでした。driverのインストール/アンインストールなどもしたのですが改善せず。省略可能領域
python scripts/data/create_note_sequences.py
を行おうとするとそもそもtensorflowのバージョンに合っていないので def log_statistics_list(stats_list, logger_fn=tf.logging.info):
AttributeError: module 'tensorflow' has no attribute 'logging'
/home/{ユーザー名}/.local/lib/python3.8/site-packages/magenta/
に行って中身の必要箇所を置き換える手段をとりました class NoteSequenceRecordWriter(tf.python_io.TFRecordWriter):
AttributeError: module 'tensorflow' has no attribute 'python_io'
tf.hoge
を tf.compat.v1.hoge
にすれば通ります。3 本番はここからだった
Magenta v2.0.1
をダウンロードして、pipでインストールしていた場所 /home/{ユーザー名}/.local/lib/python3.8/site-packages/magenta/
で中身を全部置き換えると違うエラーとなり進んだようです。2 ハンズオンを触っていく
の労力は意味なかったようです。pipのパッケージ更新してくれんかな…ModuleNotFoundError: No module named 'tensorflow_probability'
tensorflow_probability
をインストールすれば解決ModuleNotFoundError: No module named 'tensor2tensor'
tensor2tensor
をinstallしようとするとCollecting pygame
Using cached pygame-1.9.6.tar.gz (3.2 MB)
ERROR: Command errored out with exit status 1:
python scripts/data/convert_to_melody_dataset.py --config attention_rnn
を実行していくAttributeError: module 'tensorflow' has no attribute 'app'
tf.app
から tf.compat.v1.app
で対処 pipeline_instance = md.get_pipeline(config, md.FLAGS.eval_ratio)
get_pipeline
が無いと言われるので調べると pipeline_instance = md.melody_rnn_pipeline.get_pipeline(config, md.FLAGS.eval_ratio)
TypeError: 'float' object is not iterable
md.pipeline.tf_record_iterator(tgt.SEQUENCE_FILE, pipeline_instance.input_type),
tf_record_iterator
は使われなくなるそうで今後は tf.data.TFRecordDataset(tgt.SEQUENCE_FILE, pipeline_instance.input_type),
2020-08-10 19:54:24.507256: E tensorflow/stream_executor/cuda/cuda_driver.cc:314] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
を頼りに色々やってみたのですがWindowsがプレビューじゃないからぽいのでWindowsのダウンロードを待ちながらmagentaにはdockerもあるので、そちらを試したところ秒で処理が動いたのっでもうDockerでいいんじゃないかと思いました。wslでgpuを使いたい気持ちがあったものの結構格闘してすり減っていたのでDocker万歳ということで動かしていきます。(Windowsプレビューでも動かなかったのでもうわからないからやっぱDocker最高)
追記 (2020/08/12) wslのバージョンが足りてなかった、MicrosoftStoreからインストールが何故かできなかったのでマニュアルインストールの手段をとる docs.microsoft.com
dockerのセットアップがうまくいかず
Windows Subsystem for Linux(WSL)で Docker を利用する - simplestarの技術ブログ
Repository configuration | nvidia-docker
この2つの記事を参考にセットアップして動くことを確認
docker runするとエラーが出ていて
cgroups: cannot find cgroup mount destination
は
Docker command でドッカー練習する時のメモ | Hapicode
を参考に解決
TensorFlowからGPUが認識できているかを2行コードで確認する - 動かざることバグの如し
などをみてgpuの認識を確認
sudo mkdir /sys/fs/cgroup/systemd sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd
すると動いた
以下のサイトでDockerfileのベースを探すとcuda周りのセットアップをしなくていいので最高
おわり
セットアップまでにかなり引っかかるポイントがあり折れました。自分の環境、セットアップの順番で起こったことなので他の人の環境だとまた違うことが起こる可能性は高いですが、何か参考になればと思います。(最初からDocker使う方が時短にはなる)
また個人的にjetbrains系のエディターをかなりつかうのでwsl環境と同期する方法があるのか調べると Configure an interpreter using WSL - Help | PyCharm あったのでjetbrainsを使ってwslで環境構築が終わった人は
SAColliderBuilderでNull Reference Exceptionが出てしまった時の応急処置
SA Mesh Collider Builderを使おうとしたらNullExceptionで処理が止まってしまった
超絶便利なSAColliderBuilderを使おうとしたらエラーで怒られました
上記のAssetはMeshに対して当たり判定を良い感じにつけてくれるものなのですが、AssetStoreにある別の建物などの環境Assetに対して使う際にエラーがでました。
その時のエラー箇所が SAMeshColliderEditorCommon.cs
の
public static string GetSAMeshColliderName_Material( Material[] materials, int index ) { // ↓ ここ if( materials != null && index < materials.Length && !string.IsNullOrEmpty(materials[index].name)) { return materials[index].name; } return "Mesh." + index.ToString("D8"); }
942行目あたりのif文だったので、ここだけ軽くチェックしたら materials[index]
がnullになるパターンがあるようでした。Assetの階層構造によるものなのかは深くチェックしていないのでわかりません。そのためif文に materials[index] != null
を追加して以下のようにしました。
public static string GetSAMeshColliderName_Material( Material[] materials, int index ) { if( materials != null && index < materials.Length && materials[index] != null && !string.IsNullOrEmpty(materials[index].name)) { return materials[index].name; } return "Mesh." + index.ToString("D8"); }
という風にしました。これで処理が終わり無事Colliderが付けられたので応急処置としては大丈夫そうです。
VRMをPartyParrot風に表示できるPartyParrotVRMを作ってみた
PartyParrotVRM
ネット上で時たまみるPartyParrotというgifがあります
これをVRM…人型に適応したら面白いのでは?と思って適応させたサイトを作ってみました
機能
ここのREADMEというのに説明を大体書いていますが
PartyParrotVRM/README.md at master · MizoTake/PartyParrotVRM · GitHub
好きなVRMをドラッグ&ドロップすることでPartyParrot風に表示します
また簡易的なフェイストラッキングをしています
- Download Gif
VRMを移動させてPartyParrot風のgifをダウンロードします
↓ ダウンロードしたgifがこちら
- Camera Preview
顔のトラッキングを確認することができます
- Camera List
ブラウザが認識しているカメラから使用するものを決めれます
ちょいちょい触ったりしないとわかりづらいですが実装しているのはこんな感じです
まとめ
Unityとjsの連携を結構書いたり顔のトラッキングからモデルへの反映を書いてみたりと意外と面白く実装していきました 全体的に雑な実装になっていますが大まかに実装して満足度高く…一旦の区切りとしています…
細かい挙動まできちんとこだわないと自分の思う面白さ表現できないと思ったので時間があればまた触ろうかと思います
Cinemachine Sampleを触ったメモ
Cinemachine v2.6 Sampleが公開された
の記事をみてCinemachineって結構いろんなことができることを知ったのでSampleを触ることにしました。元々Cinemachineに興味はあったが触ってなかったのでSampleを触って面白かったものをメモりました。
v2.6のサンプルですが新機能の紹介ではありませんしComponentのパラメーターを細かく紹介することもないのでご了承ください。
Cinemachineのベースの考え方
CinemachineBrain
というコンポーネントが実際にUnityのCameraコンポーネントを動かすものです。
映し出す位置の指定を CinemachineVirtualCamera
などの仮想カメラとなるコンポーネントが指定して、それをCinemachineBrain
が優先度などのパラメーターを加味してCameraに映し出すような作りになっています。
仮想カメラはCameraコンポーネントはありませんが仮想カメラのTransform等をみてBrainが映し出します。
CinemachineVirtualCamera
以外にも
- CinemachineStateDrivenCamera
- CinemachineFreeLook
などの複数のコンポーネントを使い分けつつ仮想カメラを配置して挙動を制御していきます。
StateDrivenCamera
概要
Animatorの状態遷移によってCameraを切り替えるもの
- 歩いているとマウスで操作したカメラワークになる
- 走っているとキャラクターを下から見上げる角度に変わる
をComponentの設定で指定できるもの
各オブジェクトの設定
Hierarchyは
├── MainCamera ├── 3rdPersonController (子オブジェクト省略) ├── Directional Light ├── Environment (子オブジェクト省略) └── CM StateDrivenFreeLook ├── CM FreeLook └── CM FreeLook sprint
という風になっています。
MainCameraにはCinemachineを使う際の中枢となる CinemachineBrain
が追加されています。
CM StateDrivenFreeLook
はAnimatorのどのStateを見てVirtualCameraの切り替えを行うのか設定できます。
UnityEditorのMenuにある Cinemachine > Create State-Driven Camera
がベースとなっています。
シンプルな構成を確認したいときは新しいSceneを作成してCreateすると良いと思います。
CM StateDrivenFreeLook
には対象となるAnimatorとStateによってどのCameraを使用するのか設定しています。
Custom BlendsというところにScriptableObjectが設定されていますが、これはカメラを切り変える際のパラメーターが設定できます。
仮想カメラが切り替わる際のEasingや秒数が指定できます。また特定のカメラから特定のカメラへの遷移も個別に設定できるようになっています。
CinemachineStateDrivenCamera
がメインの処理となりますが同じGameObjectに CinemachineCollider
というコンポーネントがあります。Cameraに収める対象のオブジェクトが壁などでCameraに映らないようなことが起こると自動的にCameraに収めてくれるコンポーネントになります。
【Unity】【Cinemachine】対象が障害物に隠れた時に対象が映る位置にカメラをいい感じに移動するCinemachine Collider
というブログなどを見るとパラメーターがどう反映するのか確認できます。
CM FreeLook
と CM FreeLook sprint
は CinemachineFreeLook
Componentを付けてパラメーターが違うオブジェクトになります。それにより見え方が変わっています。
Impulse
概要
衝撃を通知するオブジェクトに近づくとカメラが距離や威力によって揺れるものです。
各オブジェクトの設定
Hierarchyは
├── MainCamera ├── Directional Light ├── Ground ├── Player (子オブジェト省略) ├── BouncingBall ├── Magic Cube (子オブジェト省略) └── CM PlayerCam
MainCameaには相も変わらず CinemachineBrain
です。そしてCM PlayerCam には CinemachineVirtualCamera
という標準な構成です。
今回のキモである衝撃の扱いについては、BouncingBallとCM PlayerCamにあるコンポーネントで表現できます。
BouncingBallには Cinemachine Collision Impulse Source
CM PlayerCamには Cinemachine Impulse Listener
が設定されています。
Impulseの設定はSourceの方で設定します。
Raw Signalでどういう風に揺らすのか設定できます。SignalSourceAsset.csというclassを継承したScriptableObjectを設定すれば、XYZ毎にアニメーションカーブを設定して揺れ方を変えることが可能です。
Amplitude Gain
と Frequency Gain
でカメラの揺れる威力などを調整できます。
CameraMagnets
概要
設定したObjectが範囲内にいると、元々対象としているObjectも含めてカメラに収めるようにする。 また、壁(指定した範囲)外を表示しないように収めている。
各オブジェクトの設定
Hierarchyは
├── CamCollider ├── MainCamera ├── Environment (子オブジェト省略) ├── CM vcam2D ├── Directional Light (1) ├── 3rdPersonController (子オブジェト省略) ├── TargetGroup1 └── CameraMagnets ├── CameraMagnet ├── CameraMagnet(1) └── CameraMagnet(2)
となっています。
まず指定した範囲を収めている処理から説明します。
CamColliderにて Polygon Collider 2D
で壁をなぞるように値を入れています。
上記のように設定したColliderをCM vcam2Dに追加されている Cinemachine Confiner
のInspectorに設定します。
これによってColliderで設定した範囲内をカメラに収めることができます。
次に設定したObjectに近づいた時にカメラをフォーカスさせる方法です。
Cinemachineで用意されている CinemachineTargetGroup
というコンポーネントと自前で少しだけcsを書いているようです。
CinemachineTargetGroup
に近づいたらカメラに収めたい対象のTransformを入れておきます。
CameraMagnetTargetController.cs
using System.Collections;
using System.Collections.Generic;
using Cinemachine;
using UnityEngine;
public class CameraMagnetTargetController : MonoBehaviour
{
public CinemachineTargetGroup targetGroup;
private int playerIndex;
private CameraMagnetProperty[] cameraMagnets;
// Start is called before the first frame update
void Start()
{
cameraMagnets = GetComponentsInChildren<CameraMagnetProperty>();
playerIndex = 0;
}
// Update is called once per frame
void Update()
{
for (int i = 1; i < targetGroup.m_Targets.Length; ++i)
{
float distance = (targetGroup.m_Targets[playerIndex].target.position -
targetGroup.m_Targets[i].target.position).magnitude;
if (distance < cameraMagnets[i-1].Proximity)
{
targetGroup.m_Targets[i].weight = cameraMagnets[i-1].MagnetStrength *
(1 - (distance / cameraMagnets[i-1].Proximity));
}
else
{
targetGroup.m_Targets[i].weight = 0;
}
}
}
}
CameraMagnetProperty.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class CameraMagnetProperty : MonoBehaviour
{
[Range(0.1f, 50.0f)]
public float MagnetStrength = 5.0f;
[Range(0.1f, 50.0f)]
public float Proximity = 5.0f;
public Transform ProximityVisualization;
[HideInInspector] public Transform myTransform;
void Start()
{
myTransform = transform;
}
void Update()
{
if (ProximityVisualization != null)
ProximityVisualization.localScale = new Vector3(Proximity * 2.0f, Proximity * 2.0f, 1);
}
}
Cinemachineのコンポーネントではない追加されていたcsは上記です。要約すると操作Objectからの距離をみてTargetGroupに設定してあるTargetのWeightを変更するものになります。
Weightの数値が上がることによってCameraに収める対象物として認識されます。それによってgifのような動作となります。
まとめ
かなりお手軽にカメラワークを作ることが可能なことがわかりました。今後個人で何かするなら絶対にいれるか…とは思っています。 PostProcessingについても対応するComponentがあるのでUnity機能を組み合わせるのにも問題ない気がしています。
OBS StudioでChromeのウィンドウキャプチャ方法
ブラウザの描画をGPUを使ったままにしたい
Chromeのブラウザをウィンドウキャプチャしようとしたときにもしかしたら動かないかもしれません。
以前以下の記事にて
これはChromeの設定にある ハードウェア アクセラレーションが使用可能な場合は使用する という項目をオフにすることで解決ができる
と書きましたがオフにしなくても動く方法がありました。
chrome://flags/
をurlを入れるところにコピペして開いてください。
Choose ANGLE graphics backend
という項目の選択肢を OpenGL
にします。
再起動を求められるのでChromeを再起動します。
するとOBS Studioでウインドウキャプチャが可能になります。
描画にGPUを使った方が負荷としては軽いと思うのでできるだけこちらで使っていこうかなと思いました。 Chromeの設定で完結するので楽ですね。
リアルタイムに声をテキストとして表示する「Zimack」というサイトを作った
OBSで配信するときに字幕に特化したサイトがあればいいのに
という気持ちでちょっとだけ作った
1日くらいで作ってるのでまだまだ機能が足りないし作っててUIミスったなと思っているのですが、、、いずれ…いずれな…
とりあえず、マイクの許可与えればテキストに起こしてくれるし、画面クリックすればオプションで少しだけカスタマイズできるやつ
思いついたのはTwitterのおかげ
音声認識からWebカメラ映像への字幕合成までをGoogle Chrome だけでやってくれるWebページをつくってみました! #xDiversity
— Ippei Suzuki (@1heisuzuki) May 20, 2020
ブラウザを画面共有 or OBS等でキャプチャーすればビデオ会議に字幕付きで参加できます。
↓Webページhttps://t.co/xlGX4jkIJn pic.twitter.com/Y1ju1wfUvq
別の記事で
Youtubeでライブ配信する際にボイチェンと自動字幕を入れてみた - 勉強不足で至らんブログ
紹介した上記のTweetを観て字幕特化のサイトあればいいのにと思いました。
まだまだ理想はOBSのブラウザで動くことなのでできてないのですが、ウィンドウキャプチャでは表示できるのはひとまずいいかなと
あとは背景に画像貼れたりとかテキストのフォント変えれたり、UIが字幕の表示場所と被らないようにするとかしたいですがいずれ…
まとめ
GitHubPages使っているのでバリバリソースコード公開してるのですがすげー無駄な書き方をしている気しかしてない リファクタも兼ねていずれな…って感じですね
あとは今まであまりサービス名を考えたりしてなかったので「Zimack」とつけてみました付けてみたかった。
追記
実際に使って配信してみました
色の変更もちゃんとできて配信できたので満足 自分で足りない機能は随時追加してきたい所存