RenderTargetクラスを作る

テクスチャに対してレンダリングするためには、

  • Usage.RenderTarget、Pool.Defaultを指定して作ったテクスチャ
  • 3D描画を行う場合の深度バッファ
  • 実際の描画先となるテクスチャのサーフェイス

の3つが必要になります。
さらに、デバイスのResizingイベント時の再生成やDispose()、デバイスへの設定など、そのまま使うと結構面倒です。

ということでRenderTargetクラスを作ってみます。

RenderTargetクラス

using System;
using System.ComponentModel;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace WindowsFormsApplication1
{
    public class RenderTarget : IDisposable
    {
        private Texture texture_;
        private Surface depth_;
        private Surface surface_;
        private Viewport viewport_;
        private Format format_;

        public RenderTarget( Device device )
        {
            texture_ = null;
            surface_ = device.GetRenderTarget(0);
            depth_ = device.DepthStencilSurface;
            viewport_ = device.Viewport;
            format_ = device.PresentationParameters.BackBufferFormat;
        }

        public RenderTarget( Device device, int width, int height, Format format )
        {
            texture_ = new Texture(device,
                width, height, 1,
                Usage.RenderTarget, format, Pool.Default);
            depth_ = device.CreateDepthStencilSurface(
                width, height, device.PresentationParameters.AutoDepthStencilFormat,
                MultiSampleType.None, 0, true);
            surface_ = texture_.GetSurfaceLevel(0);
            viewport_.X = 0;
            viewport_.Y = 0;
            viewport_.Width = width;
            viewport_.Height = height;
            viewport_.MinZ = 0.0f;
            viewport_.MaxZ = 1.0f;
            format_ = format;
        }

        public void Dispose()
        {
            if (depth_ != null)
            {
                depth_.Dispose();
                depth_ = null;
            }
            if (surface_ != null)
            {
                surface_.Dispose();
                surface_ = null;
            }
            if (texture_ != null)
            {
                texture_.Dispose();
                texture_ = null;
            }
        }

        public void DeviceResizing( object sender, CancelEventArgs e )
        {
            Device device = ( Device )sender;

            Dispose();
            texture_ = new Texture(device,
                viewport_.Width, viewport_.Height, 1,
                Usage.RenderTarget, format_, Pool.Default);
            depth_ = device.CreateDepthStencilSurface(
                viewport_.Width, viewport_.Height, device.PresentationParameters.AutoDepthStencilFormat,
                MultiSampleType.None, 0, true);
            surface_ = texture_.GetSurfaceLevel(0);
        }

        public Texture texture
        {
            get{ return texture_; }
        }

        public Surface surface
        {
            get{ return surface_; }
        }

        public Surface depth
        {
            get{ return depth_; }
        }

        public Viewport viewport
        {
            get{ return viewport_; }
        }

        public float aspect
        {
            get{ return ( float )viewport_.Width / viewport_.Height; }
        }

        public void Set( Device device )
        {
            device.SetRenderTarget(0, surface);
            device.DepthStencilSurface = depth;
            device.Viewport = viewport;
        }
    }
}

コンストラクタでデバイスのみ渡した場合、デフォルトのバックバッファのサーフェイスと深度バッファを取得しています。

使い方

private RenderTarget shadow_map;
shadow_map = new RenderTarget( device, 512, 512, Format.A8R8G8B8 );
device.DeviceResizing += new CancelEventHandler( shadow_map.DeviceResizing );
if (shadow_map != null)
{
    shadow_map.Dispose();
    shadow_map = null;
}
//バックバッファへのレンダーターゲットを生成
using( RenderTarget backbuffer = new RenderTarget( device ) )
{
    //レンダーターゲットの切り替え
    shadow_map.Set( device );

    /*shadow_mapへの描画*/

    //レンダーターゲットをバックバッファに戻す
    backbuffer.Set( device );
}