忍者ブログ

Memeplexes

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

DirectX10 + C++/CLI デバイスの作成と背景のクリア

さっそくDirect3D10のデバイスを作って、ウィンドウのクライアントエリアを(青く)クリアしてみました。

デバイスを作るといっても、残念ながらぼくはDirectX10対応のグラフィックスカードを持っていないので、(リファレンス・デバイスを使って)ソフトウェアで動作をエミュレートすることにします。

解説はややこしくなりそうなので、まずはコードと結果ををのせます。

Dx10Test.cpp


#using<System.Windows.Forms.dll>
#using<System.dll>

#include<d3d10.h>

using namespace System;
using namespace System::Windows::Forms;


ref class Game : Form
{
	//描画を行うデバイスです。
	//これを使ってポリゴンとかいろいろなものを描画します。
	ID3D10Device* graphicsDevice;

	//スワップ・チェーン
	//これはダブルバッファリングを行うための2つのバッファを持っています。
	//(片方が描画対象、もう片方はディスプレイに表示されるバッファ)
	//この2つのバッファは、描画が終わって実際にディスプレイに表示するときに
	//役割が交代(スワップ)します。
	//また、実際には2より多くのバッファが鎖(チェーン)のように
	//続くように設定することもできます。
	IDXGISwapChain* swapChain;

	//描画する対象です。
	//画面をある一色で塗りつぶ(クリア)したいときには
	//これに対してクリアします。
	ID3D10RenderTargetView* renderTargetView;

public:
	void Run()
	{
		InitDevice();
		Show();

		while(Created)
		{
			Draw();
			Application::DoEvents();
		}

		CleanupDevice();
	}

private:

	void InitDevice()
	{
		createGraphicsDevice();

		createRenderTargetView();

		setupViewport();
	}

	void CleanupDevice()
	{
		if(graphicsDevice) graphicsDevice->ClearState();
		if(renderTargetView) renderTargetView->Release();
		if(swapChain) swapChain->Release();
		if(graphicsDevice) graphicsDevice->Release();
	}

	void Draw()
	{
		float blue[] = {0, 0, 1, 1};
		graphicsDevice->ClearRenderTargetView(renderTargetView, blue);
		swapChain->Present(0, 0);
	}

	void createGraphicsDevice()
	{
		DXGI_SWAP_CHAIN_DESC swapChainDescription;
		ZeroMemory(&swapChainDescription, sizeof(swapChainDescription));
		swapChainDescription.BufferCount = 1;
 		swapChainDescription.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
 		swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		swapChainDescription.OutputWindow = (HWND)(this->Handle.ToInt32());
		swapChainDescription.SampleDesc.Count = 1;
		swapChainDescription.Windowed = TRUE;


		//C++/CLIでは、クラスのメンバー変数のポインタを
		//直接&graphicsDeviceとか&swapChain
		//というふうにして関数に渡すことができません。
		//一方、ローカルな変数ならそれができます。
		//そこでここでは間接的に、このクラスのメンバー、
		//graphicsDeviceとswapChainに値をセットすることにします。
		ID3D10Device *graphicsDevice;
		IDXGISwapChain *swapChain;

	    	HRESULT result = D3D10CreateDeviceAndSwapChain(
			NULL,
			D3D10_DRIVER_TYPE_REFERENCE,
			NULL, 
			0, 
			D3D10_SDK_VERSION,
			&swapChainDescription,
			&swapChain,
			&graphicsDevice
			);

    		if( FAILED(result) )
		throw gcnew Exception("Couldn't create Graphics Device");

		this->graphicsDevice = graphicsDevice;
		this->swapChain = swapChain;
	}

	void createRenderTargetView()
	{
		ID3D10Texture2D *backBuffer;
		HRESULT result = swapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&backBuffer);

		if( FAILED(result) )
		throw gcnew Exception("Couldn't get BackBuffer from swap chain.");

		ID3D10RenderTargetView* renderTargetView;
		result = graphicsDevice->CreateRenderTargetView(backBuffer, NULL, &renderTargetView);
		backBuffer->Release();

		if( FAILED(result) )
		throw gcnew Exception("Couldn't create RenderTargetView.");

		this->renderTargetView = renderTargetView;
	}

	void setupViewport()
	{
		D3D10_VIEWPORT viewport;
		viewport.Width = Width;
		viewport.Height = Height;
		viewport.MinDepth = 0.0f;
		viewport.MaxDepth = 1.0f;
		viewport.TopLeftX = 0;
		viewport.TopLeftY = 0;
		graphicsDevice->RSSetViewports( 1, &viewport );
	}
};

