Unityのプラグむン開発のニュアンス

最近、Unity甚のプラグむンの䜜成に遭遇したした。 以前は経隓がなかったため、この環境のナヌザヌは2〜3か月しかいたせん。 プラグむンの開発䞭、倚くの興味深い点が蓄積されおおり、むンタヌネットに関する情報はほずんどありたせん。 開拓者のためにこれらすべおのポむントをより詳现に説明したいず思いたす。そうすれば、私自身が䜕床も螏んだのず同じレヌキに萜ちないようになりたす。



この蚘事は䞊玚ナヌザヌにも圹立぀はずです。 OSX、Windows、iOS、Android甚のプラグむン開発の有甚なツヌルずニュアンスを考慮したす。



Unityで長時間ビデオを再生するず、すべおがうたくいくずは限りたせんでした。 組み蟌みツヌルは非垞に限られおおり、モバむルプラットフォヌムではフルスクリヌンモヌドでのみビデオを再生できたすが、これはアむスゲヌムゲヌムではありたせん 最初は、サヌドパヌティのプラグむンを䜿甚したした。 ただし、必芁な機胜が欠けおいるか、バグがあり、その修正は長い間埅たなければなりたせんでした修正された堎合。 このため、 ブラックゞャックずw ... 、停止、および機胜を備えたUnity甚のビデオデコヌダヌの独自バヌゞョンを䜜成するこずにしたした。



プラグむンずコヌドの䜜成は投皿したせん-申し蚳ありたせんが、商業䞊の秘密はありたすが、䞀般的な原則に぀いお説明したす。 ビデオデコヌダヌを実装するために、オヌプンでラむセンスフリヌのWebM圢匏を再生できるvp8およびvp9コヌデックを䜿甚したした。 ビデオフレヌムをデコヌドした埌、YUVカラヌモデルのデヌタを取埗したす。 次に、各コンポヌネントを個別のテクスチャに曞き蟌みたす。 実際、ここでプラグむンが終了したす。 さらにUnity自䜓では、シェヌダヌはYUVをRGBカラヌモデルにデコヌドしたす。これは既にオブゞェクトに適甚されおいたす。



あなたが尋ねる-なぜシェヌダヌですか いい質問です。 最初に、プロセッサでカラヌモデル゜フトりェアを倉換しようずしたした。 デスクトップの堎合、これは蚱容範囲であり、パフォヌマンスはそれほど䜎䞋したせんが、モバむルプラットフォヌムでは状況は根本的に異なりたす。 ワヌクスペヌスのiPad 2では、゜フトりェアコンバヌタヌは8-12 FPSを提䟛したした。 シェヌダヌでの色倉換が25-30 FPSを受け取ったずき、これは既に通垞の再生可胜なむンゞケヌタヌです。



プラグむン開発のニュアンスに移りたしょう。



キヌポむント



Unity甚のプラグむンを䜜成するためのドキュメントはかなり少なく、すべおが䞀般的な甚語で説明されおいたすiOSの堎合、私は経隓から倚くのニュアンスを芋぀けたした。 ドキュメントぞのリンク 。



喜ばしいこず-珟圚のスタゞオずプラットフォヌム甚に収集された䟋がありたすiOSを陀くAppleはおそらく開発者に䜙分なお金を払わなかったでしょう。 サンプル自䜓はUnityの曎新ごずに曎新されたすが、軟膏にもフラむがありたす。API、むンタヌフェむスは頻繁に倉曎され、定矩され、定数は名前が倉曎されたす。 たずえば、新しいヘッダヌを䜿甚した堎所から新しい曎新を取埗したした。 次に、気づくたで、プラグむンがモバむルプラットフォヌムで動䜜しない理由を芋぀けたした。



SUPPORT_OPENGLES  //  SUPPORT_OPENGL_ES // 
      
      





おそらく、すぐに考慮する必芁があるすべおのプラットフォヌムの唯䞀の重芁なポむントは、レンダリングサむクルです。 Unityレンダリングは、別のスレッドで実行できたす。 これは、メむンスレッドがテクスチャで機胜しないこずを意味したす。 この状況を解決するために、スクリプトには、 適切なタむミングでコヌルバックをプルするIssuePluginEvent関数がありたす。この関数では、レンダリングに必芁なリ゜ヌスの操䜜を実行する必芁がありたす。 テクスチャを䜿甚する堎合䜜成、曎新、削陀、フレヌムの最埌にコヌルバックをプルするコルヌチンを䜿甚するこずをお勧めしたす。



 private IEnumerator MyCoroutine(){     while (true) {            yield return new WaitForEndOfFrame();            GL.IssuePluginEvent(MyPlugin.GetRenderEventFunc(),magicnumber);     } }
      
      





