01.Unity側で作成したテクスチャを、Java側でGL_TEXTURE_EXTERNAL_OESのテクスチャとしてSurfaceTextureに割り付けて使用する方法

結果としては、失敗。この方法はうまくいかなかった。

事象としては、glBindTexture() で GL_INVALID_OPERATION エラーが発生する。

考察としては、「Unityで作成したテクスチャは、GL_TEXTURE_2D をターゲットとして作成されているため、異なるターゲットである GL_TEXTURE_EXTERNAL_OES での glBindTexture() でエラーが発生する」と考える。

解説

Android(Java)のSurfaceTextureのテクスチャをUnityで描画するために、最低限すべきことは、以下です。

Unity側で作成したテクスチャを、Java側でGL_TEXTURE_EXTERNAL_OESのテクスチャとしてSurfaceTextureに割り付けて使用するために、すべきことは、以下です。

実装

Androidライブラリのプロジェクトの作成

まず、AndroidStudioを使用し、Androidライブラリを作成します。

Androidライブラリのプロジェクトを作成します。

(開発環境としては、Android Studio 4.2.2 を使用しています)

(この設定でプロジェクトを作成しなければいけない、というわけではありません。)

「Welcome to Android Studio」画面の「Create New Project」をクリックします。

「New Project」ウィンドウが表示されます。

No Activity」を選択し、「Next」ボタンを押します。


Nameに、プロジェクト名を入力します。たとえば、「SurfaceTextureRendererProject」と入力します。
Package nameのドメイン部分に、会社のドメイン名を指定します。
Save locationに、プロジェクトを保存するフォルダパスを指定します。
「Finish」ボタンを押します。

しばらく待ちます。
Android Studio のステータスバーに「Gradle sync finished in ・・・」や「*daemon started successfully ・・・」と出るまで待ちます。

Androidライブラリのプロジェクトができました。

Androidライブラリモジュールの作成

Androidライブラリモジュールを追加します。

メインメニュー「File > New > New Module」を選択します。

「Create New Module」ダイアログが表示されます。

Android Library」を選択します。
Module nameに、モジュール名を入力します。たとえば、「surfacetexturerenderer」と入力します。
Package nameのドメイン部分に、会社のドメイン名を指定します。
Minimum SDKを選択します。たとえば、「API 19: Android 4.4 (KitKat)」を選択します。Unityで作成するアプリのMinimum API Levelのバージョンと一致させます
「Finish」ボタンを押します。

しばらく待ちます。
Android Studio のステータスバーに「Gradle sync finished in ・・・」や「*daemon started successfully ・・・」と出るまで待ちます。

ライブラリモジュールができました。

Javaクラスの追加

Androidライブラリモジュールに、Java側の処理を記述するクラスを追加します。

「Project」ウィンドウの「surfacetexturerenderer > java > {ドメイン}.surfacetexturerenderer」を右クリックします。
右クリックメニュー「New > Java Class」を選択します。

「New Java Class」ダイアログが表示されます。

クラス名に、「SurfaceTextureRenderer」と入力します。
エンターキーを押します。


「OK」ボタンを押します。

SurfaceTextureRenderer.javaの内容を以下のようにします。

Androidライブラリモジュールのビルド

Androidライブラリモジュールをビルドします。

「Gradle」ウィンドウの「SurfaceTextureRendererProject > surfacetexturerenderer > Tasks > build > build」をダブルクリックします。

モジュールのビルドが開始します。
しばらく待ちます。
Android Studio のステータスバーに「Gradle build finished in ・・・」と出るまで待ちます。

「{Androidプロジェクトフォルダ}\{Androidライブラリモジュール名}\build\outputs\aar」フォルダに、リリースビルド、デバッグビルドの2つの「aar」ファイルが生成されます。

Unityアプリのプロジェクトの作成

ここからは、Unityを使用し、Unityアプリを作成します。

Unityアプリのプロジェクトを作成します。

(開発環境としては、Unity 2020.3.12f1 を使用しています)

(この設定でプロジェクトを作成しなければいけない、というわけではありません。)