int main()
{
	Game ^game = gcnew Game();
	game->Run();
}

 CreatedDevice.jpg

青くウィンドウのクライアント領域が塗りつぶされました。
成功です。
次回にでもこの上にポリゴンを描いてみましょうかね。

ここからDirectX10を使っているのでコンパイルにはd3d10.libが必要です。

cl /clr dx10Test.cpp d3d10.lib


大まかな説明
 
大まかな流れは次のようになります。

1.ID3D10DeviceIDXGISwapChainID3D10RenderTargetViewオブジェクトをつくっていろいろ設定を行います。

2.(メッセージループ中に)ウィンドウのクライアント領域を青でクリア。この作業には1で作った3つのオブジェクト全部を使います。

3.クリーンナップ。 「1.」の後始末。


ID3D10DeviceとはDirect3D10で描画に使うハードウェア(ビデオカード)の描画機能をあらわすインターフェースです(ただし!ハードウェアを使わずにソフトウェアで機能をエミュレートすることもできます。そうした場合実行速度が遅くなりますが、DirectX10対応のビデオカードが無くても動きます)
描画を行うメソッドはこのインターフェースが持っています。
今回はやりませんが、ポリゴンとかを描画するのに使うのはこのインターフェースです。

IDXGISwapChainは、乱暴に説明するなら、Direct3D10でダブルバッファリングを行うためのインターフェースです。
ダブルバッファリング――つまりプログラムで描画するバッファ(バック・バッファ)と、実際にディスプレイ画面に描画されるバッファ(フロント・バッファ)の2つに分かれています。
このインターフェースは多くの場合この2つのバッファを持つことになります(しかし、3つ以上にすることも可能です。そうした場合、バッファが"鎖"(チェーン)のようにつながっているように見えることがわかると思います)

プログラムはバック・バッファに対して描画を行います。
そして、描画が完了するとそのバック・バッファを今度はフロント・バッファに変えます(そうすると描画したものがディスプレイ画面に表示されるようになりますからね)。
同時に、それまでフロント・バッファだったものは今度はバック・バッファに変えます。
つまり、バック・バッファとフロント・バッファの役割を交代(スワップ)することによって、描画結果を画面に反映させているのです。(まるではたおり機で布をバッタンバッタンと織っていくような感じですね。あれは縦糸を上下の2つのグループに分けて、横糸を通したらこの2つのグループを入れ替えて…というふうにして布を織っていくのです。)

  バッファ1 バッファ2
1回目のDraw バック・バッファ(プログラムが描画を行う) フロント・バッファ(ディスプレイに表示される)
2回目のDraw フロント・バッファ バック・バッファ
3回目のDraw バック・バッファ フロント・バッファ

ちなみに、Iのあとの最初の4文字、"DXGI"というのは"DirectX Graphics Infrastructure"の略です。
DXGIの主な目的はDirect3Dより低レベル(カーネルモードやシステムハードウェアと通信したり)で、あんまり変化しない部分の仕事をすることだそうです(MSDNいわく)。


ID3D10RenderTargetViewはID3D10Deviceで描画を行う対象(レンダーターゲット)です(実体はテクスチャ)。ここではこれは画面(正確には画面に描画される前のバック・バッファ)ですが、単なるテクスチャをレンダーターゲットにして、そのテクスチャを何かのポリゴンに貼り付けて鏡みたいな効果を出すっていうのもアリでしょう。

