以前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のsortingOrder
とsortingLayerName
で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
このブログ記事を書く際、内容及び表現に不快感を与えてしまった事をお詫び致します。