「Unity Hub」画面の「プロジェクト」「新規作成」をクリックします。

「新しいプロジェクトを作成」ウィンドウが表示されます。

3D」を選択します。
プロジェクト名欄に、プロジェクト名を入力します。たとえば、「RenderingSurfaceTextureInUnity」と入力します。
保存先に、プロジェクトを保存するフォルダパスを指定します。
「作成」ボタンを押します。

しばらく待ちます。

Unityアプリのプロジェクトができました。

Build Settingsの設定の変更

Build Settingsの設定を変更します。

メインメニュー「File > Build Settings」を選択します。

「Build Settings」ダイアログが表示されます。

「Scenes In Build」の「Add Open Scenes」ボタンを押し、現在開いているシーンを「Scenes In Build」に追加します。
「Platform」の「Android」を選択します。
Switch Platform」ボタンを押します。

しばらく待ちます。

Unityアプリの対象プラットフォームがAndroidになりました。

「Build Settings」ダイアログを閉じます。

Project Settingsの設定の変更

Project Settingsの設定を変更します。

メインメニュー「Edit > Project Settings」を選択します。

「Project Settings」ダイアログが表示されます。
左側の設定項目の「Player」を選択します。

Company Name欄に、会社名を入力します。
Graphics APIs欄の「+」ボタンから「OpenGLES2」を追加します。
Graphics APIs欄の「OpenGLES2」以外を削除します。
Multithread Renderingのチェックを外します。


Package Nameが、Company Name欄に入力した会社名が反映されたパッケージ名になります。
Minimum API Levelを選択します。たとえば、「Android 4.4 'KitKat' (API level 19)」を選択します。Android Studioで作成したAndroidライブラリのMinimum SDKのバージョンと一致させます

「Project Settings」ダイアログを閉じます。

Android Logcatのインストール

アンドロイド端末で動作させた際の出力ログを確認するために、Android Logcatをインストールします。

メインメニュー「Window > Package Manager」を選択します。

「Package Manager」ダイアログが表示されます。

ダイアログ左上のPackage表示フィルタを「Packages: In Project」から「Packages: Unity Registry」に変更します。
検索ワード欄に「logcat」と入力し、で検索します。
Android Logcat」を選択します。
Install」ボタンを押します。

しばらく待ちます。
「Android Logcat」がインストールされました。
「Package Manager」ダイアログを閉じます。

続いて、「Android Logcat」の出力ログを表示するウィンドウをUnity画面に配置します。

メインメニュー「Window > Analysis > Android Logcat」を選択します。

「Android Logcat」ウィンドウが表示されます。

「Android Logcat」ウィンドウをUnity画面の適当な場所に配置します。

UIアイテムの追加

Unityのシーンに、テクスチャを表示するための画像要素、処理をトリガーするためのボタン要素を追加します。

「Hierarchy」ウィンドウにて、何も選択せず右クリックします。
右クリックメニュー「UI > Panel」を選択します。
「Canvas」が追加され、「Canvas」の下に「Panel」が追加されます。
(「EventSystem」も追加されます。)

「Hierarychy」ウィンドウの「Panel」を右クリします。
右クリックメニュー「UI > Raw Image」を選択します。
「RawImage」が追加されます。

「Hierarychy」ウィンドウの「Panel」を右クリします。
右クリックメニュー「UI > Button」を選択します。
「Button」が追加されます。



続いて、追加したUI要素のサイズ、位置を設定します。

PanelのScaleを、X = 0.75、Y = 0.75、に設定します。


RawImageのサイズを、Width = 512、Height = 512、に設定します。


Buttonの位置を、PosX = 0、PosY = -300、サイズを、Width = 320、Height = 60、に設定します。


Sceneウィンドウを正面から表示したときの、UI要素の配置イメージ

aarファイルの配置

Androidライブラリモジュールのファイル(aarファイル)を、Unityアプリのプロジェクトに配置します。

Unityを一度閉じます(シーンを保存していない場合は、シーンを保存し、Unityを終了します)。

「{Unityプロジェクトフォルダ}\Assets」フォルダの下に「Plugins」フォルダを作成し、その下に「Android」フォルダを作成します。