さて、このインターフェースの名前は単なる「レンダーターゲット」ではなく、「レンダーターゲットビュー」となっています。
この「ビュー」というのは何かというと、これはDirect3D10で使うリソース(テクスチャとか頂点バッファとか…)がどのようにデバイスで解釈されるかを表します(C言語系でいう「型」みたいなものですね。ただし、「ビュー」は動的に変更することが出来ますし、複数のビューを1つのリソースが持つことが出来ます)。
ここでは、テクスチャをレンダーターゲットとして扱うため、「RenderTargetView」です。
(他にも、リソースを深度ステンシルバッファとして扱うインターフェース「ID3D10DepthStencilView」や、シェーダで使うリソースとして扱う「ID3D10ShaderResourceView」があります)

Direct3D10ではリソースは単なるビットのかたまりで、型が無いように設定できます。
1つのリソースを、複数の種類のものとして扱うことが出来ます(1つのリソースは複数のビューを持つことが出来ます)。
テクスチャとしても扱えるし、頂点バッファとしても扱えるようにリソースを作ることが出来るのです。
そうすれば、「ピクセルシェーダを使って頂点バッファに何かのモデルの頂点を描き出す」、なんてことが事が出来ます。
より柔軟なことが出来るようになるとい言うわけです。




デバイスとスワップチェーンを作る

ID3D10DeviceとIDXGISwapChainのオブジェクトを作るにはD3D10CreateDeviceAndSwapChain関数を使います。(いちおう、D3D10CreateDeviceとIDXGIFactory::CreateSwapChainを使って別々に作ることも可能です。しかし、両方とも使うのなら同時に作った方がいいでしょう。MSDNいわく、別々に作るのはもう一方を必要としない時だとかなんとか・・・)

 

HRESULT D3D10CreateDeviceAndSwapChain(
    IDXGIAdapter *adapter,
    D3D10_DRIVER_TYPE driverType,
    HMODULE softwareRasterizerDll,
    UINT deviceCreationFlags,
    UINT sdkVersion,
    DXGI_SWAP_CHAIN_DESC *swapChainDescription,
    IDXGISwapChain **outSwapChain,
    ID3D10Device **outDevice
);


adapterはビデオカード(あるいはマザーボードの描画する機能)をあらわします。
ふつうはビデオカードは1枚だけですが、複数枚ある場合もありますからね。
このadapterに対応したID3D10Deviceが作られるのです。
ビデオカードが一枚だけの場合(たいていそうです)はNULLを渡すことが出来ます。

driverTypeはデバイスのタイプです。
ID3D10Deviceがビデオカードを使うか、あるいはデバッグやデモ用にソフトウェアでビデオカードをエミュレートするかといったことを決めます。

この引数の型はD3D10_DRIVER_TYPE列挙型で、4つのメンバ(定数?)があります。
typedef enum D3D10_DRIVER_TYPE
{
    D3D10_DRIVER_TYPE_HARDWARE = 0,
    D3D10_DRIVER_TYPE_REFERENCE = 1,
    D3D10_DRIVER_TYPE_NULL = 2,
    D3D10_DRIVER_TYPE_SOFTWARE = 3
} D3D10_DRIVER_TYPE;

  説明
HARDWARE ハードウェア(ビデオカード)を使ってID3D10Deviceを作ります。実用向け。
REFERENCE ソフトウェアでDirect3D10対応ビデオカードをエミュレートします。そのためDirect3D10対応ビデオカードが無くってもデモを動かすことが出来て便利です(でも遅い)。
NULL 実際の描画能力のないデバイスを作ります。
SOFTWARE 将来のために予約されています。


softwareRasterizerDllは、ソフトウェアラスタライザを実装したDllへのハンドルです。
ソフトウェアラスタライザを使わない時(たいていそうでしょうが・・・)はNULLです。


deviceCreationFlagsは、デバイスに与える追加の機能(デバッグしやすくしたりとか…)を表します。

