テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】RenderTextureをTexture2DにしてSpriteに使用する

f:id:tsubaki_t1:20160606221733g:plain

以前RenderTextureにテクスチャをバックバッファとして展開し、Spriteとして使用することでSetPassを抑えて使用する方法に聞かれたので、一応ココに書いておきます。

結論としては、別にSpriteとして使用しなくても良いよねって話です。
内容としては、ココから昨日の「【Unity】マテリアルやSetPassを増やさずテクスチャのUVを変える 」に繋がります。(昨日の記事はコレの検証中に出たというか)

 

Sprite云々とは別にRenderTextureをTexture2Dに流し込む話は時々聞くので、需要はあるのかもしれません。ただ、UnityがGrahic APIのドレをどの様に使用してるかで動作が変わってくると思うので、余りお薦めはしません。

RenderTextureをTexture2Dにする

出来るか出来ないかと言われれば、一応出来ます。ただ、余りお薦めはしません。

流れとしては、こんな感じです。

  • RenderTextureを元にTexture2Dを作る
  • Texture2Dの中身をRenderTextureにする

Texture2DをSpriteにする

Texture2DをSpriteに設定します。
rtがrendertexture、tex2DがTexture2Dです。

var rect = new Rect(0, 0, rt.width, rt.height);
var pivot = new Vector2(0.5f, 0.5f);
var sprite = Sprite.Create(tex2D, rect, pivot);

 rectとpivotはスプライトに使用する範囲と中心点です。これで指定範囲のスプライトが作られます。一応。

後はTexture2DにRenderTextureの中身を流し込みます。

RenderTextureをTexture2Dに流し込む

RenderTextureの中身を元にTexture2Dを作成します。ただ、Texture2DとRenderTextureの両方を作ると無駄なので、RenderTextureのポインタを取得し、そのガワと一致するようにTexture2Dのガワを設定します。

コード的にはこんな感じです。

var ptr = rt.GetNativeTexturePtr();
tex2D = Texture2D.CreateExternalTexture(
            rt.width, rt.height, TextureFormat.ARGB32, false, false, ptr);

次に中身を流し込みます。

var ptr = rt.GetNativeTexturePtr();
tex2D.UpdateExternalTexture(ptr);

 これで、見た目はTexture2D・中身はRenderTextureの名探偵が出来上がります。一応。

ただ、動作は完全にGrahic APIに依存するため、多分安定して動作しません。例えばDirectX11では動きませんでした。またガワはTexture2Dですが中身が違う為か、GetPixel等のTexture2D独自のAPIが使えたり使えなかったりします。また、これは失敗すると「Unityエディタが落ちる」のもお薦めしない理由の一つです。

代替案

今回はSpriteの使用を前提として考えたためRenderTextureをTexture2Dに流し込みましたが、素直にSpriteとか使わず、やはりquad+rendertextureで良い気がします。

描画順はRendererのsortingOrdersortingLayerNameでSpriteと同じような感じに設定できます。その際、マテリアルはTransparent(透明)な奴を使ってください。Transparentシェーダーとか楽で良さそうです。

Unity - スクリプトリファレンス: Renderer.sortingOrder

Unity - スクリプトリファレンス: Renderer.sortingLayerName

テクスチャの差替はMaterialPropertyBlockを使用すれば、かなり低コストで行えます。設定順を少し考えた方が良いかもしれませんが、まぁ。

SetPassを減らすアプローチは、テクスチャのUV変更をメッシュ側でやればOKです。flipも似たような感じで出来ます。まぁRenderTextureを使うようなケースなので、別にここまでしなくても良いとは思いますが。

 

色々と考えましたが、最終的にはこっちの方が楽な気がします。

代替案2

追記を書いてて思い出しましたが、Texture2D.PackTexturesなんてのもありました。これ使えば別にRenderTexture使わなくてもなんとかなったんじゃ感が…
もしくは(Monoのメモリが膨らみそうですが)SetPixelでスタンプみたいに貼りまくるとかでしょうか。
(検証したところ、どちらもTextureにReadWriteを要求する上、GPUに上がってるのが1枚しか結合されてなかったり、少し不思議な挙動を)

SetPass削減は良い事ですが、ソレをするためのコストが本当に適正かと言われれば…どうなんでしょう。少し気にしすぎな気がしなくも。

追記1

このブログ記事を書く際、内容及び表現に不快感を与えてしまった事をお詫び致します。

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp