前田稔(Maeda Minoru)の超初心者のプログラム入門
struct VertexPosition { DirectX::XMFLOAT3 pos; DirectX::XMFLOAT3 norm; }; |
struct VertexPosition { float3 pos; // position float3 norm; // norm }; |
#include "BasicMath.h" struct float3 { float x; float y; float z; }; |
System⇒App.cpp⇒App1Main⇒Model⇒XLoader |
#pragma once #include "BasicMath.h" namespace App1 { // MVP マトリックスを頂点シェーダーに送信するために使用する定数バッファー。 struct ModelViewProjectionConstantBuffer { DirectX::XMFLOAT4X4 model; DirectX::XMFLOAT4X4 view; DirectX::XMFLOAT4X4 projection; }; // 頂点シェーダーへの頂点ごとのデータの送信に使用します。 struct VertexPosition { float3 pos; // position float3 norm; // norm }; } |
m_sceneRenderer = std::unique_ptr<Sample3DSceneRenderer>(new Sample3DSceneRenderer(m_deviceResources)); |
m_sceneRenderer = std::unique_ptr<Model>(new Model(m_deviceResources)); |
#pragma once #include "..\Common\DeviceResources.h" #include "..\Common\StepTimer.h" #include "ShaderStructures.h" #include "XLoader.h" namespace App1 { // このサンプル レンダリングでは、基本的なレンダリング パイプラインをインスタンス化します。 class Model { public: Model(const std::shared_ptr<DX::DeviceResources>& deviceResources); void CreateDeviceDependentResources(); void CreateWindowSizeDependentResources(); void ReleaseDeviceDependentResources(); void Update(DX::StepTimer const& timer); void Render(); void StartTracking(); void TrackingUpdate(float positionX); void StopTracking(); bool IsTracking() { return m_tracking; } private: void Rotate(float radians); std::unique_ptr<XLoader> xloader; private: // デバイス リソースへのキャッシュされたポインター。 std::shared_ptr<DX::DeviceResources> m_deviceResources; ModelViewProjectionConstantBuffer m_constantBufferData; float m_degreesPerSecond; bool m_tracking; }; } |
void Model::CreateDeviceDependentResources() { xloader = std::unique_ptr<XLoader>(new XLoader(m_deviceResources)); xloader->Load(); } |
// コーン(座標と法線)をプログラムで計算して描画 #include "pch.h" #include "Model.h" #include "..\Common\DirectXHelper.h" using namespace App1; using namespace DirectX; using namespace Windows::Foundation; // ファイルから頂点とピクセル シェーダーを読み込み、キューブのジオメトリをインスタンス化します。 Model::Model(const std::shared_ptr<DX::DeviceResources>& deviceResources) : m_degreesPerSecond(45), m_tracking(false), m_deviceResources(deviceResources) { CreateDeviceDependentResources(); CreateWindowSizeDependentResources(); } // ウィンドウのサイズが変更されたときに、ビューのパラメーターを初期化します。 void Model::CreateWindowSizeDependentResources() { Size outputSize = m_deviceResources->GetOutputSize(); float aspectRatio = outputSize.Width / outputSize.Height; float fovAngleY = 70.0f * XM_PI / 180.0f; if (aspectRatio < 1.0f) { fovAngleY *= 2.0f; } XMMATRIX perspectiveMatrix = XMMatrixPerspectiveFovRH( fovAngleY, aspectRatio, 0.01f, 100.0f ); XMFLOAT4X4 orientation = m_deviceResources->GetOrientationTransform3D(); XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation); XMStoreFloat4x4( &m_constantBufferData.projection, XMMatrixTranspose(perspectiveMatrix * orientationMatrix) ); // 視点は (0,0.7,1.5) の位置にあり、y 軸に沿って上方向のポイント (0,-0.1,0) を見ています。 //static const XMVECTORF32 eye = { 0.0f, 0.7f, 1.5f, 0.0f }; static const XMVECTORF32 eye = { 0.0f, 0.7f, 4.0f, 0.0f }; static const XMVECTORF32 at = { 0.0f, -0.1f, 0.0f, 0.0f }; static const XMVECTORF32 up = { 0.0f, 1.0f, 0.0f, 0.0f }; XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up))); } // フレームごとに 1 回呼び出し、キューブを回転させてから、モデルおよびビューのマトリックスを計算します。 void Model::Update(DX::StepTimer const& timer) { if (!m_tracking) { // 度をラジアンに変換し、秒を回転角度に変換します float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond); double totalRotation = timer.GetTotalSeconds() * radiansPerSecond; float radians = static_cast<float>(fmod(totalRotation, XM_2PI)); Rotate(radians); } } // モデルを、ラジアン単位で設定された大きさだけ回転させます。 void Model::Rotate(float radians) { //更新されたモデル マトリックスをシェーダーに渡す準備をします XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(radians))); } void Model::StartTracking() { m_tracking = true; } // 追跡時に、出力画面の幅方向を基準としてポインターの位置を追跡することにより、3D キューブを Y 軸に沿って回転させることができます。 void Model::TrackingUpdate(float positionX) { if (m_tracking) { float radians = XM_2PI * 2.0f * positionX / m_deviceResources->GetOutputSize().Width; Rotate(radians); } } void Model::StopTracking() { m_tracking = false; } // 頂点とピクセル シェーダーを使用して、1 つのフレームを描画します。 void Model::Render() { xloader->Draw(m_constantBufferData); } void Model::CreateDeviceDependentResources() { xloader = std::unique_ptr<XLoader>(new XLoader(m_deviceResources)); xloader->Load(); } void Model::ReleaseDeviceDependentResources() { xloader->Release(); } |
#pragma once #include "..\Common\DeviceResources.h" #include "..\Common\StepTimer.h" #include "ShaderStructures.h" namespace App1 { class XLoader { public: XLoader(const std::shared_ptr<DX::DeviceResources>& deviceResources); void Load(); void Draw(ModelViewProjectionConstantBuffer); void Release(); private: std::shared_ptr<DX::DeviceResources> m_deviceResources; Microsoft::WRL::ComPtr<ID3D11InputLayout> m_inputLayout; Microsoft::WRL::ComPtr<ID3D11Buffer> m_vertexBuffer; Microsoft::WRL::ComPtr<ID3D11Buffer> m_indexBuffer; Microsoft::WRL::ComPtr<ID3D11VertexShader> m_vertexShader; Microsoft::WRL::ComPtr<ID3D11PixelShader> m_pixelShader; Microsoft::WRL::ComPtr<ID3D11Buffer> m_constantBuffer; ModelViewProjectionConstantBuffer m_constantBufferData; uint32 m_indexCount; bool m_loadingComplete; }; } |
// コーン(座標と法線)をプログラムで計算して描画 #include "pch.h" #include "XLoader.h" #include "..\Common\DirectXHelper.h" #define KAKU 19 // (pyramid の画数+1) using namespace App1; using namespace DirectX; using namespace Windows::Foundation; // ファイルから頂点とピクセル シェーダーを読み込み、キューブのジオメトリをインスタンス化します。 XLoader::XLoader(const std::shared_ptr<DX::DeviceResources>& deviceResources) : m_loadingComplete(false), m_indexCount(0), m_deviceResources(deviceResources) { } // Load X-FILE void XLoader::Load() { // シェーダーを非同期で読み込みます。 auto loadVSTask = DX::ReadDataAsync(L"SampleVertexShader.cso"); auto loadPSTask = DX::ReadDataAsync(L"SamplePixelShader.cso"); // 頂点シェーダー ファイルを読み込んだ後、シェーダーと入力レイアウトを作成します。 auto createVSTask = loadVSTask.then([this](const std::vector<byte>& fileData) { DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateVertexShader( &fileData[0], fileData.size(), nullptr, &m_vertexShader ) ); static const D3D11_INPUT_ELEMENT_DESC vertexDesc [] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateInputLayout( vertexDesc, ARRAYSIZE(vertexDesc), &fileData[0], fileData.size(), &m_inputLayout ) ); }); // ピクセル シェーダー ファイルを読み込んだ後、シェーダーと定数バッファーを作成します。 auto createPSTask = loadPSTask.then([this](const std::vector<byte>& fileData) { DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreatePixelShader( &fileData[0], fileData.size(), nullptr, &m_pixelShader ) ); CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer) , D3D11_BIND_CONSTANT_BUFFER); DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateBuffer( &constantBufferDesc, nullptr, &m_constantBuffer ) ); }); // 両方のシェーダーの読み込みが完了したら、メッシュを作成します。 auto createCubeTask = (createPSTask && createVSTask).then([this] () { static VertexPosition modelVertices[KAKU * 2]; for (int slice = 0; slice<KAKU; slice++) { float v = (float)slice / (float)(KAKU - 1); float theta = v * 3.14f * 2; modelVertices[2 * slice + 0].pos.x = sinf(theta); modelVertices[2 * slice + 0].pos.y = -1.0f; modelVertices[2 * slice + 0].pos.z = cosf(theta); modelVertices[2 * slice + 0].norm.x = sinf(theta); modelVertices[2 * slice + 0].norm.y = 1.0f; modelVertices[2 * slice + 0].norm.z = cosf(theta); modelVertices[2 * slice + 1].pos.x = 0.0f; modelVertices[2 * slice + 1].pos.y = 1.0f; modelVertices[2 * slice + 1].pos.z = 0.0f; modelVertices[2 * slice + 1].norm.x = sinf(theta); modelVertices[2 * slice + 1].norm.y = 1.0f; modelVertices[2 * slice + 1].norm.z = cosf(theta); } D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; vertexBufferData.pSysMem = modelVertices; vertexBufferData.SysMemPitch = 0; vertexBufferData.SysMemSlicePitch = 0; CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(modelVertices), D3D11_BIND_VERTEX_BUFFER); DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &m_vertexBuffer ) ); static unsigned short modelIndices[KAKU*6]; for(int slice=0; slice<(KAKU-1); slice++) { modelIndices[3*slice+0] = slice*2+0; modelIndices[3*slice+1] = slice*2+1; modelIndices[3*slice+2] = slice*2+2; modelIndices[3*(KAKU+slice)+0] = slice*2+3; modelIndices[3*(KAKU+slice)+1] = slice*2+2; modelIndices[3*(KAKU+slice)+2] = slice*2+1; } m_indexCount = ARRAYSIZE(modelIndices); D3D11_SUBRESOURCE_DATA indexBufferData = {0}; indexBufferData.pSysMem = modelIndices; indexBufferData.SysMemPitch = 0; indexBufferData.SysMemSlicePitch = 0; CD3D11_BUFFER_DESC indexBufferDesc(sizeof(modelIndices), D3D11_BIND_INDEX_BUFFER); DX::ThrowIfFailed( m_deviceResources->GetD3DDevice()->CreateBuffer( &indexBufferDesc, &indexBufferData, &m_indexBuffer ) ); }); // モデルが読み込まれたら、オブジェクトを描画する準備が完了します。 createCubeTask.then([this] () { m_loadingComplete = true; }); } // モデルを描画 void XLoader::Draw(ModelViewProjectionConstantBuffer BuffData) { // 読み込みは非同期です。読み込みが完了した後にのみ描画してください。 if (!m_loadingComplete) { return; } auto context = m_deviceResources->GetD3DDeviceContext(); // レンダー ターゲットを画面に設定します。 ID3D11RenderTargetView *const targets[1] = { m_deviceResources->GetBackBufferRenderTargetView() }; context->OMSetRenderTargets(1, targets, m_deviceResources->GetDepthStencilView()); // 定数バッファーを準備して、グラフィックス デバイスに送信します。 context->UpdateSubresource( m_constantBuffer.Get(), 0, NULL, &BuffData, 0, 0); // 各頂点は、VertexPositionColor 構造体の 1 つのインスタンスです。 UINT stride = sizeof(VertexPosition); UINT offset = 0; context->IASetVertexBuffers( 0, 1, m_vertexBuffer.GetAddressOf(), &stride, &offset); context->IASetIndexBuffer( m_indexBuffer.Get(), DXGI_FORMAT_R16_UINT, // 各インデックスは、1 つの 16 ビット符号なし整数 (short) です。 0); context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); context->IASetInputLayout(m_inputLayout.Get()); // 頂点シェーダーをアタッチします。 context->VSSetShader( m_vertexShader.Get(), nullptr, 0); // 定数バッファーをグラフィックス デバイスに送信します。 context->VSSetConstantBuffers( 0, 1, m_constantBuffer.GetAddressOf()); // ピクセル シェーダーをアタッチします。 context->PSSetShader( m_pixelShader.Get(), nullptr, 0); // オブジェクトを描画します。 context->DrawIndexed( m_indexCount, 0, 0); } // 領域の解放 void XLoader::Release() { m_loadingComplete = false; m_vertexShader.Reset(); m_inputLayout.Reset(); m_pixelShader.Reset(); m_constantBuffer.Reset(); m_vertexBuffer.Reset(); m_indexBuffer.Reset(); } |