この引数にはD3D10_CREATE_DEVICE_FLAG列挙型を使います。
typedef enum D3D10_CREATE_DEVICE_FLAG
{
    D3D10_CREATE_DEVICE_FLAG_SINGLETHREADED = 0x1,
    D3D10_CREATE_DEVICE_FLAG_DEBUG = 0x2,
    D3D10_CREATE_DEVICE_FLAG_SWITCH_TO_REF = 0x4,
    D3D10_CREATE_DEVICE_FLAG_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS = 0x8
} D3D10_CREATE_DEVICE_FLAG;


  説明
SINGLETHREADED デバイスのスレッドセーフティを無効にします。(Direct3D10ではデフォルトでスレッドセーフ)
DEBUG デバッグレイヤーをデバイスに追加します。
それによってエラーレポートの文字列を出力(ID3D10InfoQueueを使う)できるようになったりします。
SWITCH_TO_REF デバイスがハードウェアかリファレンスかを変えることができるようになります(ID3D10SwitchToRef::SetUseRefを使う)。
PREVENT_INTERNAL_THREADING_OPTIMIZATIONS 予約されています。

sdkVersionはSDKのバージョンです(そのまんま……)。
これはd3d10.hのなかで定義されている定数、D3D_SDK_VERSIONを使います。


swapChainDescriptionはどのようなスワップチェーンを作るかを表します。

outSwapChainはこの関数の結果を格納するためのポインタです。この引数の表すアドレスに、スワップチェーンへのポインタが書き込まれます。

outDeviceはこの関数の結果を格納するためのポインタです。この引数の表すアドレスに、デバイスへのポインタが書き込まれます。


DXGI_SWAP_CHAIN_DESC構造体

6番目の引数、swapChainDescriptionについてもう少しくわしく見てみます。
これはどのようなスワップチェーンを作るかを表すDXGI_SWAP_CHAIN_DESC構造体へのポインタなので、まずはこの構造体を見てみます。
typedef struct DXGI_SWAP_CHAIN_DESC
{
    DXGI_MODE_DESC BufferDesc;
    DXGI_SAMPLE_DESC SampleDesc;
    DXGI_USAGE BufferUsage;
    UINT BufferCount;
    HWND OutputWindow;
    BOOL Windowed;
    DXGI_SWAP_EFFECT SwapEffect;
    UINT Flags;
} DXGI_SWAP_CHAIN_DESC;



BufferDescはスワップチェーンがどのようなバッファを持つかを表します。
バッファの大きさやフォーマット、拡大する時にはどのように拡大するかといったことを表します。

BufferDescの型はディスプレイのモードを表すDXGI_MODE_DESC構造体です。

typedef struct DXGI_MODE_DESC {
    UINT Width;
    UINT Height;
    DXGI_RATIONAL RefreshRate;
    DXGI_FORMAT Format;
    DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
    DXGI_MODE_SCALING Scaling;
} DXGI_MODE_DESC, *LPDXGI_MODE_DESC;

WidthHeightは解像度の横幅と縦幅です。

RefreshRateは一秒間にリフレッシュする回数を表します。この型は分数(Rational)を表すDXGI_RATIONAL構造体で、2つのUINT型のメンバー、Numerator(分子)とDenominator(分母)を持っています。MSDNのチュートリアルを見る限りでは分子を60、分母を1にセットするのが普通なようです(つまり1秒間に60回リフレッシュ)。でもそれじゃあ構造体なんて使わなくって、ただのUINTでいいような気も……。
typedef struct DXGI_RATIONAL {
    UINT Numerator;
    UINT Denominator;
} DXGI_RATIONAL, *LPDXGI_RATIONAL;


Formatは、データのフォーマットを表します。
この型はDXGI_FORMAT列挙型です。
メンバーを紹介したいのですが、死ぬほど多い(90個)のでリンクだけ。
メンバー名を見たところ、「DXGI_FORMAT_[データのレイアウト]_[型]」という法則があるようですね(例えば、DXGI_FORMAT_R32G32B32_FLOATと言った具合です)

ScanlineOrderingはラスターがイメージを作り出す方法です。この型はDXGI_MODE_SCANLINE_ORDER列挙型です。

