Posts Tagged ‘ RenderTarget2D

RenderTarget2D.GetTexture()は同じアドレスを返す

RenderTarget2D.GetTexture()した結果を配列や二つの変数に代入し、あとからそのRenderTarget2Dをいじくり回すと両者が同じになるということについてです。

何のこっちゃさっぱりって人は、こちらのサンプルをどうぞ。XNA3.0で作成しています。

操作方法
左シフト->レンダリングターゲットからテクスチャを取得し左側のテクスチャに代入する。
右シフト->レンダリングターゲットからテクスチャを取得し右側のテクスチャに代入する。
そうするとソース上では片方しか描き換えてないのに、 両方書き換わってしまう。

私は最初これと同じようなことをしていて、この現象に出合い混乱して乱数クラスが狂ったのかと思いました。でもデバッガで追ってくと そうじゃなかったですね。ちゃんと乱数になってましたし、代入してるのも変数一つでした。で、ふと思いついたのが「ポインタ」って言葉。もしGetTexture()で取得できるオブジェクトのアドレスが同じならつじつまが通る…!

確かめてみようと思ってunsafeコード書いてみましたが、どうやら値型のアドレスは取得できても参照型のアドレスは取得できないようで、断念。

で、どうするか。下のような感じでディープコピーしてやればOKです。

GraphicsDevice.SetRenderTarget(0, null);
Texture2D newTex = new Texture2D(GraphicsDevice, tex1.Width, tex1.Height);
Color[] data = new Color[tex1.Width * tex1.Height];
target.GetTexture().GetData(data);
newTex.SetData(data);
tex1 = newTex;

ただひとつ問題なのがこの記事で検証されているようにXBOX360上ではGetData()/SetData()がパフォーマンスにかなり影響を与えるようです。特にGetData()が。今のところこれに対する対策は見つかってません…。描画処理をGPU上で全部やって最終的にテクスチャをもらうということぐらいしか思いつきません。ただそれだとfxファイルを書かなければならないですし、SpriteBatchなどで複雑な描画をしていた場合はとGPUには不向きかと。

うが~~~~!!!
XBOXでゲーム作りたいです…。

2009-12-16 01:18:49追記。

簡単な話でしたね。GetTexture()する数だけRenderTarget2Dを作ればいいんですね。
なぜ気がつかなかった!???


疲れてきてるな流石に…

RenderTarget2Dでエラー

バックバッファより大きいか、バックバッファより小さいRenderTarget2Dを作って、レンダーターゲットを切り替えてGraphicsDevice.Clear()もしくはspriteBatch.End()などをすると以下のようにエラーになったことがあると思います。

System.InvalidOperationExceptionエラー
アクティブなレンダー ターゲットと深度ステンシル サーフェイスは、ピクセル サイズとマルチサンプリング タイプがそれぞれ同じである必要があります。

具体的にはこんな感じのコードでエラーになるかと。

graphics.PreferredBackBufferHeight = 720;
graphics.PreferredBackBufferWidth = 1280;
var target = new RenderTarget2D(GraphicsDevice, 100, 100, 1, SurfaceFormat.Color);
//DepthStencilBuffer old = GraphicsDevice.DepthStencilBuffer;
//GraphicsDevice.DepthStencilBuffer = GfxComponent.CreateDepthStencil(target, DepthFormat.Depth24Stencil8Single);
GraphicsDevice.SetRenderTarget(0, target);
GraphicsDevice.Clear(Color.Brown);
GraphicsDevice.SetRenderTarget(0, null);
//GraphicsDevice.DepthStencilBuffer = old;
2009-12-31 追記

このままのコードだと、パフォーマンスが非常に悪くなるので、GfxComponent.CreateDepthStencilで作ったテクスチャは再利用するようにしたほうがいいです。


いままでは、このエラーを回避するにはレンダーターゲットの大きさを画面のサイズ(バックバッファ)と同じにするしかないと思ってました。でもエラーメッセージにはバックバッファなんて単語はひとつも入ってないんです。おかしいなぁと思って調べまくった結果、コメントアウトしてあることを追加すればOKでした。GfxComponentとかいうクラスはMSDNライブラリの「方法 : 深度テクスチャーを作成する」の「完全なサンプル コード」というところから落としてください。そのプロジェクトの中に入ってます。


以下、自分なりに解釈したこんなエラーになる理由です。

続きを読む