前回までで、ポリゴンを表示して自由に座標変換(2D)できるようになりました。
今後はそれを応用して3D座標変換をして、3Dゲームの絵づくりをしていきます。
なのですが、3D座標変換の前に、これまで表示している三角形に色をのせて、より立体的な構成を把握しやすくしましょう。
そのために、今回は頂点カラーを使って三角形に色付けしていきます。
前回の記事:
【3Dゲーム開発#05】ポリゴンの座標変換② : 移動・回転・スケールの2D変換
前回までで、DirectXMathを使って行列の用意、シェーダーで座標変換、ができました。今回は、「移動」「回転」「スケール」それぞれの2D変換について詳しく見ていきましょう。また、座標変換は、単体で終わるものではなく、移動・回転・スケール...
3Dゲーム開発記事のまとめ:「3Dゲーム開発」
頂点カラーとは
頂点カラーとは、その名の通り頂点単位での色設定です。
頂点(1つの点)に色をつけたところで、ポリゴンの色はどうなるの?
と疑問に思うかもしれませんが、描画処理で頂点間の色は補間され、きれいなグラデーションのような色付けがされます。
いかが各頂点のカラーを、赤、緑、青に設定した三角形の描画結果(本記事の出力結果そのもの)です。
ここで頂点カラーを取り入れる意味
今後3Dモデルの描画をしていくにあたり、頂点データを拡張して扱えることは重要となります。
3Dモデルでは、
- 頂点座標
- 頂点ごとの法線
- テクスチャ座標(UV座標)
といったデータを頂点ごとにもつことが多く、頂点データは単純な座標データではなくなります。
そこで、もっとも出力結果がわかりやすい、頂点カラーを使って、本記事で頂点データの拡張を行った描画・シェーダ処理を行っていきます。
頂点カラーがシェーダー含めて扱えれば、同様の拡張で法線、UVなどもシェーダーで扱うことが可能となるでしょう。
頂点カラー処理
頂点(Vertex)構造体の拡張
まずは頂点に色をもたせられるように、頂点構造体(struct Vertex)を拡張しましょう。
下記のように、ColorプロパティをDirectX::XMFLOAT4
型で追加します。
色は、R,G,B,Aの4つの値から構成するため、Float4つで構成できるようにします。
struct Vertex
{
DirectX::XMFLOAT3 Position = {};
DirectX::XMFLOAT4 Color = {};
...
};
続いて、拡張した頂点データに、前回まで表示していた三角形ポリゴンの各頂点に色を設定します。
冒頭の通り、赤、緑、青を設定、色は[0.0f, 1.0f]でシェーダーで扱うので、この範囲で設定します。
また今回はAlpha値はわかりやすく1.0(不透明)とします。Alphaの適用は[次の記事]()で詳しく扱います。
Triangle::Triangle()
{
auto sqrt3 = sqrtf(3);
Vertices[0] = { 0.f, sqrt3 / 3.f, 0.f };
Vertices[1] = { 0.5f, -sqrt3 / 6.f, 0.f };
Vertices[2] = { -0.5f, -sqrt3 / 6.f, 0.f };
constexpr float ALPHA = 1.f;
Vertices[0].Color = { 1.f, 0.f, 0.f, ALPHA };
Vertices[1].Color = { 0.f, 1.f, 0.f, ALPHA };
Vertices[2].Color = { 0.f, 0.f, 1.f, ALPHA };
}
これで頂点データに、カラーをもたせることができました。
頂点バッファへの対応は不要
頂点データは以下の処理で頂点バッファに設定されているのでした。
bool Triangle::CreateVertexBuffer(Renderer& renderer)
{
D3D11_BUFFER_DESC vertexBufferDesc = {};
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof(Vertex) * 3;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA vertexSubData;
vertexSubData.pSysMem = Vertices;
auto hr = renderer.GetDevice()->CreateBuffer(
&vertexBufferDesc,
&vertexSubData,
&VertexBuffer
);
...
}
この処理のとおり、sizeof(Vertex) * 3
でサイズを指定してデータを設定しているので、Vertexが拡張されれば自動で頂点バッファにも適切なサイズでデータ設定されます。
ですので頂点バッファに対しては、特に何もいじる必要がありません。
シェーダー向け入力レイアウトの定義の拡張
ここまでで頂点データの拡張準備はできました。
あとはシェーダーでColorを解釈できるようにする必要があります。
シェーダーに渡す頂点データは、入力レイアウト(=どういった頂点データか)を教えて上げる必要がありました(参考:入力レイアウト作成)。
D3D11_INPUT_ELEMENT_DESC
構造体は以下の構成(参考:公式ドキュメント)となっています。
typedef struct D3D11_INPUT_ELEMENT_DESC {
LPCSTR SemanticName;
UINT SemanticIndex;
DXGI_FORMAT Format;
UINT InputSlot;
UINT AlignedByteOffset;
D3D11_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate;
} D3D11_INPUT_ELEMENT_DESC;
今回は、頂点バッファには、Position、Colorが1セットとなったVertex構造体単位でデータをセットしているので、上記のAlignedByteOffset
を指定することで、Position、ColorがVertexの中でどこに位置しているかを教えてあげます。
PositionはVertexの先頭に位置するのでOffsetは0、ColorはPositionの後ろにあるので、Positionのサイズ分(=sizeof(XMFLOAT3)
)である12バイトのオフセットを指定します。
結果以下のような入力レイアウト指定となります。
D3D11_INPUT_ELEMENT_DESC layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
シェーダーでの入力・出力構造体の拡張
入力レイアウトの指定が済めば、シェーダーにデータが渡る用意ができたので、あとはシェーダーで使っていきます。
頂点シェーダー
まずは頂点シェーダーです。
これまではPositionのみを入力として、出力もPositionのみだったので、以下のような単純な処理でした。
...
float4 main( float4 pos : POSITION ) : SV_POSITION
{
return mul(pos, Transform);
}
これが、入力データを拡張して構造体(VS_INPUT)に、そして後工程(ピクセルシェーダー等)にもColorは伝える必要があるので、出力データも同様の構造体(VS_OUTPUT)とします。
頂点シェーダーの出力Positionには「SV_POSITION」というセマンティクスを使うのがルールとなっており必須です。
Colorはそのまま出力すればOKです。ピクセルシェーダーでは頂点間で自動で補間された色が渡ってきます。
結果、頂点シェーダーは以下のような処理となります。
...
struct VS_INPUT {
float3 Pos : POSITION; // 頂点座標(モデル座標系)
float4 Col : COLOR; // 頂点色
};
struct VS_OUTPUT {
float4 Pos : SV_POSITION;
float4 Col : COLOR;
};
VS_OUTPUT main(VS_INPUT input)
{
VS_OUTPUT output;
float4 pos = float4(input.Pos, 1.0);
output.Pos = mul(pos, Transform);
output.Col = input.Col;
return output;
}
ピクセルシェーダー
続いてピクセルシェーダーです。
こちらもこれまではポリゴンを白にしていただけなので、以下のような単純な処理でした。
float4 main() : SV_TARGET
{
return float4(1.0f, 1.0f, 1.0f, 1.0f);
}
これが、頂点シェーダーから出力結果を受け取るため、VS_OUTPUTと同じ構造体のPS_INPUTとして、入力データを受け取ります。
前述もした通り、ピクセルシェーダーには頂点間で補間されたColor値が渡ってきます。
ですので、渡ってきたColorをそのままピクセルの色として出力します。
struct PS_INPUT {
float4 Pos : SV_POSITION;
float4 Col : COLOR;
};
float4 main(PS_INPUT input) : SV_TARGET
{
return input.Col;
}
結果
以上が頂点カラーの対応でした。
出力結果が以下となります(冒頭でも表示している通りです)。
上述もしたとおり、今後3D描画していくにあたって、頂点データは法線(Normal)やテクスチャ(UV)など、データが拡張されていきます。
ですが、ここでやったカラーと同様に拡張すれば、そういった拡張データも扱えるイメージがつくかと思います。
ソースコード
以下が今回の実装があるコードです。
GameDev/04-VertexColor/RenderParam.cpp at master · prog-log/GameDev
Contribute to prog-log/GameDev development by creating an account on GitHub.
struct PS_INPUT {
float4 Pos : SV_POSITION; // 頂点座標(モデル座標系)
float4 Col : COLOR; // 頂点色
};
float4 main(PS_INPUT input) : SV_TARGET
{
return input.Col;
}
#include "Application.h"
void Application::Initialize(HINSTANCE hInst)
{
window_.Initialize(hInst);
renderer_.Initialize(window_.GetWindowHandle());
}
void Application::Loop()
{
while (true) {
bool result = window_.MessageLoop();
if (result == false) break;
bool ret = gameLoop();
if (ret == false) break;
}
}
void Application::Terminate()
{
renderer_.Terminate();
window_.Terminate();
}
bool Application::gameLoop()
{
renderer_.Draw();
renderer_.Swap();
return true;
}
#pragma once
#include "Window.h"
#include "Renderer.h"
class Application
{
public:
void Initialize(HINSTANCE hInst);
void Loop();
void Terminate();
private:
// アプリのメインループ
bool gameLoop();
private:
Window window_;
Renderer renderer_;
};
#pragma once
struct CbTransform
{
XMFLOAT4X4 Transform;
};
struct CbTransformSet
{
CbTransform Data;
ID3D11Buffer* pBuffer = nullptr;
};
#pragma once
#include "ConstantBuffer.h"
struct RenderParam
{
CbTransformSet CbTransformSet;
bool Initialize(Renderer& renderer);
void Terminate(Renderer& renderer);
private:
bool initConstantBuffer(Renderer& renderer);
};
#pragma once
#include "Shader.h"
#include "Triangle.h"
#include "RenderParam.h"
class Renderer
{
public:
Renderer();
~Renderer();
bool Initialize(HWND hWindow);
void Terminate();
void Draw();
void Swap();
ID3D11Device* GetDevice() { return pD3DDevice_; }
ID3D11DeviceContext* GetDeviceContext() { return pImmediateContext_; }
RenderParam& GetRenderParam() { return renderParam_; }
bool CompileShader(const WCHAR* vsPath, const WCHAR* psPath, Shader& outShader);
private:
bool initDeviceAndSwapChain(HWND hWindow);
bool initBackBuffer();
private:
//! 機能レベルの配列
static const UINT FEATURE_LEVELS_NUM = 4;
D3D_FEATURE_LEVEL pFeatureLevels_[FEATURE_LEVELS_NUM] = {};
//! デバイス作成時に返される機能レベル
D3D_FEATURE_LEVEL featureLevelsSupported_;
//! デバイス
ID3D11Device* pD3DDevice_ = nullptr;
//! デバイスコンテキスト
ID3D11DeviceContext* pImmediateContext_ = nullptr;
//! スワップ・チェイン
IDXGISwapChain* pSwapChain_ = nullptr;
//! 描画ターゲット・ビュー
ID3D11RenderTargetView* pRenderTargetView_ = nullptr;
//! ビューポート
D3D11_VIEWPORT viewPort_[1];
//! ブレンド・ステート・オブジェクト
ID3D11BlendState* pBlendState_ = nullptr;
UINT backBufferNum_ = 3;
UINT screenWidth_ = 0;
UINT screenHeight_ = 0;
Shader defaultShader_;
Triangle sampleTriangle_;
RenderParam renderParam_;
};
#pragma once
struct Shader
{
Shader() {}
~Shader() {}
void Terminate() {
DX_SAFE_RELEASE(pVertexShader);
DX_SAFE_RELEASE(pPixelShader);
DX_SAFE_RELEASE(pInputLayout);
}
ID3D11VertexShader* pVertexShader = nullptr;
ID3D11PixelShader* pPixelShader = nullptr;
ID3D11InputLayout* pInputLayout = nullptr;
};
#pragma once
struct Triangle
{
static constexpr size_t VERTEX_NUM = 3;
Vertex Vertices[VERTEX_NUM];
ID3D11Buffer* VertexBuffer = nullptr;
Triangle();
~Triangle();
bool CreateVertexBuffer(Renderer& renderer);
void DestroyVertexBuffer();
void Draw(Renderer& renderer);
private:
void updateTransform();
void setupTransform(Renderer& renderer);
private:
float translateX_ = 0.f;
float translateY_ = 0.f;
float angle_ = 0.f;
float scale_ = 1.f;
};
#pragma once
struct Vertex
{
DirectX::XMFLOAT3 Position = {};
DirectX::XMFLOAT4 Color = {};
Vertex() {}
Vertex(float x, float y, float z) {
Position.x = x;
Position.y = y;
Position.z = z;
}
};
#include
#include "Application.h"
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int)
{
Application* application = new Application();
application->Initialize(hInst);
application->Loop();
application->Terminate();
delete(application);
return 0;
}
#pragma once
#include
class Window
{
public:
Window();
virtual ~Window();
bool Initialize(HINSTANCE hInst);
bool Terminate();
bool MessageLoop();
static LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void OnResize(UINT width, UINT height);
HWND GetWindowHandle() { return hWindow_; }
private:
WNDCLASS wc_;
HWND hWindow_ = nullptr;
SIZE sizeWindow_;
MSG msg_ = {};
};
#include "RenderParam.h"
#include "Renderer.h"
bool RenderParam::Initialize(Renderer& renderer)
{
auto result = initConstantBuffer(renderer);
if (result == false) return false;
return true;
}
void RenderParam::Terminate(Renderer& renderer)
{
DX_SAFE_RELEASE(CbTransformSet.pBuffer);
}
bool RenderParam::initConstantBuffer(Renderer& renderer)
{
// 定数バッファの定義
D3D11_BUFFER_DESC cBufferDesc;
cBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
cBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cBufferDesc.MiscFlags = 0;
cBufferDesc.StructureByteStride = 0;
// 定数バッファ①の作成
cBufferDesc.ByteWidth = sizeof(CbTransform); // バッファ・サイズ
auto hr = renderer.GetDevice()->CreateBuffer(&cBufferDesc, nullptr, &CbTransformSet.pBuffer);
if (FAILED(hr)) {
// DXTRACE_ERR(L"InitDirect3D g_pD3DDevice->CreateBuffer", hr);
return false;
}
return true;
}
#include "Renderer.h"
#include
#pragma comment(lib, "d3dcompiler.lib")
Renderer::Renderer()
{
pFeatureLevels_[0] = D3D_FEATURE_LEVEL_11_1;
pFeatureLevels_[1] = D3D_FEATURE_LEVEL_11_0;
pFeatureLevels_[2] = D3D_FEATURE_LEVEL_10_1;
pFeatureLevels_[3] = D3D_FEATURE_LEVEL_10_0;
}
Renderer::~Renderer()
{
}
bool Renderer::Initialize(HWND hWindow)
{
// Windowに合わせてスクリーンサイズ初期化
RECT rc;
GetClientRect(hWindow, &rc);
screenWidth_ = rc.right - rc.left;
screenHeight_ = rc.bottom - rc.top;
initDeviceAndSwapChain(hWindow);
initBackBuffer();
CompileShader(L"VertexShader.hlsl", L"PixelShader.hlsl", defaultShader_);
renderParam_.Initialize(*this);
sampleTriangle_.CreateVertexBuffer(*this);
return true;
}
void Renderer::Terminate()
{
sampleTriangle_.DestroyVertexBuffer();
renderParam_.Terminate(*this);
// デバイス・ステートのクリア
if(pImmediateContext_)
pImmediateContext_->ClearState();
// スワップ チェインをウインドウ モードにする
if (pSwapChain_)
pSwapChain_->SetFullscreenState(FALSE, nullptr);
DX_SAFE_RELEASE(pRenderTargetView_);
DX_SAFE_RELEASE(pBlendState_);
DX_SAFE_RELEASE(pSwapChain_);
DX_SAFE_RELEASE(pImmediateContext_);
DX_SAFE_RELEASE(pD3DDevice_);
defaultShader_.Terminate();
}
void Renderer::Draw()
{
if (!pImmediateContext_ || !pRenderTargetView_) return;
pImmediateContext_->OMSetRenderTargets(1, &pRenderTargetView_, nullptr);
// OMにブレンドステートオブジェクトを設定
FLOAT BlendFactor[4] = { 0.f, 0.f, 0.f, 0.f };
pImmediateContext_->OMSetBlendState(pBlendState_, nullptr, 1);
float color[] = { 0.f, 0.f, 0.f, 0.f };
pImmediateContext_->ClearRenderTargetView(pRenderTargetView_, color);
pImmediateContext_->IASetInputLayout(defaultShader_.pInputLayout);
pImmediateContext_->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
pImmediateContext_->VSSetShader(defaultShader_.pVertexShader, nullptr, 0);
pImmediateContext_->PSSetShader(defaultShader_.pPixelShader, nullptr, 0);
sampleTriangle_.Draw(*this);
}
void Renderer::Swap()
{
// バックバッファの表示(画面をすぐに更新)
HRESULT hr = pSwapChain_->Present(0, 0);
if (FAILED(hr)) {
//TRACE("Swap failed(%0x08x)\n", hr);
return;
}
}
bool Renderer::CompileShader(const WCHAR* vsPath, const WCHAR* psPath, Shader& outShader)
{
ID3DBlob* vsBlob = nullptr;
ID3DBlob* errBlob = nullptr;
auto pDevice = GetDevice();
// シェーダーコンパイル
auto hr = D3DCompileFromFile(
vsPath,
nullptr,
D3D_COMPILE_STANDARD_FILE_INCLUDE,
"main",
"vs_4_0",
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
0,
&vsBlob,
&errBlob
);
if (FAILED(hr)) return false;
// 頂点シェーダ作成(シェーダオブジェクト作成)
ID3D11VertexShader* pVertexShader = nullptr;
hr = pDevice->CreateVertexShader(
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
nullptr,
&pVertexShader
);
if (FAILED(hr)) return false;
// 入力レイアウトオブジェクト作成
ID3D11InputLayout* pInputLayout = nullptr;
D3D11_INPUT_ELEMENT_DESC layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
hr = pDevice->CreateInputLayout(
layout,
_countof(layout),
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
&pInputLayout
);
if (FAILED(hr)) return false;
// ピクセルシェーダー作成
ID3DBlob* psBlob = nullptr;
hr = D3DCompileFromFile(
psPath,
nullptr,
D3D_COMPILE_STANDARD_FILE_INCLUDE,
"main",
"ps_4_0",
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
0,
&psBlob,
&errBlob
);
ID3D11PixelShader* pPixelShader = nullptr;
hr = pDevice->CreatePixelShader(
psBlob->GetBufferPointer(),
psBlob->GetBufferSize(),
nullptr,
&pPixelShader
);
if (FAILED(hr)) return false;
outShader.pVertexShader = pVertexShader;
outShader.pPixelShader = pPixelShader;
outShader.pInputLayout = pInputLayout;
return true;
}
bool Renderer::initDeviceAndSwapChain(HWND hWindow)
{
// デバイスとスワップ・チェイン作成
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = backBufferNum_; // バックバッファの数
sd.BufferDesc.Width = screenWidth_; // バックバッファの幅
sd.BufferDesc.Height = screenHeight_; // バックバッファの高さ
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // フォーマット
sd.BufferDesc.RefreshRate.Numerator = 60; // リフレッシュレート(分母)
sd.BufferDesc.RefreshRate.Denominator = 1; // リフレッシュレート(分子)
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // バックバッファの使用法
sd.OutputWindow = hWindow; // 関連付けるウィンドウ
sd.SampleDesc.Count = 1; // マルチサンプル(アンチエイリアス)の数
sd.SampleDesc.Quality = 0; // マルチサンプル(アンチエイリアス)のクオリティ
sd.Windowed = TRUE; // ウィンドウモード(TRUEがウィンドウモード)
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // モード自動切り替え
#if defined(DEBUG) || defined(_DEBUG)
UINT createDeviceFlags = D3D11_CREATE_DEVICE_DEBUG;
#else
UINT createDeviceFlags = 0;
#endif
const D3D_DRIVER_TYPE DriverTypes[] = {
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
HRESULT hr;
for (auto type : DriverTypes) {
// ハードウェアデバイスを作成
hr = D3D11CreateDeviceAndSwapChain(
nullptr, type, nullptr, createDeviceFlags,
pFeatureLevels_, FEATURE_LEVELS_NUM, D3D11_SDK_VERSION, &sd,
&pSwapChain_, &pD3DDevice_, &featureLevelsSupported_, &pImmediateContext_);
if (SUCCEEDED(hr)) {
break;
}
}
if (FAILED(hr)) return false;
return true;
}
bool Renderer::initBackBuffer()
{
HRESULT hr;
// スワップ・チェインから最初のバック・バッファを取得する
ID3D11Texture2D *pBackBuffer; // バッファのアクセスに使うインターフェイス
hr = pSwapChain_->GetBuffer(
0, // バック・バッファの番号
__uuidof(ID3D11Texture2D), // バッファにアクセスするインターフェイス
(LPVOID*)&pBackBuffer); // バッファを受け取る変数
if (FAILED(hr)) {
//TRACE("InitBackBuffer g_pSwapChain->GetBuffer(%0x08x)\n", hr); // 失敗
return false;
}
// バック・バッファの情報
D3D11_TEXTURE2D_DESC descBackBuffer;
pBackBuffer->GetDesc(&descBackBuffer);
// バック・バッファの描画ターゲット・ビューを作る
hr = pD3DDevice_->CreateRenderTargetView(
pBackBuffer, // ビューでアクセスするリソース
nullptr, // 描画ターゲット・ビューの定義
&pRenderTargetView_); // 描画ターゲット・ビューを受け取る変数
DX_SAFE_RELEASE(pBackBuffer); // 以降、バック・バッファは直接使わないので解放
if (FAILED(hr)) {
//TRACE("InitBackBuffer g_pD3DDevice->CreateRenderTargetView(%0x08x)\n", hr); // 失敗
return false;
}
// RenderTarget0へのAlphaブレンド描画設定
D3D11_BLEND_DESC BlendState;
//ZeroMemory(&BlendState, sizeof(D3D11_BLEND_DESC));
BlendState.AlphaToCoverageEnable = FALSE;
BlendState.IndependentBlendEnable = FALSE;
BlendState.RenderTarget[0].BlendEnable = TRUE;
BlendState.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
BlendState.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
BlendState.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
BlendState.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
BlendState.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
BlendState.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
BlendState.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
hr = pD3DDevice_->CreateBlendState(&BlendState, &pBlendState_);
if (FAILED(hr)) {
//TRACE(L"InitDirect3D g_pD3DDevice->CreateBlendState", hr);
return false;
}
// ビューポートの設定
viewPort_[0].TopLeftX = 0.0f; // ビューポート領域の左上X座標。
viewPort_[0].TopLeftY = 0.0f; // ビューポート領域の左上Y座標。
viewPort_[0].Width = static_cast(screenWidth_); // ビューポート領域の幅
viewPort_[0].Height = static_cast(screenHeight_); // ビューポート領域の高さ
viewPort_[0].MinDepth = 0.0f; // ビューポート領域の深度値の最小値
viewPort_[0].MaxDepth = 1.0f; // ビューポート領域の深度値の最大値
pImmediateContext_->RSSetViewports(1, &viewPort_[0]);
return true;
}
#include "Triangle.h"
#include "Renderer.h"
Triangle::Triangle()
{
// √3
auto sqrt3 = sqrtf(3);
Vertices[0] = { 0.f, sqrt3 / 3.f, 0.f };
Vertices[1] = { 0.5f, -sqrt3 / 6.f, 0.f };
Vertices[2] = { -0.5f, -sqrt3 / 6.f, 0.f };
constexpr float ALPHA = 0.3f;
Vertices[0].Color = { 1.f, 0.f, 0.f, ALPHA };
Vertices[1].Color = { 0.f, 1.f, 0.f, ALPHA };
Vertices[2].Color = { 0.f, 0.f, 1.f, ALPHA };
}
Triangle::~Triangle()
{
DestroyVertexBuffer();
}
bool Triangle::CreateVertexBuffer(Renderer& renderer)
{
D3D11_BUFFER_DESC vertexBufferDesc = {};
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof(Vertex) * 3;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA vertexSubData;
vertexSubData.pSysMem = Vertices;
auto hr = renderer.GetDevice()->CreateBuffer(
&vertexBufferDesc,
&vertexSubData,
&VertexBuffer
);
if (FAILED(hr)) return false;
return true;
}
void Triangle::DestroyVertexBuffer()
{
DX_SAFE_RELEASE(VertexBuffer);
}
void Triangle::Draw(Renderer& renderer)
{
updateTransform();
setupTransform(renderer);
auto pDeviceContext = renderer.GetDeviceContext();
uint32_t strides[1] = { sizeof(Vertex) };
uint32_t offsets[1] = { 0 };
pDeviceContext->IASetVertexBuffers(0, 1, &VertexBuffer, strides, offsets);
pDeviceContext->Draw(VERTEX_NUM, 0);
}
void Triangle::updateTransform()
{
// 平行移動
//translateX_ += 0.0001f;
//if (translateX_ >= 1.f) translateX_ = -1.f;
//translateY_ += 0.0001f;
//if (translateY_ >= 1.f) translateY_ = -1.f;
translateX_ = 0.5f;
// 回転
//angle_ += XM_PI / 60000.f;
angle_ = XM_PI / 2.f;
// スケール
//scale_ += 0.0001f;
//if (scale_ >= 2.0f) scale_ = 0.5f;
scale_ = 2.f;
}
void Triangle::setupTransform(Renderer& renderer)
{
// WorldMatrixを定数バッファに設定
auto& cb = renderer.GetRenderParam().CbTransformSet;
//auto mtxS = XMMatrixScaling(scale_, scale_, 1.f);
//auto mtxR = XMMatrixRotationX(angle_);
//auto mtxR = XMMatrixRotationY(angle_);
//auto mtxR = XMMatrixRotationZ(angle_);
//auto mtxT = XMMatrixTranslation(translateX_, translateY_, 0);
auto mtx = XMMatrixIdentity();
// 左から変換が適用される
//auto mtx = mtxT * mtxS;
//auto mtx = mtxS * mtxT;
//auto mtx = mtxT * mtxR;
//auto mtx = mtxR * mtxT;
XMStoreFloat4x4(&cb.Data.Transform, XMMatrixTranspose(mtx));
//DirectX::XMStoreFloat4x4(&cb.Data.Transform, translate);
D3D11_MAPPED_SUBRESOURCE mappedResource;
auto pDeviceContext = renderer.GetDeviceContext();
// CBufferにひもづくハードウェアリソースマップ取得(ロックして取得)
HRESULT hr = pDeviceContext->Map(
cb.pBuffer,
0,
D3D11_MAP_WRITE_DISCARD,
0,
&mappedResource);
if (FAILED(hr)) {
//DXTRACE_ERR(L"DrawSceneGraph failed", hr);
return;
}
CopyMemory(mappedResource.pData, &cb.Data, sizeof(cb.Data));
// マップ解除
pDeviceContext->Unmap(cb.pBuffer, 0);
pDeviceContext->VSSetConstantBuffers(0, 1, &cb.pBuffer);
}
#include "Window.h"
#include
Window::Window()
: sizeWindow_()
{
sizeWindow_.cx = 480;
sizeWindow_.cy = 480;
}
Window::~Window()
{
}
bool Window::Initialize(HINSTANCE hInst)
{
// ウインドウ クラスの登録
wc_.style = CS_HREDRAW | CS_VREDRAW;
wc_.lpfnWndProc = (WNDPROC)Window::MainWndProc;
wc_.cbClsExtra = 0;
wc_.cbWndExtra = 0;
wc_.hInstance = hInst;
wc_.hIcon = LoadIcon(hInst, IDI_APPLICATION);
wc_.hCursor = LoadCursor(hInst, IDC_ARROW);
wc_.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
wc_.lpszMenuName = nullptr;
wc_.lpszClassName = _T("VertexColor");
if (!RegisterClass(&wc_)) {
return false;
}
// メイン ウインドウ作成
RECT rect;
rect.top = 0;
rect.left = 0;
rect.right = sizeWindow_.cx;
rect.bottom = sizeWindow_.cy;
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
hWindow_ = CreateWindow(wc_.lpszClassName, _T("VertexColor"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top,
nullptr, nullptr, hInst, nullptr);
if (hWindow_ == nullptr) {
return false;
}
// ウインドウ表示
ShowWindow(hWindow_, SW_SHOWNORMAL);
UpdateWindow(hWindow_);
return true;
}
bool Window::Terminate()
{
DestroyWindow(GetWindowHandle());
// ウインドウ クラスの登録解除
UnregisterClass(wc_.lpszClassName, wc_.hInstance);
hWindow_ = nullptr;
return true;
}
bool Window::MessageLoop()
{
// Windowsメッセージループ処理
if (PeekMessage(&msg_, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg_); DispatchMessage(&msg_);
}
// アプリケーションが終わるときにmessageがWM_QUITになる
if (msg_.message == WM_QUIT) {
return false;
}
return true;
}
/*static*/ LRESULT CALLBACK Window::MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_DESTROY:
// アプリ終了
PostQuitMessage(0);
return 0;
default:
break;
}
// デフォルト処理(必須)
return DefWindowProc(hWnd, msg, wParam, lParam);
}
void Window::OnResize(UINT width, UINT height)
{
sizeWindow_.cx = width;
sizeWindow_.cy = height;
}
#pragma once
#include
#pragma comment(lib, "d3d11.lib")
#include
#define DX_SAFE_RELEASE(x) { if(x) { (x)->Release(); (x)=nullptr; } }
#include "Vertex.h"
using namespace DirectX;
class Renderer;
cbuffer cbTransform : register(b0) { // 常にスロット「0」を使う
matrix Transform;
};
struct VS_INPUT {
float3 Pos : POSITION; // 頂点座標(モデル座標系)
float4 Col : COLOR; // 頂点色
};
struct VS_OUTPUT {
float4 Pos : SV_POSITION;
float4 Col : COLOR;
};
VS_OUTPUT main(VS_INPUT input)
{
VS_OUTPUT output;
float4 pos = float4(input.Pos, 1.0);
output.Pos = mul(pos, Transform);
output.Col = input.Col;
return output;
}
コメント