定数名 説明
DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED 順番を指定しません。 0
DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE 最初から最後まで順番に、スキップすることなく。 1
DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST 上のほうのフィールドから始めます。 2
DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST 下の方のフィールドから始めます。 3


Scalingはどのようにイメージを拡大するかを表します(指定されたモニターの解像度に合わせなければいけませんからね)。
この型はDXGI_MODE_SCALING列挙型です。

定数名 説明
DXGI_MODE_SCALING_UNSPECIFIED 拡大の方法を指定しません 0
DXGI_MODE_SCALING_CENTERED 拡大しません。イメージはディスプレイの中央に表示されます。 1
DXGI_MODE_SCALING_STRETCHED 引き伸ばされて拡大されます。 2



さて、DXGI_SWAP_CHAIN_DESC構造体のメンバーの説明に戻ります。(こういうネストっていやですね!)
次はSampleDescです。

SampleDescは、このスワップチェーンでアンチ・エイリアシング(画像のギザギザを無くして滑らかに)する方法をあらわします。
アンチエイリアシングするにはいくつかの点の色を採ってきて(サンプルする)、その平均値の色を使います。

このメンバの型はそのマルチ・サンプリングを表すDXGI_SAMPLE_DESC構造体です。

typedef struct DXGI_SAMPLE_DESC {
    UINT Count;
    UINT Quality;
} DXGI_SAMPLE_DESC, *LPDXGI_SAMPLE_DESC;

Countはピクセル1つあたりのマルチサンプルの数です。デフォルトでは1で、アンチエイリアシングを行いません。

Qualityはイメージのクオリティレベルです。
値の範囲は0 ~ (ID3D10Device::CheckMultisampleQualityLevelsの戻り値 - 1)までです。
デフォルトでは0です。


BufferUsageはこのスワップチェーンのバックバッファの使用目的と、CPUアクセスオプションを表します。
この引数の型はD3D10のリソースの使い方を表すDXGI_USAGEですが、これは意外なことに列挙型ではなく、typedefでUINTから作られた型です(といっても注意しなきゃいけないようなことは無いようですが・・・)

  説明
DXGI_USAGE_SHADER_INPUT シェーダーへの入力として使います。
DXGI_USAGE_RENDER_TARGET_OUTPUT レンダーターゲット、つまりディスプレイへの出力として使います。
DXGI_USAGE_BACK_BUFFER  バックバッファとして使います。
DXGI_USAGE_SHARED  共有します。
DXGI_USAGE_READ_ONLY 読み込み専用です。


BufferCountは・・・これは2つの情報があってどっちが正しいのかよくわかりません。
msdnには、これはフロントバッファも含めた、全てのバッファの数だと書いてあります。
でもmsdnのチュートリアルではこのメンバに1を代入しているわけですから、これではバックバッファが作られないことになってしまいます。
これではダブルバッファリングできません。(いや、でももしかするとバックバッファの数を0にしていすると自動的に1つ作ってくれる仕様なのかもしれません。うーん…)

一方、つい最近読んだ『Beginning DirectX 10 Game Programming』や、DXTen.comのwikiには、これはバックバッファの数だと書いてあります。
msdnのチュートリアルから考えて、こっちの方が筋が通っているように思えます。
こっちの解釈ならこのメンバに1を代入してもバックバッファとフロントバッファの両方が作られますからね。
それにDirectXの古いバージョンではこっちでしたし・・・。

OutputWindowは、D3D10で使うウィンドウへのハンドルです。
ここではWindows.Formsを使っているのでControl.Handleプロパティの値を使えばいいでしょう。

Windowedは、trueならウィンドウモードになって、falseならフルスクリーンモードになります。

SwapEffectは、どのようにバックバッファとフロントバッファをスワップ(入れ替え。ダブルバッファリングで、描画を完了した時にその描画を実際の画面に反映させる時に行う)するかを表します。
typedef enum DXGI_SWAP_EFFECT
{
    DXGI_SWAP_EFFECT_DISCARD = 0,
    DXGI_SWAP_EFFECT_SEQUENTIAL = 1
} DXGI_SWAP_EFFECT, *LPDXGI_SWAP_EFFECT;