「{Unityプロジェクトフォルダ}\Assets\Plugins\Android」フォルダに、
「{Androidプロジェクトフォルダ}\{Androidライブラリモジュール名}\build\outputs\aar」フォルダに生成済みの「aar」ファイルのリリースビルドの方を、コピ-します。


Unityでプロジェクトを再度開きます。

「Project」ウィンドウにて、「Assets > Plugins > Android」に、「aar」ファイルが配置されていることを確認します。



C#スクリプトの追加

Unity側の処理を記述するc#スクリプトを追加します。

「Project」ウィンドウにて、「Assets」フォルダの下に「Scripts」フォルダを作成します。
「Scripts」フォルダの中に、「C# Script」を追加し、名前を「RawImageScript」に変更します。

RawImageScriptの内容を以下のようにします。

C#スクリプトのUI要素への割り付け

C#スクリプト「RawImageScript」をUI要素「RawImage」に割り付けます。

「Project」ウィンドウのC#スクリプト「RawImageScript」を、「Hierarchy」ウィンドウの「RawImage」にドラッグ&ドロップします。


「Inspector」ウィンドウにて、「RawImageScript」が「RawImage」に割り付いたことを確認します。

ボタンを押したときに実行する関数の設定

ボタンを押したときに実行する関数を設定します。

「Hierarchy」ウィンドウの「Button」を選択し、「Inspector」ウィンドウの表示内容を「Button」にします。

「Hierarchy」ウィンドウの「RawImage」を、表示内容が「Button」になっている「Inspector」ウィンドウの「OnClick()」のオブジェクト欄にドラッグ&ドロップします。

「OnClick()」のFunction欄を、「RawImageScript.OnEvent」にします。



「ボタンをクリックすると、『RawImage』オブジェクトに割り付けられた『RawImageScript』スクリプトの『OnEvent』関数が実行される」ようになりました。

Build

メインメニュー「File > Build Settings」を選択します。

「Build Settings」ダイアログが表示されます。

「Build」ボタンを押します。

出力フォルダと、出力ファイル名を指定します。たとえば、出力フォルダとして、Unityアプリのプロジェクトフォルダの下に「Build」フォルダを作成、指定し、出力ファイル名として「RenderingSurfaceTextureInUnity.apk」と指定します。

「保存」ボタンを押します。

Unityアプリのビルドが開始します。

しばらく待ちます。

Unityアプリの実行ファイル(apkファイル)が生成されます。

「Build Settings」ダイアログを閉じます。

実行

Build And Run

Android端末をUSB接続しておきます。

メインメニュー「File > Build And Run」を選択します。

Unityアプリのビルドが開始し、ビルドが終了すると、Android端末上でUnityアプリが実行されます。

起動直後


アプリ画面のボタンを押します。
TextureRendererの初期化処理が実行されます。

「Android Logcat」ウィンドウを確認すると、glBindTexture() でエラーが発生しています。



アプリ画面のボタンを再度押します。
テクスチャの更新処理が実行されます。

UnityアプリのRawImageの描画に変化はありませんでした。

「Android Logcat」ウィンドウを確認すると、SurfaceTexture#updateTexImage() で、エラーが発生しています。

考察

アプリ画面のボタンを1回目に押した際のエラーのエラーコードは1282。エラーコード 1282 (16進数表現にすると0x502)は、GL_INVALID_OPERATION。

glBindTexture()関数のリファレンスによると、
「GL_INVALID_OPERATION is generated if texture was previously created with a target that doesn't match that of target.」

「Unityで作成したテクスチャは、GL_TEXTURE_2D をターゲットとして作成されているため、異なるターゲットである GL_TEXTURE_EXTERNAL_OES での glBindTexture() でエラーが発生する」と考える。

アプリ画面のボタンを2回目に押した際のエラーは、1回目に押した際のエラーと関係のあるエラーと考える。

関連ページ

次項目:02.Unity側で作成したテクスチャを、Java側でGL_TEXTURE_2DのテクスチャとしてSurfaceTextureに割り付けて使用する方法