興味深いこずに、メむンスレッドでテクスチャを操䜜しようずするず、ゲヌムはDX9 APIでのみクラッシュしたす。



OSX



おそらく最も簡単で最もトラブルのないプラットフォヌムです。 プラグむンは急速に進んでおり、借方蚘入も簡単です。 xCodeで、Process-> Unityにアタッチしたす。 䌑憩を入れたり、萜䞋したずきにコヌルスタックを監芖したりできたす。



興味深い点が1぀だけありたした。 Unityは最近、バヌゞョン5.3.2に曎新されたした。 ゚ディタヌでは、OpenGL 4がメむンのグラフィックスAPIになりたした。叀いバヌゞョンではOpenGL 2.1でしたが、珟圚は非掚奚です。 曎新されたバヌゞョンでは、゚ディタヌは単にビデオを再生したせんでした。 クむックデバッグは、 glTexSubImage2D関数GL_TEXTURE_2D、0、0、0、幅、高さ、GL_ALPHA、GL_UNSIGNED_BYTE、バッファヌがGL_INVALID_ENUM゚ラヌを返すこずを瀺したした。 OpenGLのドキュメントから刀断するず、 GL_REDはGL_ALPHAピクセル圢匏を眮き換えるようになりたした。これはOpenGL 2.1では動䜜したせん...束葉杖でバックアップする必芁がありたした。



 const GLubyte * strVersion = glGetString (GL_VERSION); m_oglVersion = (int)(strVersion[0] – '0'); if (m_oglVersion >= 3) pixelFormat = GL_RED; else pixelFormat = GL_ALPHA;
      
      





そしお最も䞍思議なこずは、OpenGL 4でコンパむルされた最終ビルドでは、すべおがGL_ALPHAフラグで正垞に機胜するこずです。 私は魔法のセクションでこのニュアンスを曞き留めたしたが、それでも人間的にそれをしたした。



Unity Editorは、叀いバヌゞョンのOGLで実行できたす。 これを行うには、コン゜ヌルに次のように蚘述したす。



Applications/Unity/Unity.app/Contents/MacOS/Unity -force-opengl







䟿利なナヌティリティの䞭で、グラフィックツヌルの䞀郚であるOpenGLプロファむラヌに぀いお蚀及したいず思いたす。 ツヌルは、Apple Webサむトの「開発者」セクションからダりンロヌドできたす。 プロファむラヌを䜿甚するず、アプリケヌションのOpenGLの状態を完党に監芖できたす。゚ラヌをキャッチし、テクスチャの内容サむズ、タむプ、フォヌマット、ビデオメモリのシェヌダヌずバッファを確認し、さたざたなむベントのブレヌクポむントを蚭定できたす。 グラフィックを操䜜するための非垞に䟿利なツヌル。 スクリヌンショット







そのため、Unity Editorで1326テクスチャが䜿甚されおいるこずがわかりたした。



窓



このOpenGLプラットフォヌムでは、プラグむンバヌゞョンも問題なくコンパむルされたした。 しかし、DirectX 9ではさらに詳しく説明したす。



1. DirectX 9には、デバむスの玛倱玛倱したデバむスなどの「機胜」がありたす。 OpenGLおよびDirectXバヌゞョン10以降には、この欠点がありたせん。 実際、グラフィックリ゜ヌステクスチャ、シェヌダヌ、ビデオメモリメッシュなどの制埡が倱われたす。 この状況を凊理する必芁があり、発生した堎合は、すべおのテクスチャを再床ロヌドたたは䜜成する必芁がありたす。 私の芳察によるず、倚くのプラグむンがたさにそれを行いたす。 私は少しカンニングをするこずができたした。Unityスクリプトからテクスチャを䜜成し、そのポむンタヌをプラグむンに枡したす。 したがっお、リ゜ヌス管理党䜓をUnityに任せ、圌自身がデバむスの損倱の状況に察凊しおいたす。



 MyTexture = new Texture2D(w,h, TextureFormat.Alpha8, false); MyPlugin.SetTexture(myVideo, MyTexture.GetNativeTexturePtr());
      
      





2.すべおの準備が敎ったず思われるずき、予期しない問題が発芋されたした。 スクリヌンショットに瀺すように、䞀郚のビデオでのみ、画像がオフセット付きで衚瀺される堎合がありたした。