DXGI_SWAP_EFFECT_DISCARDは、バックバッファ(だったもの)がディスプレイに表示したあとは、その内容は捨てられる、保障されないことを表します。(「ディスプレイに表示」とは、ようするにスワップのことです。)
まあ、バックバッファと言うのは描画結果をディスプレイに表示するまでの一時的なバッファですから、表示された後どうなっても問題ないでしょう。
実行速度は速いですし、普通はこれをセットします。

DXGI_SWAP_EFFECT_SEQUENTIALは、DISCARDの逆(?)で、ディスプレイに表示した後も、バックバッファ(だったもの)の内容が変わらないことを意味します。

Flagsは、このスワップチェーンがどんな風に働くかを表す追加の情報です。
typedef enum DXGI_SWAP_CHAIN_FLAG
{
    DXGI_SWAP_CHAIN_FLAG_NONPREROTATED = 1,
    DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH = 2
} DXGI_SWAP_CHAIN_FLAG, *LPDXGI_SWAP_CHAIN_FLAG;

  説明
DXGI_SWAP_CHAIN_FLAG_NONPREROTATED これはフルスクリーンモードでしか意味を成さないのですが、自動的なイメージの回転をオフにします。つまり、ゲームが回転して表示しなきゃいけないような時に、フロントバッファからモニターへ表示する時の回転をしません。
DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH ディスプレイモード(DXGI_MODE_DESC)を途中で変えることができることを表します(変えるにはIDXGISwapChain::ResizeTargetを使います)。



メソッド IDXGISwapChain::GetBuffer

このプログラムで一番最初に使っているD3Dのメソッドは、IDXGISwapChain::GetBufferです。
このメソッドは、スワップチェーンのバックバッファの1つを取得します。
HRESULT GetBuffer(
    UINT bufferIndex,
    FEFIID bufferInterfaceType,
    void **outBackBuffer
);

bufferIndexは、取得するバックバッファのインデックスです。

bufferInterfaceTypeは、バッファのインターフェースの型です。

outBackBufferは、このメソッドで取得するバックバッファを入れるための変数へのポインタです。
ここに結果が入ります。


メソッド ID3D10Device::CreateRenderTargetView

次に使っているメソッドはID3D10Device::CreateRenderTargetViewです。
これは「あるリソース(普通はテクスチャでしょうが、トリッキーな方法を使いたいのなら、たとえば頂点バッファでもOK)をレンダーターゲットとして扱う」ことを表すビューを作り出します。

このサンプルでは、上記のIDXGISwapChain::GetBufferで取り出したバックバッファから、レンダーターゲットビューを作り出しています。

HRESULT CreateRenderTargetView(
    ID3D10Resource *resource,
    const D3D10_RENDER_TARGET_VIEW_DESC *description,
    ID3D10RenderTargetView **outRenderTargetView
);

resourceは、このメソッドでビューを作るリソースです。
このリソースは、レンダーターゲットとして扱うことができるようになります。
ただし、そのリソースは、作られるときにD3D10_BIND_RENDER_TARGETフラグを指定されていなければいけません。

descriptionは、リソースがどのようなレンダーターゲットとして扱われるようになるかを表します。
リソースの作成時にフォーマットの型を指定していない時(TYPELESSのフォーマットを指定した時)には、ここで指定できます。
このパラメーターにNULLを指定すると、mipmapレベル0(つまり一番大きい、縮小されていないテクスチャ)にアクセスするようになります。
普通の用途ならNULLでいいでしょう。

outRenderTargetViewは、このメソッドで作ったレンダーターゲットビューを格納するための変数へのポインタです。
ここに結果が入ります。


メソッド ID3D10Device::RSSetViewports

