忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

C#でDirectX11 SlimDXチュートリアルその03 背景のクリア

 レンダーターゲットのクリア

前回まではただ単にウィンドウを表示しているのと見た目は変わりませんでした。
slimDXWindow00.jpg

今回はこのように背景を(青で)クリアする方法をメモしておきます。

Tutorial02ClearRenderTarget.jpg

「なぜ青色で塗る必要があるのか?」と思う方もいらっしゃるでしょう。
その理由は、以前描画した内容を消すためです。
ゲームでは一秒間に何十回も違った絵を表示してアニメーションにしています。
その時、以前描いた内容が残っていてはおかしなことになる場合があるのです。
(全てのケースにおいて、ではありませんが)

なお、ここでのこの背景クリア方法は、背景クリアにだけ使える方法です。
今回使った方法の応用で絵を描くことはできないので注意してください。
絵の描き方は次回以降です。


クリアするAPI

背景を一色でクリアするには、DeviceContext.ClearRenderTargetView()メソッドを使います。
public void ClearRenderTargetView(RenderTargetView view, Color4 color);
viewはクリアする対象。レンダーターゲットといいます。
colorはクリアする色です。例えばここに青を指定すれば画面が全て青になります。

さてここで聞きなれないクラスが2つ現れました。
DeviceContextクラスとはなんでしょう?
RenderTargetViewクラスとは?

順番に説明しましょう。
SlimDX.Direct3D11.DeviceContextクラスはデバイスの描画機能をカプセル化したクラスです。
デバイスは描画を司ると説明しておきながら実はDeviceクラスそのものには描画機能はありませんでした。
このクラスに全てまとめられていたのです。

これはコンストラクタで生成して使うようなタイプのクラスではありません。
Deviceのプロパティを通じてアクセスするクラスです。
このクラスを使うときにはいつもDevice.ImmediateContextプロパティを使うことになるでしょう。

public DeviceContext ImmediateContext { get; }

たとえばdevice.ImmediateContext.ClearRenderTargetView(view, new Color4(1, 1, 1, 1));という具合です。

RenderTargetView

SlimDX.Direct3D11.RenderTargetViewクラスは描画対象を表すクラスです。
3DCGを描いたり今回のように青でクリアしたりするときはこのオブジェクトが変わります。
レンダー(描画)ターゲット(対象)ビューです。
?「ビュー」とはなんでしょう?

ビューというのはDirect3D11におけるデータの使われ方を意味するオブジェクトです。
RenderTargetViewの他にも~~Viewというクラスが幾つかあります。
Direct3D11では、デバイスで使われるデータ(リソース)と、その使われ方(ビュー)を切り離しています。
これは謎ですね。
オブジェクト指向の原則「データとそれに対する操作を一緒にせよ」に反しているようです。

どうしてこういうことをするのかというと、ひとつのデータに複数の役割を割り当てられるようにするためです。
「このデータはあるときにはこういう使い方をするけど別の時にはああいう使い方をしたいなあ」というとき、
この2つが一体化しているとクラスの数が膨大になってしまうでしょう。
そのため一見めんどくさいようでありますが、データとその使われ方を分離しているのですね。

RenderTargetViewクラスを使うにはコンストラクタでインスタンスを生成してやります。

public RenderTargetView(Device device, Resource resource);

deviceはレンダーターゲットビューを作るデバイスです。
resourceはレンダーターゲットビューを関連付けるリソースです。「このリソースをレンダーターゲットとして使う」ということですね。

deviceは前回初期化したデバイスを使います。
resourceには何を使えばいいのでしょう?
それはスワップチェーンのバックバッファーです。
スワップチェーンのバックバッファーがレンダーターゲットになるのです。
具体的にはどうすればいいのかというと、Resource.FromSwapChain()メソッドの戻り値を使います。
Resourceという名前のクラスはたくさんあるのですが、ここではSlimDX.Direct3D11.Resourceクラスのことです。

public static T FromSwapChain(SwapChain swapChain, int index) where T : class, Resource; 