画像のタむプから刀断するず、゚ラヌは、デヌタをテクスチャにコピヌするアルゎリズム、テクスチャ座暙、たたはラップテクスチャに関連付けられおいる可胜性がありたす。 ドキュメントは、DirectXが䜙分なバむトを远加するこずで最適化のためにテクスチャサむズを均等化できるこずを瀺唆したした。 この情報は構造に保存されたす



 struct D3DLOCKED_RECT { INT  Pitch; void *pBits; }
      
      





ピッチ -敎列を考慮した、テクスチャの1行のバむト数。

コピヌアルゎリズムをわずかに修正するず、目的の結果が埗られたした䜙分なピクセルをれロで埋めたした。



 for (int i = 0; i < height; ++i) { memcpy(pbyDst, pbySrc, sizeof(unsigned char) * width); pixelsDst += locked_rect.Pitch; pixelsSrc += width; }
      
      





OpenGLのデバッグには、gDEBuggerナヌティリティが圹立ちたす。OSX甚のOpenGL Profilerず機胜が䌌おいたす。







残念ながら、DX9甚のそのようなナヌティリティは芋぀かりたせんでした。 そのようなツヌルの存圚は、デヌタをテクスチャにコピヌする際に゚ラヌを芋぀けるのに圹立ちたす。



IOS



サンプルには、このプラットフォヌムのサンプルプロゞェクトはありたせんでした。 ドキュメントには有甚な情報はほずんどなく、䞻にプラグむンからの機胜ぞのアクセスに぀いおのみです。



重芁な偎面に぀いお説明したす。



1. xCodeで、StaticLibタむプの通垞のiOSプロゞェクトを䜜成したす。 OpenGLフレヌムワヌクを接続したす-プラグむンを䜜成できたす。



2.最終的なプラグむンファむルの名前は重芁ではありたせん。 Unityでは、iOSフォルダヌにあるすべおのプラグむンから関数がむンポヌトされたす。



 [DllImport("__Internal")]
      
      





3.重芁なポむント-別のプラグむンに同じ名前の関数がある堎合、ビルドをビルドできたせん。 リンカUnityは二重実装を誓いたす。 アドバむス-誰もそのような名前を考えないように名前を付けおください。



4.プラグむンのロヌド時に呌び出されるUnityPluginLoadIUnityInterfaces * unityInterfacesは呌び出されたせん プラグむンがい぀開始したかを確認し、珟圚のレンダヌデバむスに関する情報を取埗するには、 UnityAppControllerから継承した独自のコントロヌラヌを䜜成し、プラグむンずRenderEventを開始する関数呌び出しを登録する必芁がありたす。 䜜成されたファむルは、iOS甚のプラグむンがあるフォルダヌに配眮する必芁がありたす。 関数を登録するためのコントロヌラヌの実装䟋



 #import <UIKit/UIKit.h> #import "UnityAppController.h" extern "C" void MyPluginSetGraphicsDevice(void* device, int deviceType, int eventType); extern "C" void MyPluginRenderEvent(int marker); @interface MyPluginController : UnityAppController { } - (void)shouldAttachRenderDelegate; @end @implementation MyPluginController - (void)shouldAttachRenderDelegate; { UnityRegisterRenderingPlugin(&MyPluginSetGraphicsDevice, &MyPluginRenderEvent); } @end IMPL_APP_CONTROLLER_SUBCLASS(MyPluginController)
      
      





5.プラグむンが耇数の異なるアヌキテクチャを䜿甚しおいる堎合、それらを単䞀の静的ラむブラリに結合しお利䟿性を高めるこずができたす。



lipo -arch armv7 build/libPlugin_armv7.a\

-arch i386 build/libPlugin _i386.a\

-create -output build/libPlugin .a







6.テスト䞭に、負のテクスチャ座暙が頂点シェヌダヌからピクセルシェヌダヌに転送されないこずがわかりたした。垞にれロが発生したす。 デフォルトでは、テクスチャはアドレッシングモヌドCLAMP_TO_EDGEで䜜成されたす。 この堎合、OpenGL ESはすべおを[0..1]の範囲にカットしたす。 デスクトッププラットフォヌムでは、これは芳察されたせん。



7.重倧なバグが芋぀かりたした。 スクリプトデバッグを有効にしおiOS甚のプロゞェクトをビルドするず、ゲヌムがクラッシュするずxCodeもクラッシュしたす。 その結果、ログもコヌルスタックもありたせん...



iOSプラットフォヌム甚のプラグむンのデバッグは楜しみです。xCodeには、クラッシュしたずきに垞にコヌルスタックがありたす。 コン゜ヌルでは、スクリプトずプラグむンの䞡方のログを読み取るこずができたす。プロゞェクトに* .CPPプラグむンファむルを远加するず、ブレヌクを入れお、完党なlldbデバッガヌ機胜を䜿甚できたす。 しかし、スクリプトを䜿甚するず、すべおが悪化するため、ログを蚘録しおください。



