[PR]
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
プログラミング、3DCGとその他いろいろについて
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
#using<System.Windows.Forms.dll>
#using<System.Drawing.dll>//ClientSizeを使うのに必要
#using<System.dll>
#include<d3d10.h>
#include<d3dx10.h<
using namespace System;
using namespace System::Windows::Forms;
struct VertexPositionColor
{
D3DXVECTOR3 Position;
D3DXVECTOR4 Color;
};
ref class Game : Form
{
ID3D10Device* graphicsDevice;
IDXGISwapChain* swapChain;
ID3D10RenderTargetView* renderTargetView;
ID3D10Effect *effect;
ID3D10InputLayout* vertexLayout;
ID3D10Buffer* vertexBuffer;
public:
void Run()
{
InitDevice();
Show();
while(Created)
{
Draw();
Application::DoEvents();
}
}
private:
void InitDevice()
{
createGraphicsDevice();
createRenderTargetView();
setupViewport();
LoadGraphicsContent();
}
void LoadGraphicsContent()
{
//シェーダーの設定
ID3D10Effect* effect;
HRESULT result = D3DX10CreateEffectFromFile(
"MyShader.fx",
NULL,
NULL,
"fx_4_0",
D3D10_SHADER_ENABLE_STRICTNESS,
0,
graphicsDevice,
NULL,
NULL,
&effect,
NULL,
NULL
);
if(FAILED(result))
throw gcnew Exception("couldn't create effect object");
this->effect = effect;
//頂点データのレイアウトの設定
D3D10_INPUT_ELEMENT_DESC vertexElements[] =
{
{"SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"Color", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0}
};
D3D10_PASS_DESC passDesc;
effect->GetTechniqueByName("MyTechnique")->GetPassByIndex(0)->GetDesc(&passDesc);
ID3D10InputLayout *vertexLayout;
result = graphicsDevice->CreateInputLayout(
vertexElements,
2,
passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize,
&vertexLayout
);
if(FAILED(result))
throw gcnew Exception("couldn't create InputLayout");
this->vertexLayout = vertexLayout;
graphicsDevice->IASetInputLayout(vertexLayout);
//頂点バッファの設定
VertexPositionColor vertices[] =
{
{D3DXVECTOR3(0, 0.5f, 0), D3DXVECTOR4(1, 1, 1, 1)},
{D3DXVECTOR3(0.5f, 0, 0), D3DXVECTOR4(0, 0, 1, 1)},
{D3DXVECTOR3(-0.5f, 0, 0), D3DXVECTOR4(1, 0, 0, 1)}
};
D3D10_SUBRESOURCE_DATA initData;
initData.pSysMem = vertices;
D3D10_BUFFER_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
bufferDesc.Usage = D3D10_USAGE_DEFAULT;
bufferDesc.ByteWidth = sizeof(VertexPositionColor) * 3;
bufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
ID3D10Buffer *vertexBuffer;
result = graphicsDevice->CreateBuffer(
&bufferDesc,
&initData,
&vertexBuffer
);
if(FAILED(result))
throw gcnew Exception("couldn't create Vertex Buffer");
this->vertexBuffer = vertexBuffer;
unsigned int stride = sizeof(VertexPositionColor);
unsigned int offset = 0;
graphicsDevice->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
//頂点バッファが三角形のリストとして描画されるようにセット
graphicsDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
~Game(){ this->!Game(); }
!Game()
{
if(graphicsDevice) graphicsDevice->ClearState();
if(vertexBuffer) vertexBuffer->Release();
if(vertexLayout) vertexLayout->Release();
if(effect) effect->Release();
if(renderTargetView) renderTargetView->Release();
if(swapChain) swapChain->Release();
if(graphicsDevice) graphicsDevice->Release();
}
void Draw()
{
float cornflowerBlue[] = {0.39, 0.58, 0.93, 1};
graphicsDevice->ClearRenderTargetView(renderTargetView, cornflowerBlue);
//三角形の3D空間の中での動きをあらわすマトリックスです。
//ここでは、時間によってz座標が[-1 ~ -3]の間を動きまわります。
//(xとyは動かない)
D3DXMATRIX worldTransform;
D3DXMatrixTranslation(
&worldTransform,
0, 0, (float)Math::Sin(D3DXToRadian(Environment::TickCount / 20.0)) - 2
);
//三角形に遠近法の効果を与えるマトリックスです。
//視野の角度は90°です。
//また、あまり見た目に影響を与えませんが、
//描画される領域は画面からの距離が[0.1f ~ 1000]に設定されていて、
//この領域を外れると、三角形は描画されなくなります。
D3DXMATRIX projectionTransform;
D3DXMatrixPerspectiveFovRH(
&projectionTransform,
D3DXToRadian(90),
(float)ClientSize.Width / ClientSize.Height,
0.1f, 1000
);
//上の2つのマトリックスを組み合わせて、シェーダーに送り込みます。
//つまり、「三角形のz座標を動かしてから、遠近法っぽい効果を適用する」
//ことを意味するマトリックスを新たに作り、
//それをエフェクトオブジェクトにセットしています。
//(実際の変換はDrawの時、HLSLのシェーダープログラムの中で)
effect->GetVariableByName("Transform")->AsMatrix()->SetMatrix(
(float*)&(worldTransform * projectionTransform)
);
effect->GetTechniqueByName("MyTechnique")->GetPassByIndex(0)->Apply(0);
graphicsDevice->Draw( 3, 0);
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;
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;
graphicsDevice->OMSetRenderTargets(1, &renderTargetView, NULL);
}
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();
}
matrix Transform;
struct VertexPositionColor
{
float4 Position : SV_Position;
float4 Color : COLOR;
};
VertexPositionColor MyVertexShader(VertexPositionColor input)
{
input.Position = mul(input.Position, Transform);
return input;
}
float4 MyPixelShader(VertexPositionColor input) : SV_Target
{
return input.Color;
}
technique10 MyTechnique
{
pass
{
SetVertexShader(CompileShader(vs_4_0, MyVertexShader()));
SetPixelShader(CompileShader(ps_4_0, MyPixelShader()));
}
}
D3DXMATRIX operator * ( CONST D3DXMATRIX& ) const; D3DXMATRIX& operator *= ( CONST D3DXMATRIX& );
D3DXMATRIX* D3DXMatrixTranslation(
D3DXMATRIX *outMatrix,
float x,
float y,
float z
);
D3DXMATRIX * D3DXMatrixPerspectiveFovRH(
D3DXMATRIX *outMatrix,
float fieldOfViewY,
float aspectRatio,
float nearPlaneDistance,
float farPlaneDistance
);
ID3D10EffectVariable* GetVariableByName(
LPCSTR name
);
ID3D10EffectMatrixVariable* AsMatrix();
HRESULT SetMatrix(
float *data
);
#using<System.Windows.Forms.dll>
#using<System.dll>
#include<d3d10.h>
#include<d3dx10.h>
using namespace System;
using namespace System::Windows::Forms;
struct VertexPositionColor
{
D3DXVECTOR3 Position;
D3DXVECTOR4 Color;
};
ref class Game : Form
{
ID3D10Device* graphicsDevice;
IDXGISwapChain* swapChain;
ID3D10RenderTargetView* renderTargetView;
ID3D10Effect *effect;
ID3D10InputLayout* vertexLayout;
ID3D10Buffer* vertexBuffer;
public:
void Run()
{
InitDevice();
Show();
while(Created)
{
Draw();
Application::DoEvents();
}
}
private:
void InitDevice()
{
createGraphicsDevice();
createRenderTargetView();
setupViewport();
LoadGraphicsContent();
}
void LoadGraphicsContent()
{
//シェーダーの設定
ID3D10Effect* effect;
HRESULT result = D3DX10CreateEffectFromFile(
"MyShader.fx",
NULL,
NULL,
"fx_4_0",
D3D10_SHADER_ENABLE_STRICTNESS,
0,
graphicsDevice,
NULL,
NULL,
&effect,
NULL,
NULL
);
if(FAILED(result))
throw gcnew Exception("couldn't create effect object");
this->effect = effect;
//描画のときデバイスに入力する頂点データのレイアウトの設定
D3D10_INPUT_ELEMENT_DESC vertexElements[] =
{
{"SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"Color", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0}
};
D3D10_PASS_DESC passDesc;
effect->GetTechniqueByName("MyTechnique")->GetPassByIndex(0)->GetDesc(&passDesc);
ID3D10InputLayout *vertexLayout;
result = graphicsDevice->CreateInputLayout(
vertexElements,
2,
passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize,
&vertexLayout
);
if(FAILED(result))
throw gcnew Exception("couldn't create InputLayout");
this->vertexLayout = vertexLayout;
graphicsDevice->IASetInputLayout(vertexLayout);
//頂点バッファの設定
VertexPositionColor vertices[] =
{
{D3DXVECTOR3(0, 0.5f, 0), D3DXVECTOR4(1, 1, 1, 1)},
{D3DXVECTOR3(0.5f, 0, 0), D3DXVECTOR4(0, 0, 1, 1)},
{D3DXVECTOR3(-0.5f, 0, 0), D3DXVECTOR4(1, 0, 0, 1)}
};
D3D10_SUBRESOURCE_DATA initData;
initData.pSysMem = vertices;
D3D10_BUFFER_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
bufferDesc.Usage = D3D10_USAGE_DEFAULT;
bufferDesc.ByteWidth = sizeof(VertexPositionColor) * 3;
bufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
ID3D10Buffer *vertexBuffer;
result = graphicsDevice->CreateBuffer(
&bufferDesc,
&initData,
&vertexBuffer
);
if(FAILED(result))
throw gcnew Exception("couldn't create Vertex Buffer");
this->vertexBuffer = vertexBuffer;
unsigned int stride = sizeof(VertexPositionColor);
unsigned int offset = 0;
graphicsDevice->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
//頂点バッファが三角形のリストとして描画されるようにセットします。
graphicsDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
~Game(){ this->!Game(); }
!Game()
{
if(graphicsDevice) graphicsDevice->ClearState();
if(vertexBuffer) vertexBuffer->Release();
if(vertexLayout) vertexLayout->Release();
if(effect) effect->Release();
if(renderTargetView) renderTargetView->Release();
if(swapChain) swapChain->Release();
if(graphicsDevice) graphicsDevice->Release();
}
void Draw()
{
float cornflowerBlue[] = {0.39, 0.58, 0.93, 1};
graphicsDevice->ClearRenderTargetView(renderTargetView, cornflowerBlue);
effect->GetTechniqueByName("MyTechnique")->GetPassByIndex(0)->Apply(0);
graphicsDevice->Draw( 3, 0);
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;
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;
graphicsDevice->OMSetRenderTargets(1, &renderTargetView, NULL);
}
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();
}
struct VertexPositionColor
{
float4 Position : SV_Position;
float4 Color : COLOR;
};
VertexPositionColor MyVertexShader(VertexPositionColor input)
{
return input;
}
float4 MyPixelShader(VertexPositionColor input) : SV_Target
{
return input.Color;
}
technique10 MyTechnique
{
pass
{
SetVertexShader(CompileShader(vs_4_0, MyVertexShader()));
SetPixelShader(CompileShader(ps_4_0, MyPixelShader()));
}
}
#using<System.Windows.Forms.dll>
#using<System.dll>
#include<d3d10.h>
#include<d3dx10.h>
using namespace System;
using namespace System::Windows::Forms;
ref class Game : Form
{
ID3D10Device* graphicsDevice;
IDXGISwapChain* swapChain;
ID3D10RenderTargetView* renderTargetView;
ID3D10Effect *effect;
ID3D10EffectTechnique *effectTechnique;
ID3D10InputLayout* vertexLayout;
ID3D10Buffer* vertexBuffer;
public:
void Run()
{
InitDevice();
Show();
while(Created)
{
Draw();
Application::DoEvents();
}
}
private:
void InitDevice()
{
createGraphicsDevice();
createRenderTargetView();
setupViewport();
LoadGraphicsContent();
}
void LoadGraphicsContent()
{
//シェーダーの設定
//「グラフィックスカードへおくる頂点バッファが
//どのように処理されて画面に表示されるか」
//を表すエフェクト・オブジェクトを
//(外部のHLSLで書かれたファイルMyShader.fxから)作り出します。
ID3D10Effect* effect;
HRESULT result = D3DX10CreateEffectFromFile(
"MyShader.fx",
NULL,
NULL,
"fx_4_0",
D3D10_SHADER_ENABLE_STRICTNESS,
0,
graphicsDevice,
NULL,
NULL,
&effect,
NULL,
NULL
);
if(FAILED(result))
throw gcnew Exception("couldn't create effect object");
this->effect = effect;
this->effectTechnique = effect->GetTechniqueByName("MyTechnique");
//描画のときデバイスに入力する頂点データのレイアウトの設定
//普通なら頂点データは座標のほかに、色やテクスチャ座標を持っていますが、
//ここでは話を単純にするために座標データのみです。
D3D10_INPUT_ELEMENT_DESC vertexElements[] =
{
{"SV_POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0}
};
D3D10_PASS_DESC passDesc;
effectTechnique->GetPassByIndex(0)->GetDesc(&passDesc);
ID3D10InputLayout *vertexLayout;
result = graphicsDevice->CreateInputLayout(
vertexElements,
1,
passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize,
&vertexLayout
);
if(FAILED(result))
throw gcnew Exception("couldn't create InputLayout");
this->vertexLayout = vertexLayout;
graphicsDevice->IASetInputLayout(vertexLayout);
//頂点バッファの設定
//3Dモデルの頂点データを格納する頂点バッファを
//グラフィックスカード内に作り、
//それをDrawのとき使われるようにセットします。
D3DXVECTOR3 vertices[] =
{
D3DXVECTOR3(0, 0.5f, 0),
D3DXVECTOR3(0.5f, 0, 0),
D3DXVECTOR3(-0.5f, 0, 0)
};
D3D10_SUBRESOURCE_DATA initData;
initData.pSysMem = vertices;
D3D10_BUFFER_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
bufferDesc.Usage = D3D10_USAGE_DEFAULT;
bufferDesc.ByteWidth = sizeof(D3DXVECTOR3) * 3;
bufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
ID3D10Buffer *vertexBuffer;
result = graphicsDevice->CreateBuffer(
&bufferDesc,
&initData,
&vertexBuffer
);
if(FAILED(result))
throw gcnew Exception("couldn't create Vertex Buffer");
this->vertexBuffer = vertexBuffer;
unsigned int stride = sizeof(D3DXVECTOR3);
unsigned int offset = 0;
graphicsDevice->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
//頂点バッファが三角形のリストとして描画されるようにセットします。
//ここでは三角形のリストですが、ほかにも
//点や線のリストとして描画されるようにセットすることもできます。
graphicsDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
~Game(){ this->!Game(); }
!Game()
{
if(graphicsDevice) graphicsDevice->ClearState();
if(vertexBuffer) vertexBuffer->Release();
if(vertexLayout) vertexLayout->Release();
if(effect) effect->Release();
if(renderTargetView) renderTargetView->Release();
if(swapChain) swapChain->Release();
if(graphicsDevice) graphicsDevice->Release();
}
void Draw()
{
float blue[] = {0, 0, 1, 1};
graphicsDevice->ClearRenderTargetView(renderTargetView, blue);
D3D10_TECHNIQUE_DESC techniqueDesc;
effectTechnique->GetDesc(&techniqueDesc);
for(int i = 0; i < techniqueDesc.Passes; i++)
{
effectTechnique->GetPassByIndex(i)->Apply(0);
graphicsDevice->Draw( 3, 0);
}
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;
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;
graphicsDevice->OMSetRenderTargets(1, &renderTargetView, NULL);
}
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();
}
float4 MyVertexShader(float4 position : SV_Position) : SV_Position
{
return position;
}
float4 MyPixelShader() : SV_Target
{
return float4(1, 1, 1, 1);
}
technique10 MyTechnique
{
pass
{
SetVertexShader(CompileShader(vs_4_0, MyVertexShader()));
SetPixelShader(CompileShader(ps_4_0, MyPixelShader()));
}
}
void OMSetRenderTargets(
UINT numViews,
ID3D10RenderTargetView *const *renderTargetViews,
ID3D10DepthStencilView *depthStencilView
);
HRESULT D3DX10CreateEffectFromFile(
LPCTSTR fileName,
CONST D3D10_SHADER_MACRO *defines,
ID3D10Include *shaderIncludeFile,
LPCSTR profile,
UINT hlslFlags,
UINT fxFlags,
ID3D10Device *graphicsDevice,
ID3D10EffectPool *effectPool,
ID3DX10ThreadPump *pump,
ID3D10Effect **outEffect,
ID3D10Blob **outErrors
);
| 変数名 | 説明 |
| D3D10_SHADER_DEBUG | デバッグ情報を挿入します。 |
| D3D10_SHADER_SKIP_VALIDATION | 過去にコンパイルできたコードをまたコンパイルする時、VALIDATIONをスキップする目的で使います。 |
| D3D10_SHADER_SKIP_OPTIMIZATION | デバッグしたい時に、最適化をスキップします。 |
| D3D10_SHADER_PACK_MATRIX_ROW_MAJOR | 例外が明示されない限り、マトリックスは行が優先的にレジスタに入ります。 |
| D3D10_SHADER_PACK_MATRIX_COLUMN_MAJOR | 例外が明示されない限り、マトリックスは列が優先的にレジスタに入ります。内積の計算方法の関係で、たいていこっちの方が効率的です。 |
| D3D10_SHADER_PARTIAL_PRECISION | 計算の正確性を削って速さを優先します。(速くなるかどうかは実際には保障されていませんが・・・。速くなる「かもしれない」レベルです) |
| D3D10_SHADER_FORCE_VS_SOFTWARE_NO_OPT | 頂点シェーダを次に高いシェーダープロファイルでコンパイルします。これは最適化をoffにしてデバッグをonにします。 |
| D3D10_SHADER_FORCE_PS_SOFTWARE_NO_OPT | ピクセルシェーダを次に高いシェーダープロファイルでコンパイルします。これは最適化をoffにしてデバッグをonにします。 |
| D3D10_SHADER_NO_PRESHADER | Preshader(CPUで出来る計算は1回だけCPUでやって残りの計算をGPUで毎回行う)を無効にします。 |
| D3D10_SHADER_AVOID_FLOW_CONTROL | 可能ならば、フロー制御を使わないようにします。 |
| D3D10_SHADER_PREFER_FLOW_CONTROL | 可能ならば、フロー制御を使うようにします。 |
| D3D10_SHADER_ENABLE_STRICTNESS | 古いシンタックスを使えなくします。(デフォルトでは、HLSLのコンパイラは古いシンタックスがあってもコンパイルしてくれます) |
| D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | 後方互換を有効にして、古いシェーダーを4_0でコンパイルできるようにします。 |
| D3D10_SHADER_IEEE_STRICTNESS | IEEEに厳密にします。 |
| D3D10_SHADER_OPTIMIZATION_LEVEL0 | 1番低い最適化のレベルです。 |
| D3D10_SHADER_OPTIMIZATION_LEVEL1 | 2番目に低い最適化のレベルです。 |
| D3D10_SHADER_OPTIMIZATION_LEVEL2 | 2番目に高い最適化のレベルです。 |
| D3D10_SHADER_OPTIMIZATION_LEVEL3 | 1番高い最適化のレベルです。パフォーマンスがとっても重要な時にだけ使います。 |
| 定数名 | 値 | 説明 |
| D3D10_EFFECT_COMPILE_CHILD_EFFECT | 1 << 0 | .fxファイルを子エフェクトにコンパイルします。子エフェクトは共有された値に対する初期化を行いません。それらは、エフェクトプールで初期化されるからです。 |
| D3D10_EFFECT_COMPILE_ALLOW_SLOW_OPS | 1 << 1 | ミュータブルなステート・オブジェクトを作ることが出来ます。 どういうことかというと、デフォルトではパフォーマンスのため、ステートオブジェクトはリテラルを使ってしか定義できないのですが、このフラグを使えばそれを無効に出来ます。 |
| D3D10_EFFECT_SINGLE_THREADED | 1 << 3 | 同じプールにエフェクトをロードしたほかのスレッドと同期しようとしません。 |
HRESULT CreateInputLayout(
const D3D10_INPUT_ELEMENT_DESC *inputElementDescs,
UINT numElements,
const void *shaderBytecodeWithInputSignature,
SIZE_T bytecodeLength,
ID3D10InputLayout **outInputLayout
);
inputElementDescsは、頂点バッファに格納される頂点のレイアウトをあらわすD3D10_INPUT_ELEMENT_DESC構造体の配列です。基本的には、頂点の構造体を構成するメンバ変数1つが1つのD3D10_INPUT_ELEMENT_DESCに対応します。例えば、頂点が3次元ベクトル1つだけならこの配列の長さも1で、もし頂点が3次元ベクトルと色を表すデータの2つを持っているならこの配列の長さは2です(そして、座標と色と、テクスチャ座標も持っていたりして3つなら・・・もちろん3です)。
D3D10_INPUT_ELEMENT_DESC 構造体
typedef struct D3D10_INPUT_ELEMENT_DESC { LPCSTR SemanticName; UINT SemanticIndex; DXGI_FORMAT Format; UINT InputSlot; UINT AlignedByteOffset; D3D10_INPUT_CLASSIFICATION InputSlotClass; UINT InstanceDataStepRate; } D3D10_INPUT_ELEMENT_DESC;
SemanticNameはHLSLでシェーダーの入力や出力の変数に付けるセマンティック、つまりこの要素がどのような役割を果たすかをあらわす文字列です。たとえば、座標を表すのなら"SV_Position"、色を表すのなら"Color"、テクスチャ座標を表すのなら"TexCoord"といった具合です。これは、大文字小文字の区別が結構ゆるいようです。MSDNにはCOLORやTEXCOORDと全部大文字で書いていますが、そうでなくてもいけます。
SemanticIndexは、セマンティックに付ける数です。この数によって、同じ名前のセマンティックでも別々に扱うことができます(Color0とColor1は違う)。セマンティックとは要素の役割をあらわすわけで、同じ役割を持つものが複数あるのは変に思えるかもしれませんが、たとえばColor0は乱反射の色、Color1は鏡面反射の色という風に分けたい時だってあるでしょう。あるいは、4x4のマトリックスを、4つの4次元ベクトルとしてシェーダーに流し込みたいとき、セマンティクスは全部同じにしてこのインデックスをそれぞれ変えて入力する、なんてのもありです(たしかXNAのサンプルにそんなのがありました)。
Formatは、この要素のフォーマットです。このメンバの型は、スワップチェーンを作るときにテクスチャを構成するピクセル(テクセル)のフォーマットを決めるのに使った、あのDXGI_FORMATです。つまり、どのくらいのサイズの要素なのかといったことを決めるんですね。
InputSlotは、頂点バッファのインデックスのようなものです(0から15まで。たいてい0)。GPUがポリゴンを描画するとき、(普通は1つだけですが)複数の頂点バッファをセットすることができます。これによって、3DのモデルをGPUの中で複製したりといったことができる(0番目の頂点バッファはモデルの頂点、1番目の頂点バッファは各モデルのインスタンスの情報)のですが、このメンバがあらわしているのはその使う頂点バッファのインデックスです。そういうわけで、普通に3Dモデルを描画したいときにはここは0です。テクニカルなことをしたいときに、ここは0以外になります。
AlignedByteOffsetは、要素間のオフセットだそうです。これはあくまでもオプションで、必ず指定しなければいけないということはありません。自分で値を指定したくない場合は、D3D10_APPEND_ALIGNED_ELEMENTをセットすると、この要素が前の要素のすぐ後にくるようになります。
InputSlotClassには、D3D10_INPUT_CLASSIFICATION列挙型、つまりD3D10_INPUT_PER_VERTEX_DATA(=0)かD3D10_INPUT_PER_INSTANCE_DATA(=1)を指定します。それぞれ、インプットデータが、頂点ごとのデータ、インスタンスごとのデータであることをあらわします。たぶんこれは3DモデルのGPUによる複製、つまりハードウェア・インスタンシングをするときに使うのではないでしょうか(たぶん)。普通に3Dモデルをあらわす頂点バッファから描画するときにはD3D10_INPUT_PER_VERTEX_DATAを指定していいでしょう。
InstanceDataStepRateは、上のメンバInputSlotClassがD3D10_INPUT_PER_INSTANCE_DATAにセットされているときだけ意味を持ちます。D3D10_INPUT_PER_VERTEX_DATAがセットされているときには、このメンバは0でなくてはいけません。このメンバが何を意味するのかというと、MSDNによると、「同じインスタンス毎のデータを使って、バッファをひとつの要素分進む前に、描画するインスタンスの数」だそうです。なんのこっちゃ……。とりあえずハードウェア・インスタンシングをしないのならあんまり意味がなさそうです。そんなに心配する必要はないでしょう。たぶん
void IASetInputLayout (
ID3D10InputLayout *inputLayout
);
HRESULT CreateBuffer(
const D3D10_BUFFER_DESC *desc,
const D3D10_SUBRESOURCE_DATA *initialData,
ID3D10Buffer **outBuffer
);
D3D10_BUFFER_DESC構造体
typedef struct D3D10_BUFFER_DESC { UINT ByteWidth; D3D10_USAGE Usage; UINT BindFlags; UINT CPUAccessFlags; UINT MiscFlags; } D3D10_BUFFER_DESC;
ByteWidthは、バッファのサイズ(単位はbyte)です。
Usageは、このバッファをどのようにつかわれるかです。
これには4つ選択肢があって、それぞれCPUやGPUからのアクセスできたりできなかったりが違います。
GPUから読む GPUから書く CPUから読む CPUから書く ステージの入力として使える(ポリゴンに貼るテクスチャとか?) ステージの出力として使える(レンダーターゲットのことかな?) D3D10_USAGE_DEFAULT ○ ○(制限あり) ○ ○ D3D10_USAGE_IMMUTABLE ○ ○ D3D10_USAGE_DYNAMIC ○(制限あり) ○ ○(サブリソースは1つだけでなければいけません。テクスチャの配列やmipmapチェーンにはできません) D3D10_USAGE_STAGING ○(制限あり) ○(制限あり) ○(制限あり) ○(制限あり)
CPUからのアクセスは、ID3D10Buffer::Map、ID3D10Texture1D::Map、ID3D10Texture2D::Map、ID3D10Texture3D::Mapメソッドで行います。
GPUからのアクセスは、ID3D10Device::CopySubresourceRegion, ID3D10Device::CopyResource、ID3D10Device::UpdateSubresourceで行えます。
ただし!Defaultの書き込みとDynamic、そしてStagingでは、最初の2つだけに制限されます。
なお、Stagingのバッファは、深度ステンシルバッファにはできませんし、マルチサンプルのレンダーターゲットにもできません。
BindFlagsは、どんなふうにバインドできるかをあらわします。
たとえば、頂点バッファとして使えるか、インデックスバッファとして使えるか、定数バッファとして使えるか…といったぐあいです。
これには、D3D10_BIND_FLAGを使います。
typedef enum D3D10_BIND_FLAG { D3D10_BIND_VERTEX_BUFFER = 0x1L, D3D10_BIND_INDEX_BUFFER = 0x2L, D3D10_BIND_CONSTANT_BUFFER = 0x4L, D3D10_BIND_SHADER_RESOURCE = 0x8L, D3D10_BIND_STREAM_OUTPUT = 0x10L, D3D10_BIND_RENDER_TARGET = 0x20L, D3D10_BIND_DEPTH_STENCIL = 0x40L } D3D10_BIND_FLAG;
CPUAccessFlagsは、CPUからの書き込みや読み込みを許可するかを指定します(D3D10_CPU_ACCESS_FLAG列挙型を使います)。
もし、CPUからまったくアクセスしないのであれば、0を指定します。
書き込みを許可するのはD3D10_CPU_ACCESS_WRITEで、これを使うとパイプラインの出力としては使えなくなり、またUsageメンバがDynamicかStagingになってなければいけません。
読み込みを許可するのはD3D10_CPU_ACCESS_READで、これを使うとパイプラインの入力としても出力としても使えなくなり、またUsageメンバがStagingになっていなければいけません。
MiscFlagsは、あんまり使われない、「その他」な機能を表すフラグです。
使わないのなら0です。
このメンバにはD3D10_RESOURCE_MISC_FLAG列挙型を使います。
typedef enum D3D10_RESOURCE_MISC_FLAG { D3D10_RESOURCE_MISC_GENERATE_MIPS = 0x1L, D3D10_RESOURCE_MISC_SHARED = 0x2L, D3D10_RESOURCE_MISC_TEXTURECUBE = 0x4L } D3D10_RESOURCE_MISC_FLAG;
D3D10_SUBRESOURCE_DATA 構造体
typedef struct D3D10_SUBRESOURCE_DATA { const void *pSysMem; UINT SysMemPitch; UINT SysMemSlicePitch; } D3D10_SUBRESOURCE_DATA;
pSysMemは、これから作るサブリソースを初期化する値です。たとえば、作るサブリソースがインデックスバッファならインデックスの配列、テクスチャなら色の配列です。
SysMemPitchは、2Dや3Dのテクスチャを作るときのみ使われます。頂点バッファやインデックスバッファでは使いません。このメンバが何を意味するのかというと、テクスチャの横幅です(ただし単位はbyteらしいです。そのままwidthとかを突っ込んではいけません。つまり、テクスチャのピクセル1つのデータのサイズを×しなきゃいけないとうことです。)。
SysMemSlicePitchは、3Dのテクスチャを作るときのみ使われます。これはテクスチャの深さ(単位はbyteで)ですね。
void IASetVertexBuffers(
UINT startSlot,
UINT numBuffers,
ID3D10Buffer *const *vertexBuffers,
const UINT *strides,
const UINT *offsets
);
void IASetPrimitiveTopology(
D3D10_PRIMITIVE_TOPOLOGY topology
);
typedef enum D3D10_PRIMITIVE_TOPOLOGY
{
D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
D3D10_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
D3D10_PRIMITIVE_TOPOLOGY_LINELIST = 2,
D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
D3D10_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13
} D3D10_PRIMITIVE_TOPOLOGY;
HRESULT Apply(UINT flags);
ID3D10EffectPass* GetPassByIndex( UINT index );
ID3D10EffectTechnique* GetTechniqueByName(
LPCSTR name
);
void Draw(
UINT vertexCount,
UINT startVertexLocation
);
さっそく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();
}
青くウィンドウのクライアント領域が塗りつぶされました。
成功です。
次回にでもこの上にポリゴンを描いてみましょうかね。
ここからDirectX10を使っているのでコンパイルにはd3d10.libが必要です。
cl /clr dx10Test.cpp d3d10.lib
大まかな説明
大まかな流れは次のようになります。
1.ID3D10Device、IDXGISwapChain、ID3D10RenderTargetViewオブジェクトをつくっていろいろ設定を行います。
2.(メッセージループ中に)ウィンドウのクライアント領域を青でクリア。この作業には1で作った3つのオブジェクト全部を使います。
3.クリーンナップ。 「1.」の後始末。
ID3D10DeviceとはDirect3D10で描画に使うハードウェア(ビデオカード)の描画機能をあらわすインターフェースです(ただし!ハードウェアを使わずにソフトウェアで機能をエミュレートすることもできます。そうした場合実行速度が遅くなりますが、DirectX10対応のビデオカードが無くても動きます)。
描画を行うメソッドはこのインターフェースが持っています。
今回はやりませんが、ポリゴンとかを描画するのに使うのはこのインターフェースです。
IDXGISwapChainは、乱暴に説明するなら、Direct3D10でダブルバッファリングを行うためのインターフェースです。
ダブルバッファリング――つまりプログラムで描画するバッファ(バック・バッファ)と、実際にディスプレイ画面に描画されるバッファ(フロント・バッファ)の2つに分かれています。
このインターフェースは多くの場合この2つのバッファを持つことになります(しかし、3つ以上にすることも可能です。そうした場合、バッファが"鎖"(チェーン)のようにつながっているように見えることがわかると思います)。
プログラムはバック・バッファに対して描画を行います。
そして、描画が完了するとそのバック・バッファを今度はフロント・バッファに変えます(そうすると描画したものがディスプレイ画面に表示されるようになりますからね)。
同時に、それまでフロント・バッファだったものは今度はバック・バッファに変えます。
つまり、バック・バッファとフロント・バッファの役割を交代(スワップ)することによって、描画結果を画面に反映させているのです。(まるではたおり機で布をバッタンバッタンと織っていくような感じですね。あれは縦糸を上下の2つのグループに分けて、横糸を通したらこの2つのグループを入れ替えて…というふうにして布を織っていくのです。)
| バッファ1 | バッファ2 | |
| 1回目のDraw | バック・バッファ(プログラムが描画を行う) | フロント・バッファ(ディスプレイに表示される) |
| 2回目のDraw | フロント・バッファ | バック・バッファ |
| 3回目のDraw | バック・バッファ | フロント・バッファ |
HRESULT D3D10CreateDeviceAndSwapChain(
IDXGIAdapter *adapter,
D3D10_DRIVER_TYPE driverType,
HMODULE softwareRasterizerDll,
UINT deviceCreationFlags,
UINT sdkVersion,
DXGI_SWAP_CHAIN_DESC *swapChainDescription,
IDXGISwapChain **outSwapChain,
ID3D10Device **outDevice
);
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 | 将来のために予約されています。 |
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 | 予約されています。 |
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;
WidthとHeightは解像度の横幅と縦幅です。
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です。
| 説明 | |
| DXGI_USAGE_SHADER_INPUT | シェーダーへの入力として使います。 |
| DXGI_USAGE_RENDER_TARGET_OUTPUT | レンダーターゲット、つまりディスプレイへの出力として使います。 |
| DXGI_USAGE_BACK_BUFFER | バックバッファとして使います。 |
| DXGI_USAGE_SHARED | 共有します。 |
| DXGI_USAGE_READ_ONLY | 読み込み専用です。 |
typedef enum DXGI_SWAP_EFFECT
{
DXGI_SWAP_EFFECT_DISCARD = 0,
DXGI_SWAP_EFFECT_SEQUENTIAL = 1
} DXGI_SWAP_EFFECT, *LPDXGI_SWAP_EFFECT;
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を使います)。 |
HRESULT GetBuffer(
UINT bufferIndex,
FEFIID bufferInterfaceType,
void **outBackBuffer
);
HRESULT CreateRenderTargetView(
ID3D10Resource *resource,
const D3D10_RENDER_TARGET_VIEW_DESC *description,
ID3D10RenderTargetView **outRenderTargetView
);
void RSSetViewports(
UINT numViewports,
const D3D10_VIEWPORT *viewports
);
typedef struct D3D10_VIEWPORT { INT TopLeftX; INT TopLeftY; UINT Width; UINT Height; FLOAT MinDepth; FLOAT MaxDepth; } D3D10_VIEWPORT;
TopLeftXとTopLeftYは、描画する領域の左上の点を表します。(こんな変数名にしないで単にX, Yでいいような気もするのですが・・・)
Width、Heightは描画する領域のサイズを表します。
MinDepthとMaxDepthは深度バッファのとる値の範囲です。(深度バッファとはピクセルごとに用意される値で、そのピクセルのカメラからの距離を表します(ただし0から1まで)。これの値を使って、デバイスは近くのポリゴンを、遠くのポリゴンより優先して描画します。これがないと近くの壁が遠くのキャラクターの後ろに描画されると言うめちゃくちゃなことになります。)
これは両方とも0と1の間でなければなりません。
普通は単純に、MinDepth = 0、MaxDepth = 1としていいでしょう。
void ClearRenderTargetView(
ID3D10RenderTargetView *renderTargetView,
const FLOAT colorRGBA[4]
);
HRESULT Present(
UINT syncInterval,
UINT flags
);
void ClearState();
最近忙しかったので久々の投稿です。
こう時間が空くとどうも精神的にやりにくくなりますね・・・。
さて、前々から思っていたのですが、そろそろDirectX10をやってみたいと思います。
言語はC#・・・を使いたいところですが、ManagedDirectXは消滅してしまったので、泣く泣くC++/CLIを使います。
OSはVistaオンリーです。DirectX10はXPでは使えません。
まずはSDKのダウンロードです。
現在最新のDirectX のSDKは(November 2007)です。
Novemberって何月だっけ・・・と思って辞書で引くとなんと11月、つまり今月です!
良いタイミングでDirectX10をはじめたことになります。
幸先良いスタートです。
また、Windows Platform SDKをインストールする必要もあるようです。(もちろんWindows Vista用のです)
なんせVisual C++ ExpressにはWindows.hが付いてきません。
DirectX10のサンプルを動かすにはWindows SDKのIncludeファイルとLibファイルが必要です。
で、Windows SDKのIncludeファイルととLibファイルをC++/CLIのコンパイラから使えるようにします。(単にコピー&ペーストでいいでしょう。(いいわけない。環境変数LIBとINCLUDEでそれぞれのディレクトリのパスをセットしてやりましょう。)いちおうWindows SDKには"Integrate Windows SDK with Visual Studio 2005"というのが付いていますが、cl.exeには効果が無いように見えます。)
これで準備は整いました(たぶん)。
さっそくやってみましょう!
#using<System.Windows.Forms.dll>
#using<System.dll>
using namespace System::Windows::Forms;
int main()
{
Form ^form = gcnew Form();
form->Show();
while(form->Created)
{
Application::DoEvents();
}
}
#using<System.Windows.Forms.dll>
#using<System.dll>
using namespace System::Windows::Forms;
ref class Game : Form
{
public:
void Run()
{
Show();
while(Created)
{
Application::DoEvents();
}
}
};
int main()
{
Game ^game = gcnew Game();
game->Run();
}