このメソッドはスワップチェーンのバックバッファーを取得します。
swapChainは取得するバックバッファーを持つスワップチェーン。
indexは欲しいバッファのインデックスです。通常0です。
Tは取得するリソースの型です。Resourceでもいいでしょうが、Resourceは似たような名前が多くて紛らわしいのでサンプルではTexture2Dにしておきます。


SwapChain.Present

以上のクラスを使って青にした後、しなければならないことがまだ残っています。
それはSwapChain.Present()を呼ぶことです。
これを呼ばなければクリアの結果が画面に反映されません。
これは描画されたイメージをウィンドウにプレゼントするメソッドです。
参考:IDXGISwapChain::Present

public Result Present(int syncInterval, PresentFlags flags);
syncIntervalは垂直同期とフレーム表示の同期方法を表します。0ならば同期せずに即座にプレゼントします。その他の値ならその分の垂直同期の後に表示を同期します。0でいいでしょう。
flagsはプレゼント方法を表します。
 
参考:DXGI_PRESENT
  数値  
None 0  
Test 1  
DoNotSequence 2  
 

コード

コードは前回のを少し変えてこうなります。


	
using SlimDX.Direct3D11;
using SlimDX.DXGI;
 
class Program
{
    static void Main()
    {
        using (Game game = new MyGame())
        {
            game.Run();
        }
    }
}
 
class MyGame : Game
{
    protected override void Draw()
    {
        GraphicsDevice.ImmediateContext.ClearRenderTargetView(
            RenderTarget,
            new SlimDX.Color4(1, 0, 0, 1)
            );
 
        SwapChain.Present(0, PresentFlags.None);
    }
}
 
class Game : System.Windows.Forms.Form
{
    public SlimDX.Direct3D11.Device GraphicsDevice;
    public SwapChain SwapChain;
    public RenderTargetView RenderTarget;
 
 
    public void Run()
    {
        initDevice();
        SlimDX.Windows.MessagePump.Run(this, Draw);
        disposeDevice();
    }
 
    private void initDevice()
    {
        MyDirectXHelper.CreateDeviceAndSwapChain(
            this, out GraphicsDevice, out SwapChain
            );
 
        initRenderTarget();
    }
 
    private void initRenderTarget()
    {
        using (Texture2D backBuffer
            = SlimDX.Direct3D11.Resource.FromSwapChain<Texture2D>(SwapChain, 0)
            )
        {
            RenderTarget = new RenderTargetView(GraphicsDevice, backBuffer);
        }
    }
 
 
    private void disposeDevice()
    {
        RenderTarget.Dispose();
        GraphicsDevice.Dispose();
        SwapChain.Dispose();
    }
 
    protected virtual void Draw() { }
}
 
class MyDirectXHelper
{
    public static void CreateDeviceAndSwapChain(
        System.Windows.Forms.Form form,
        out SlimDX.Direct3D11.Device device,
        out SlimDX.DXGI.SwapChain swapChain
        )
    {
        SlimDX.Direct3D11.Device.CreateWithSwapChain(
            DriverType.Hardware,
            DeviceCreationFlags.None,
            new SwapChainDescription
            {
                BufferCount = 1,
                OutputHandle = form.Handle,
                IsWindowed = true,
                SampleDescription = new SampleDescription
                {
                    Count = 1,
                    Quality = 0
                },
                ModeDescription = new ModeDescription
                {
                    Width = form.ClientSize.Width,
                    Height = form.ClientSize.Height,
                    RefreshRate = new SlimDX.Rational(60, 1),
                    Format = Format.R8G8B8A8_UNorm
                },
                Usage = Usage.RenderTargetOutput
            },
            out device,
            out swapChain
            );
    }
}
 
まず、デバイスとスワップチェーンを作成します。 そしてスワップチェーン→リソース→レンダーターゲットという流れでオブジェクトを作成し、 レンダーターゲットを青でクリアします。 そして仕上げとしてスワップチェーンでプレゼントします。 そうするとウィンドウに青が反映されます。 結果はこうなります。
Tutorial02ClearRenderTarget.jpg

拍手[3回]

PR