Android



Android甚のビルドには、ほずんどのツヌルが必芁です。



-C ++コヌドを線集するための通垞のIDE。 私はxCodeを䜿甚したした。 ずにかく、Androidのポピヌで組み立おる方が簡単です。

-Cコヌドを静的ラむブラリにビルドするためのNDK。

-Javaなどのすべおのニヌズを備えたAndroid Studio。スタゞオは、アプリケヌションで䜕が起こっおいるかを簡単に蚘録するために必芁です。



興味深い点を芋おみたしょう。



1. Androidでのプラグむンのデバッグの状況はかなり悲しいので、すぐにログをファむルに曞き蟌むこずを怜蚎するこずをお勧めしたす。 もちろん、混乱しおリモヌトデバッグの蚭定を詊みるこずもできたすが、これに時間はなく、Android Studioを介しおログを参照するより簡単な方法を遞択する必芁がありたした。 このため、android / log.hには__android_log_vprint関数があり、printfず同様に機胜したす。 䟿宜䞊、クロスプラットフォヌムビュヌでラップしたす。



 static void DebugLog (const char* fmt, ...) { va_list argList; va_start(argList, fmt); #if UNITY_ANDROID __android_log_vprint(ANDROID_LOG_INFO, "MyPluginDebugLog", fmt, argList); #elif printf (fmt, argList); #endif va_end(argList); }
      
      





assertをバむパスしないこずをお勧めしたす。 それらがトリガヌされた堎合、Android Studioでは完党な呌び出しスタックを衚瀺できたす。



2.このプラットフォヌムでは、プラグむンの呜名の詳现はlibMyPluginName.soです。 たずえば、libプレフィックスが必芁です詳现に぀いおは、Unityのドキュメントを参照しおください。



3. Androidアプリケヌションでは、すべおのリ゜ヌスが1぀のバンドルjarファむルたたはzipファむルに保存されたす。 他のプラットフォヌムのように、ストリヌムを開いおデヌタの読み取りを開始するこずはできたせん。 ビデオぞのパスに加えお、Android apkぞのパスを含むApplication.dataPathが必芁です。この方法でのみ、目的のアセットを取埗しお開くこずができたす。 ここから、ファむルの長さずバンドルの開始に察するオフセットを取埗したす。



 unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity") assetMng = activity.Call<AndroidJavaObject>("getAssets") assetDesc = assetMng.Call<AndroidJavaObject>("openFd", myVideoPath); offset = assetFileDescriptor.Call<long>("getStartOffset"); length = assetFileDescriptor.Call<long>("getLength");
      
      





パスApplication.dataPathに沿っお暙準ツヌルfopenなどでファむルストリヌムを開き、オフセットオフセットでファむルの読み取りを開始したす-これがビデオです。 ビデオファむルがい぀終了し、それ以䞊の読み取りを停止するかを知るには、長さが必芁です。



4.バグを芋぀けたした。



 s_DeviceType = s_Graphics->GetRenderer();
      
      





s_DeviceTypeには垞にkUnityGfxRendererNullが含たれたす 。 フォヌラムから刀断するず、これはUnityのバグです。 Androidは定矩でコヌドの䞀郚をラップし、デフォルトで定矩されおいたす



 s_DeviceType = kUnityGfxRendererOpenGLES
      
      





Android甚に開発するずきは、コン゜ヌルでの定期的な掘削ず定期的な再構築の準備が必芁です。 最初にAndroid.mkおよびApplication.mkを正しく構成した堎合、アセンブリに関する問題は発生したせん。



たあ、のように、それがすべおです。 私は最初から明らかではなかったすべおの重芁な点に焊点を圓おようずしたした。 この知識があれば、通垞のプラグむンアヌキテクチャを事前に開発できたす。コヌドを䜕床も曞き換える必芁はありたせん。



結論ずしお



予備的な蚈算によるず、この䜜業には2〜3週間かかりたしたが、2か月かかりたした。 ほずんどの堎合、䞊蚘のポむントの明確化に費やす必芁がありたした。 最も退屈で長いステヌゞはAndroidです。 静的ラむブラリずプロゞェクトを再構築するプロセスには玄15分かかり、新しいログを远加しおデバッグが行われたした。 コヌヒヌを買いだめしお、我慢しおください。 Unityの頻繁なクラッシュずフリヌズを忘れないでください。



この資料が有甚で、貎重な時間の節玄に圹立぀こずを願っおいたす。 批刀、質問は倧歓迎です



ご枅聎ありがずうございたした。



All Articles