グラフィックスデバイスにビューポート(ウィンドウ中のどの領域に描画されるかを表す構造体。二人対戦型ゲームで、ウィンドウの画面を真ん中で半分に分割したい時に使います。ビューポートをウィンドウの半分のサイズにして、それぞれのプレイヤー用に位置は変えつつ、2回描画すればいいのです。)をセットします。
DirectX9まではこれはデフォルトの値でよかったはずですが、DirectX10ではどうやら必ずプログラマがセットしてやらなければいけないようです。

なお、このメソッドは、頭に「RS」というのをくっつけていますが、これはラスタライザー・ステージ(rasterizer stage : 頂点データからピクセルデータを作り出すステージ(まだ色は決まってない。ピクセルのテクスチャ座標とかはこれで決まる)。)の略です。
ラスタライザー・ステージで使うパラメーターをセットしているので、こういう名前になっているのでしょう。
実際、ID3D10Deviceには、ステージの略称が頭にくっついたメソッドが他にもまだまだたくさんあります。

void RSSetViewports(
    UINT numViewports,
    const D3D10_VIEWPORT *viewports
);

numViewportsはセットするビューポートの数です。
普通は2番目の引数viewports配列の長さになるでしょうね。

viewportsはセットするビューポートを格納する配列です。

ビューポートはD3D10_VIEWPORT構造体によって定義されています。

typedef struct D3D10_VIEWPORT {
    INT TopLeftX;
    INT TopLeftY;
    UINT Width;
    UINT Height;
    FLOAT MinDepth;
    FLOAT MaxDepth;
} D3D10_VIEWPORT;


TopLeftXTopLeftYは、描画する領域の左上の点を表します。(こんな変数名にしないで単にX, Yでいいような気もするのですが・・・)

WidthHeightは描画する領域のサイズを表します。

MinDepthMaxDepthは深度バッファのとる値の範囲です。(深度バッファとはピクセルごとに用意される値で、そのピクセルのカメラからの距離を表します(ただし0から1まで)。これの値を使って、デバイスは近くのポリゴンを、遠くのポリゴンより優先して描画します。これがないと近くの壁が遠くのキャラクターの後ろに描画されると言うめちゃくちゃなことになります。)
これは両方とも0と1の間でなければなりません。
普通は単純に、MinDepth = 0、MaxDepth = 1としていいでしょう。


メソッド ID3D10Device::ClearRenderTargetView

ようやく描画関連のメソッドです。
このメソッド、ID3D10Device::ClearRenderTargetViewは、レンダーターゲットビューを指定した一色で塗りつぶ(クリア)します。
普通このメソッドは、描画の一番初めに呼び出します。

void ClearRenderTargetView(
    ID3D10RenderTargetView *renderTargetView,
    const FLOAT colorRGBA[4]
);

renderTargetViewはクリアするレンダーターゲットです。
ここに指定したレンダーターゲットが、colorRGBAで塗りつぶされます。

colorRGBAは塗りつぶす色を表します。これはfloatの配列(長さ4)ですが、内訳は、{赤、緑、青、アルファ}です。

メソッド IDXGISwapChain::Present

このメソッドは描画結果をユーザーに見えるようにします。
それまではバックバッファに対して描画していたので、ユーザーには見えないというわけです。

このメソッドはバックバッファとフロントバッファを入れ替え、新しい描画結果を、ユーザーが見えるようにするのです。

HRESULT Present(
    UINT syncInterval,
    UINT flags
);

syncIntervalは、垂直ブランクとどのようにシンクロするかを表します(垂直帰線区間)。

これに0を指定すると、シンクロは行われずに、すぐにpresentします。
1,2,3,4だとその分の垂直ブランクの後に、描画結果を見えるようにする作業をシンクロします。

flagsはオプションです。0でいいでしょう。(msdnのDXGI_PRESENTの書き方が悪いんです!これじゃわかりませんって!)

メソッド ID3D10Device::ClearState

このメソッドはグラフィックスデバイスを最初の、作った直後の状態に戻します。
セットしたリソースやビューポート、さらに他のもろもろの設定をNULLにします。
サンプルを見るに、後始末をする前に呼ぶようですね。
void ClearState();


拍手[1回]

PR