昨日投稿した「Unityから画像のピクセル情報をネイティブに渡す方法」の続きです。
昨日のプロジェクトではOnPostRender
でJavaのメソッドを呼んで、Javaネイティブ側でglReadPixels
を実行させていたのですが、UnityのMultithreaded Renderingに対応していませんでした。
そこで、GL.IssuePluginEvent
を使ってMultithreaded Renderingに対応させようということなのですが、結果から言えば半分できて半分諦めました。
更新したサンプルプロジェクトはこちら
https://bitbucket.org/HoshiyamaTakaaki/pixelreadstest
GL.IssuePluginEvent
はレンダリングスレッドから指定のC++メソッドを呼んでくれる命令です。
なのでそのままではJavaメソッドは呼べません。
そこでいったんC++のメソッドを経由してJNI経由でJavaのstaticメソッドを呼び出します。
#if !UNITY_EDITOR
#if UNITY_ANDROID
[DllImport("glutil")]
private static extern IntPtr getRenderEventFunc();
#endif
#endif
private void OnPostRender()
{
#if UNITY_ANDROID && !UNITY_EDITOR
GL.IssuePluginEvent(getRenderEventFunc(), m_TargetTexture.GetNativeTexturePtr().ToInt32());
//m_NativePlugin.CallStatic("sendRgbaFrame", m_TargetTexture.GetNativeTexturePtr().ToInt32());
//GL.InvalidateState();
#endif
}
extern "C" {
using UnityRenderEvent = void(*)(int);
UnityRenderEvent getRenderEventFunc();
}
// call from Unity(IssuePluginEvent)
void onRenderEvent(int eventId)
{
LIBENC_LOGD("onRenderEvent:%d", eventId);
JNIEnv *jenv = getEnv();
if (gjClass_UnityConnect == NULL)
{
gjClass_UnityConnect = (jclass)jenv->NewGlobalRef(findClass(jenv, "jp/ne/pickle/libpixelreads/UnityConnect"));
gjMethodId_sendRgbaFrame = jenv->GetStaticMethodID(gjClass_UnityConnect, "sendRgbaFrame", "(I)V");
}
if (gjClass_UnityConnect != NULL)
{
jenv->CallStaticVoidMethod(gjClass_UnityConnect, gjMethodId_sendRgbaFrame, eventId);
jthrowable mException = jenv->ExceptionOccurred();
if (mException)
{
jenv->ExceptionDescribe();
jenv->ExceptionClear();
}
}
else
{
LIBENC_LOGE("jClass not got");
}
}
// call from Unity(IssuePluginEvent)
UnityRenderEvent getRenderEventFunc()
{
return onRenderEvent;
}
このような形で、C#からC++のonRenderEvent
がレンダリングスレッドで呼ばれます。
そしてメソッド内でJavaの目的のメソッドを探してアクセスを行います。
ちなみにJNI_OnLoad
が呼ばれるスレッドとは別スレッドとなるので、JavaVM以外のJNIEnvなどの情報は取得し直す必要があるようです。
これで一応Javaメソッドの呼び出しは行えるようになりましたが、ここからJava側でOpenGLESの操作を行う場合に、色々とRuntimeエラーが発生しました。
たぶんサンプルコードではJava側のOpenGLESの初期化(UnityConnect.initialize)などが別スレッドで行われているからだと思います。
GL_INVALID_OPERATIONが出まくります。
というわけで、スレッドを意識して処理をきちんと整理すれば動くようになるんじゃないかと思いますが、正直もうこれ以上沼にはまる時間はないので、Multithreaded Renderingは諦めようと思います。
Androidは本当に沼です。