4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UnityのTextureのポインタをSwiftだけで作ったNative Pluginに渡して処理する

Posted at

UnityのTextureのポインタをSwiftだけで作ったNative Pluginに渡して処理する

  • Swift だけで、Unity の iOS の Native Plugin を作る方法を紹介しました

  • Unity の Texture をネイティブで処理したい場合があります
  • 例えば、Texture を mp4 で録画する Native Plugin を実装することが可能です
  • Unity には、Texture.GetNativeTexturePtr 関数が用意されており、Texture2D や RenderTexture からも直接 Native で処理できる Texture のポイントを取得することが可能です
  • iOS では、id<MTLTexture> を取得することが可能であり、今回はこれを Swift で受け取って、処理する方法の紹介です

今回のサンプル

  • リポジトリはこちらです

  • [Swift だけで、Unity の iOS の Native Plugin を作る](Swift だけで、Unity の iOS の Native Plugin を作る方法) の内容を前提知識にしています
  • 今回は、Unity の Texture をアルバムに保存する機能を作ります
  • 左の画像の(小さいですが)真ん中のボタンを押すと、右の画像が保存されます

処理の流れ

  1. Unity で適当な Texture を用意する
  2. Texture.GetNativeTexturePtr() を使って、Native で処理するポインタを取得する
    == ここまで C# ここから Swift ===
  3. void ポインタを受け取るので、MTLTexture 型にキャストする
  4. MTLTexture -> UIImage 変換する
  5. アルバムに保存する

Unity の実装

  • 任意の Texture が用意できれば良いです
  • ここでは、RenderTexture のパターンで進めます
  • すでに、存在する Texture を利用する場合は、RenderTexture の用意 の章は読み飛ばしてください
  • Native の Texture のポインタを取得して、Native に渡す から固有の処理です

RenderTexture の用意

  • RenderTexture を作成します
  • Color Format が R8G8B8A8_UNorm になっていることを確認します
  • サイズは任意のサイズで大丈夫です

make-render-tex.png

  • 新規のカメラを追加し、先ほど作成した、RenderTexture を Target に設定します

set-target-texture.png

  • 新規の Button を追加し、下記のスクリプトを設定します
using System;
using System.Runtime.InteropServices;
using UnityEngine;

public class Button : MonoBehaviour
{
#if UNITY_IOS
    [DllImport("__Internal")]
    private static extern void swiftPmPlugin_saveImage(IntPtr mtlTexture);
#endif

    public RenderTexture texture;

    public void onTap()
    {
        Debug.Log("Button tapped!");

#if UNITY_IOS
        swiftPmPlugin_saveImage(texture.GetNativeTexturePtr());
#endif
    }
}
  • スクリプトをアタッチしたボタンの onClick と Texture を設定します
    set-button.png

Native の Texture のポインタを取得して、Native に渡す

  • Native の関数を宣言します
  • 今回は、iOS のみサポートです
  • [DllImport("__Internal")] をつけた、static extern な関数を定義します
#if UNITY_IOS
    [DllImport("__Internal")]
    private static extern void swiftPmPlugin_saveImage(IntPtr mtlTexture);
#endif
  • C# では、この関数に texture.GetNativeTexturePtr() を渡すだけです
#if UNITY_IOS
        swiftPmPlugin_saveImage(texture.GetNativeTexturePtr());
#endif

Swift の実装

C# (c) の呼び出し口を作る

  • @_cdecl を付けて Swift で関数を定義します
  • C# の定義的に、void* なので、UnsafeRawPointer 型として受け取ります
  • MTLTexture にキャストして、保存する関数に渡します
@_cdecl("swiftPmPlugin_saveImage")
public func swiftPmPlugin_saveImage(_ texturePtr: UnsafeRawPointer?) {
    guard let texturePtr = texturePtr else { return }
    let mtlTexture: MTLTexture = __bridge(texturePtr)
    SwiftPmPlugin.saveImage(mtlTexture: mtlTexture)
}

MTLTexture -> UIImage

  • デフォルトの pixel format は rgba8Unorm なのですが、Unity は srgb でレンダリングしているので、フォーマットを修正します
  • MTLTexture -> CIImage -> CGImage -> UIImage に変換します
  • UIImageWriteToSavedPhotosAlbum を使ってアルバムに保存します
class SwiftPmPlugin {
    static func saveImage(mtlTexture: MTLTexture) {
        let mtlTexture2 = mtlTexture.makeTextureView(pixelFormat: .rgba8Unorm_srgb)!
        let ci = CIImage(mtlTexture: mtlTexture2, options: nil)!
        let context = CIContext()
        let cg = context.createCGImage(ci, from: ci.extent)!
        let ui = UIImage(cgImage: cg)

        UIImageWriteToSavedPhotosAlbum(ui, nil, nil, nil)
    }
}

Framework の出力と設定

  • こちらの記事の Framework でビルドする の章以降と同じ手順で実行ビルド可能です

  • アルバムの追加のために、Unity でビルドした後に、Xcode でアプリをビルドする前に、Info.plist にPrivacy - Photo Library Additions Usage Description の設定をします
  • ビルドしたアプリで、ボタンを押した時に、画像がアルバムに保存されているはずです

おわりに

  • Unity と Swift の Texture のやりとりは、GetNativeTexturePtr を使うことで簡易に実現可能です
  • Texture のサイズやフォーマット、mipmap などの情報も、MTLTexture に入っているので、個別に取得する必要がないのが便利です
  • また、Texture2D に書き写して、ReadPixels したバイト配列をコピーするよりポインタ渡しの方が経済的なのかなと思っています
  • Unity の Texture を Swift で処理するのは、応用の幅が広いので、活用して行きたいです
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?