Microsoft Visual C++ 2010 Express Microsoft DirectX SDK (June 2010) Direct3D 11.0 Shader Model 5.0 FBX SDK 2011.3 |
■Direct3D 11.0 被写界深度 | Prev Top Next |
関連ページ:Direct3D 11.0 初期化 Direct3D 11.0 デバック用フォント描画 FBX SDKを使う |
1.ブラー処理について
DirectX9 は縮小バッファを使用して自前でブラー処理をかけたレンダーターゲットサーフェスを使用して被写界深度を実装しましたが、
今回はミップマップチェーンを使用して実装します。
この辺は DirectX SDK のサンプルのDepthOfField10.1 サンプルを参考にしました。
DirectX SDK のサンプルでは MSAA も使用してますが、ここでは使用しません。
ちなみにやったことないですが、リファレンスをみるとミップマップチェーンを使用したブラー処理は DirectX9 でもできそうです。 ためしませんが。
2.フォーカス( 注視点 )の深度値の取得方法について
サンプルでは、レンダーターゲットサーフェスの1つの深度マップの中心位置( 注視点 )をサンプリングして深度値を取得し、フォーカスアニメーションを行います。
この注視点の深度値を取得する方法として DirectX9 ではレンダーターゲットサーフェスの内容を CPU 側で参照可能なサーフェスにいったんコピーして、
ロックして、注視点の深度値を取得し、浮動小数に変換して、フォーカスアニメーションをかますというわりと面倒なことをしてました。
今回も最初この方法で実装しましたが、パフォーマンスがとんでもなく低下したため、コンピュートシェーダーを使用して実装し直しました。ある意味今回のメイン部分かも。
3.奥行が被写界深度と異なるところに存在するオブジェクトの輪郭付近の処理について
今回は何もしません。
さて、今回は D3D11USERクラス を修正してます。レンダーターゲットサーフェス作成するとき、ミップマップチェーンを作成できるようにしました。 ですのでDirect3D 11.0 初期化を参照して修正してください。
ではソースを見ていきます。
DepthOfField.hlsl | 被写界深度のhlslファイル。マルチレンダーターゲット出力に対応したメッシュのシェーディング処理も実装しています。 |
DepthOfField.h | 被写界深度のヘッダファイル。 |
DepthOfField.cpp | 被写界深度のソースファイル。 |
main.cpp | メイン関数があるソースファイル。 |
// ************************************************************ // 被写界深度 // ************************************************************ // ************************************************************ // 構造体の宣言 // ************************************************************ // ハーフランバートレンダリングで使用する構造体の宣言 // 頂点シェーダー入力用の構造体 struct VS01_IN { float3 pos : POSITION; // 頂点座標 float3 normal : NORMAL; // 法線 float2 texel : TEXCOORD; // テクセル }; // 頂点シェーダー出力用の構造体 struct VS01_OUT { float4 pos : SV_POSITION; float3 normal : NORMAL; float2 texel : TEXCOORD0; float zWVP : TEXCOORD1; }; // ピクセルシェーダー出力用の構造体 struct PS01_OUT { float4 ColorBuffer : SV_Target0; // シーンのレンダリングイメージを書込むカラーマップ float4 DepthBuffer : SV_Target1; // 深度マップ }; // 注視点の深度値取得で使用する構造体の宣言 // コンピュートシェーダー入出力用の構造体 struct CS02_INOUT { float g_ZofLookAt; // 注視点の深度値 }; // 被写界深度レンダリングで使用する構造体の宣言 // 頂点シェーダー入力用の構造体 struct VS03_IN { float3 pos : POSITION; // 頂点座標 float2 texel : TEXCOORD; // テクセル }; // 頂点シェーダー出力用の構造体 struct VS03_OUT { float4 pos : SV_POSITION; float2 texel : TEXCOORD0; }; // ************************************************************ // 定数バッファ // ************************************************************ // 定数バッファ1 cbuffer CB_STEP01 : register( b0 ) { // 列優先 column_major float4x4 g_matWVP : packoffset( c0 ); // ワールド × ビュー × 射影 行列 float4 g_vecLight : packoffset( c4 ); // ローカル座標系での平行光源の方向ベクトル。w成分はZfar値。 }; // 定数バッファ2 cbuffer CB_STEP02 : register( b0 ) { float2 g_LookAt : packoffset( c0.x ); // テクセル座標上での注視点の座標 float g_Speed : packoffset( c0.z ); // 被写界深度の変更速度 }; // 定数バッファ3 cbuffer CB_STEP03 : register( b0 ) { float g_MipMaxLevel : packoffset( c0.x ); // ミップマップレベルの最大値 float g_ZofLookAt : packoffset( c0.y ); // 注視点の深度値( コンピュートシェーダーを使用する場合は使用しない ) }; // ************************************************************ // テクスチャー // ************************************************************ Texture2D g_DecalMap : register( t0 ); // デカールマップ Texture2D g_ColorMap : register( t0 ); // カラーマップ Texture2D g_DepthMap : register( t1 ); // 深度ステンシルマップ StructuredBuffer<CS02_INOUT> g_ZofLookAtMap : register( t2 ); // 注視点深度マップ。ピクセルシェーダーから使用する読み込み専用のバッファ。 // ************************************************************ // 構造化バッファー // ************************************************************ // 読み書き可能な構造化バッファー。コンピュートシェーダーから使用する。 RWStructuredBuffer<CS02_INOUT> g_CSInOut : register(u0); // ************************************************************ // サンプラーステート // ************************************************************ SamplerState g_Sampler : register( s0 ); // ************************************************************ // ハーフランバートレンダリング // ************************************************************ // 頂点シェーダー VS01_OUT Step01_VS_Main( VS01_IN In ) { VS01_OUT Out; Out.pos = mul( float4( In.pos, 1.0f ), g_matWVP ); Out.normal = In.normal; Out.texel = In.texel; Out.zWVP = Out.pos.z; return Out; } // ピクセルシェーダー PS01_OUT Step01_PS_Main( VS01_OUT In ) { PS01_OUT Out; float diffuse = dot( -g_vecLight.xyz, In.normal ); diffuse = diffuse * 0.5f + 0.5f; diffuse *= diffuse; Out.ColorBuffer = float4( g_DecalMap.Sample( g_Sampler, In.texel ).rgb * diffuse, 1 ); // Zfarで除算 Out.DepthBuffer = In.zWVP / g_vecLight.w; return Out; } // ************************************************************ // 注視点の深度値取得 // ************************************************************ // コンピュートシェーダー [numthreads(1, 1, 1)] void Step02_CS_Main() { float z = g_DepthMap.Load( float3( g_LookAt.x, g_LookAt.y, 0 ) ).z; if( g_CSInOut[0].g_ZofLookAt < z ) g_CSInOut[0].g_ZofLookAt += g_Speed; else if( g_CSInOut[0].g_ZofLookAt > z ) g_CSInOut[0].g_ZofLookAt -= g_Speed; if( g_CSInOut[0].g_ZofLookAt > 1.0 ) g_CSInOut[0].g_ZofLookAt = 1.0; else if( g_CSInOut[0].g_ZofLookAt < 0 ) g_CSInOut[0].g_ZofLookAt = 0; } // ************************************************************ // 被写界深度レンダリング // ************************************************************ // 頂点シェーダー VS03_OUT Step03_VS_Main( VS03_IN In ) { VS03_OUT Out; Out.pos = float4( In.pos, 1 ); Out.texel = In.texel; return Out; } // ピクセルシェーダ float4 Step03_PS_Main( VS03_OUT In ) : SV_Target0 { float4 Out = 0; // ターゲットとなるテクセル位置の深度値を取得 float ZofTarget = g_DepthMap.Sample( g_Sampler, In.texel ).z; // 深度値による補間係数 //float a = abs( g_ZofLookAt - ZofTarget ); float a = abs( g_ZofLookAtMap[0].g_ZofLookAt - ZofTarget ); float f = 1.0f / (float)g_MipMaxLevel; float low = 0; float high = 0; for( int i=0; i<g_MipMaxLevel; i++ ) { high = ( i + 1 ) * f; // 補間係数が2点間内のうちどこに含まれるか調べる if( low <= a && high >= a ) { // 補間係数を対象の2点間内で( 0 〜 1 )になるように変換する float a2 = ( a - (float)i * f ) * (float)g_MipMaxLevel; // 対象の2点上でのカラー情報を取得する float4 c0 = g_ColorMap.SampleLevel( g_Sampler, In.texel, i ); float4 c1 = g_ColorMap.SampleLevel( g_Sampler, In.texel, i + 1 ); // 線形合成する Out = c0 * ( 1.0f - a2 ) + c1 * a2; break; } low = high; } return Out; }---DepthOfField.h---
#ifndef DEPTHOFFIELD_H #define DEPTHOFFIELD_H #include "Polygon2DUser.h" class DEPTH_OF_FIELD { private: // シェーディング用の構造体定義 typedef struct _CB_STEP01 { // ワールド × ビュー × 射影 行列 D3DXMATRIX matWVP; // 平行光源の方向ベクトル。w成分はZfar値。 D3DXVECTOR4 vecLight; }CB_STEP01; // 注視点の深度値取得用の構造体定義 typedef struct _CB_STEP02 { // テクセル座標上での注視点の座標 D3DXVECTOR2 LookAt; // 被写界深度の変更速度 float Speed; float Dummy3; }CB_STEP02; // 被写界深度用の構造体定義 typedef struct _CB_STEP03 { // ミップマップレベルの最大値 float MipMaxLevel; // コンピュートシェーダーを使用する場合は使用しない float ZofLookAt; float Dummy2; float Dummy3; }CB_STEP03; // コンピュータシェーダー用の構造化バッファ typedef struct _CS_INOUT { float ZofLookAt; }CS_INOUT; // シェーディング用で使用するリソースの構造体定義 typedef struct _STEP01 { // 入力レイアウト ID3D11InputLayout* pLayout; // 頂点シェーダー ID3D11VertexShader* pVertexShader; // ピクセルシェーダー ID3D11PixelShader* pPixelShader; // 定数バッファ ID3D11Buffer* pConstantBuffers; // サンプラーステート ID3D11SamplerState* pSamplerState; // 深度ステンシルステート ID3D11DepthStencilState* pDepthStencilState; }STEP01; // 注視点の深度値取得で使用するリソースの構造体定義 typedef struct _STEP02 { // コンピュートシェーダー ID3D11ComputeShader* pComputeShader; // 定数バッファ ID3D11Buffer* pConstantBuffers; // アンオーダードアクセスビュー ID3D11UnorderedAccessView* pUAView; // アンオーダードアクセスビューからシェーダーリソースビューを作成する ID3D11ShaderResourceView* pSRView; }STEP02; // 被写界深度で使用するリソースの構造体定義 typedef struct _STEP03 { // 入力レイアウト ID3D11InputLayout* pLayout; // 頂点シェーダー ID3D11VertexShader* pVertexShader; // ピクセルシェーダー ID3D11PixelShader* pPixelShader; // 定数バッファ ID3D11Buffer* pConstantBuffers; // サンプラーステート ID3D11SamplerState* pSamplerState; // 深度ステンシルステート ID3D11DepthStencilState* pDepthStencilState; }STEP03; // ブレンドステート ID3D11BlendState* m_pBlendState; CPolygon2D m_Polygon2D; // 宣言 STEP01 m_Step01; STEP02 m_Step02; STEP03 m_Step03; // 注視点の深度値( コンピュートシェーダーを使用する場合は使用しない ) float m_ZofLookAt; private: // 共通項目の初期化 HRESULT InitCommon( ID3D11Device* pD3DDevice ); // シェーディング用の初期化 HRESULT InitStep01( ID3D11Device* pD3DDevice , const BYTE* pVSStep01Shader, size_t VSStep01Size , const BYTE* pPSStep01Shader, size_t PSStep01Size ); // 注視点の深度値取得の初期化 HRESULT InitStep02( ID3D11Device* pD3DDevice , const BYTE* pCSStep02Shader, size_t CSStep02Size ); // DepthOfFiled用の初期化 HRESULT InitStep03( ID3D11Device* pD3DDevice , const BYTE* pVSStep03Shader, size_t VSStep03Size , const BYTE* pPSStep03Shader, size_t PSStep03Size ); // S10E5フォーマット形式にしたがってメモリに格納されている WORD型 変数を 浮動小数点数 で認識できるように変換する double ConvS10E5Format( WORD Data ); public: DEPTH_OF_FIELD(); ~DEPTH_OF_FIELD(); // 初期化 HRESULT Init( ID3D11Device* pD3DDevice // hlslファイルのファイル名 , TCHAR pSrcFile[] // シェーディング , CHAR pVSStep01FunctionName[], CHAR pPSStep01FunctionName[] // 注視点の深度値取得 , CHAR pCSStep02FunctionName[] // 被写界深度レンダリング , CHAR pVSStep03FunctionName[], CHAR pPSStep03FunctionName[] ); HRESULT Init( ID3D11Device* pD3DDevice // シェーディング , const BYTE* pVSStep01Shader, size_t VSStep01Size, const BYTE* pPSStep01Shader, size_t PSStep01Size // 注視点の深度値取得 , const BYTE* pCSStep02Shader, size_t CSStep02Size // 被写界深度レンダリング , const BYTE* pVSStep03Shader, size_t VSStep03Size, const BYTE* pPSStep03Shader, size_t PSStep03Size ); // シェーディング用描画関数 HRESULT BeginStep01( ID3D11DeviceContext* pD3DDeviceContext ); // 定数バッファを設定 HRESULT SetCBStep01( ID3D11DeviceContext* pD3DDeviceContext , D3DXMATRIX* p_matWVP , float Zfar , D3DXVECTOR4* p_vecLight , ID3D11ShaderResourceView* pDecalMap ); HRESULT EndStep01( ID3D11DeviceContext* pD3DDeviceContext, ID3D11ShaderResourceView* pSRView ); // 注視点の深度値を取得する( コンピュートシェーダーを使用する場合は使用しない ) HRESULT GetZofLookAt( ID3D11Device* pD3DDevice, ID3D11DeviceContext* pD3DDeviceContext , ID3D11ShaderResourceView* pSRView , D3DXVECTOR2* pLookAt , float Speed ); // 定数バッファを設定 HRESULT SetCBStep02( ID3D11DeviceContext* pD3DDeviceContext, D3DXVECTOR2* pLookAt, float Speed ); // 注視点の深度値取得処理用関数 HRESULT StartStep02( ID3D11DeviceContext* pD3DDeviceContext, ID3D11ShaderResourceView* pSRView[2] ); // 定数バッファを設定 HRESULT SetCBStep03( ID3D11DeviceContext* pD3DDeviceContext, float MipMaxLevel, ID3D11ShaderResourceView* pSRView[2] ); // DepthOfField用描画関数 HRESULT RenderStep03( ID3D11DeviceContext* pD3DDeviceContext ); }; #endif---DepthOfField.cpp---
#include "DX11User.h" #include "DepthOfField.h" DEPTH_OF_FIELD::DEPTH_OF_FIELD() { m_Step01.pLayout = NULL; m_Step01.pVertexShader = NULL; m_Step01.pPixelShader = NULL; m_Step01.pConstantBuffers = NULL; m_Step01.pSamplerState = NULL; m_Step01.pDepthStencilState = NULL; m_Step02.pComputeShader = NULL; m_Step02.pConstantBuffers = NULL; m_Step02.pUAView = NULL; m_Step02.pSRView = NULL; m_Step03.pLayout = NULL; m_Step03.pVertexShader = NULL; m_Step03.pPixelShader = NULL; m_Step03.pConstantBuffers = NULL; m_Step03.pSamplerState = NULL; m_Step03.pDepthStencilState = NULL; m_pBlendState = NULL; m_ZofLookAt = 0.0f; } DEPTH_OF_FIELD::~DEPTH_OF_FIELD() { SAFE_RELEASE( m_Step01.pLayout ); SAFE_RELEASE( m_Step01.pVertexShader ); SAFE_RELEASE( m_Step01.pPixelShader ); SAFE_RELEASE( m_Step01.pConstantBuffers ); SAFE_RELEASE( m_Step01.pSamplerState ); SAFE_RELEASE( m_Step01.pDepthStencilState ); SAFE_RELEASE( m_Step02.pComputeShader ); SAFE_RELEASE( m_Step02.pConstantBuffers ); SAFE_RELEASE( m_Step02.pUAView ); SAFE_RELEASE( m_Step02.pSRView ); SAFE_RELEASE( m_Step03.pLayout ); SAFE_RELEASE( m_Step03.pVertexShader ); SAFE_RELEASE( m_Step03.pPixelShader ); SAFE_RELEASE( m_Step03.pConstantBuffers ); SAFE_RELEASE( m_Step03.pSamplerState ); SAFE_RELEASE( m_Step03.pDepthStencilState ); SAFE_RELEASE( m_pBlendState ); } // 共通項目の初期化 HRESULT DEPTH_OF_FIELD::InitCommon( ID3D11Device* pD3DDevice ) { HRESULT hr = E_FAIL; // ***************************************************************************************************************** // ブレンドステートの作成 // ***************************************************************************************************************** D3D11_BLEND_DESC BlendDesc; ::ZeroMemory( &BlendDesc, sizeof( BlendDesc ) ); BlendDesc.AlphaToCoverageEnable = FALSE; BlendDesc.IndependentBlendEnable = FALSE; // アルファブレンドを無効 BlendDesc.RenderTarget[0].BlendEnable = FALSE; BlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; BlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; BlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; BlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; BlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; hr = pD3DDevice->CreateBlendState( &BlendDesc, &m_pBlendState ); if( FAILED( hr ) ) goto EXIT; hr = S_OK; EXIT: return hr; } // シェーディング用の初期化 HRESULT DEPTH_OF_FIELD::InitStep01( ID3D11Device* pD3DDevice , const BYTE* pVSStep01Shader, size_t VSStep01Size , const BYTE* pPSStep01Shader, size_t PSStep01Size ) { HRESULT hr = E_FAIL; D3D11_BUFFER_DESC BufferDesc; if( pD3DDevice == NULL ) goto EXIT; // ***************************************************************************************************************** // 頂点シェーダーの作成 // ***************************************************************************************************************** hr = pD3DDevice->CreateVertexShader( pVSStep01Shader, VSStep01Size, NULL, &m_Step01.pVertexShader ); if( FAILED( hr ) ) goto EXIT; // 入力レイアウトは固定設定にしておく D3D11_INPUT_ELEMENT_DESC layout[] = { { "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 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; hr = pD3DDevice->CreateInputLayout( layout, _countof( layout ), pVSStep01Shader, VSStep01Size, &m_Step01.pLayout ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // ピクセルェーダーの作成 // ***************************************************************************************************************** hr = pD3DDevice->CreatePixelShader( pPSStep01Shader, PSStep01Size, NULL, &m_Step01.pPixelShader ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // 定数バッファを作成 // ***************************************************************************************************************** ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) ); BufferDesc.ByteWidth = sizeof( CB_STEP01 ); // バッファサイズ BufferDesc.Usage = D3D11_USAGE_DYNAMIC; // リソース使用法を特定する BufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;// バッファの種類 BufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // CPU アクセス BufferDesc.MiscFlags = 0; // その他のフラグも設定しない hr = pD3DDevice->CreateBuffer( &BufferDesc, NULL, &m_Step01.pConstantBuffers ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // サンプラーステートの作成 // ***************************************************************************************************************** D3D11_SAMPLER_DESC samplerDesc; samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; // サンプリング時に使用するフィルタ。ここでは線形補間を使用する。 samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; // 0 〜 1 の範囲外にある u テクスチャー座標の描画方法 samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; // 0 〜 1 の範囲外にある v テクスチャー座標 samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; // 0 〜 1 の範囲外にある w テクスチャー座標 samplerDesc.MipLODBias = 0; // 計算されたミップマップ レベルからのバイアス samplerDesc.MaxAnisotropy = 1; // サンプリングに異方性補間を使用している場合の限界値。有効な値は 1 〜 16 。 samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; // 比較オプション。 ::CopyMemory( samplerDesc.BorderColor, &D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 0.0f ), sizeof( D3DXVECTOR4 ) ); // 境界色 samplerDesc.MinLOD = 0; // アクセス可能なミップマップの下限値 samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; // アクセス可能なミップマップの上限値 hr = pD3DDevice->CreateSamplerState( &samplerDesc, &m_Step01.pSamplerState ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // 深度ステンシルステートの作成 // ***************************************************************************************************************** // 深度ステンシルステートを作成する D3D11_DEPTH_STENCIL_DESC ddsDesc; ::ZeroMemory( &ddsDesc, sizeof( ddsDesc ) ); ddsDesc.DepthEnable = TRUE; // 深度テストを有効 ddsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; // 深度バッファへの書き込みを行う ddsDesc.DepthFunc = D3D11_COMPARISON_LESS; ddsDesc.StencilEnable = FALSE; hr = pD3DDevice->CreateDepthStencilState( &ddsDesc, &m_Step01.pDepthStencilState ); if( FAILED( hr ) ) goto EXIT; hr = S_OK; EXIT: return hr; } // 注視点の深度値取得用の初期化 HRESULT DEPTH_OF_FIELD::InitStep02( ID3D11Device* pD3DDevice , const BYTE* pCSStep02Shader, size_t CSStep02Size ) { HRESULT hr = E_FAIL; D3D11_BUFFER_DESC BufferDesc; ID3D11Buffer* pBuf = NULL; ID3D11Resource* pResource = NULL; CS_INOUT initData; if( pD3DDevice == NULL ) goto EXIT; // ***************************************************************************************************************** // コンピュートシェーダーの作成 // ***************************************************************************************************************** hr = pD3DDevice->CreateComputeShader( pCSStep02Shader, CSStep02Size, NULL, &m_Step02.pComputeShader ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // 定数バッファを作成 // ***************************************************************************************************************** ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) ); BufferDesc.ByteWidth = sizeof( CB_STEP02 ); // バッファサイズ BufferDesc.Usage = D3D11_USAGE_DYNAMIC; // リソース使用法を特定する BufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;// バッファの種類 BufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // CPU アクセス BufferDesc.MiscFlags = 0; // その他のフラグも設定しない hr = pD3DDevice->CreateBuffer( &BufferDesc, NULL, &m_Step02.pConstantBuffers ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // UAVの作成 // ***************************************************************************************************************** ::ZeroMemory( &BufferDesc, sizeof(D3D11_BUFFER_DESC) ); BufferDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | // アンオーダード アクセス リソースをバインドする D3D11_BIND_SHADER_RESOURCE; // バッファーをシェーダー ステージにバインドする BufferDesc.ByteWidth = sizeof( CS_INOUT ) * 1; // バッファサイズ BufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; // 構造化バッファーとしてリソースを作成する BufferDesc.StructureByteStride = sizeof( CS_INOUT ); // 構造化バッファーのサイズ (バイト単位) // 初期値を設定する initData.ZofLookAt = 0.0f; D3D11_SUBRESOURCE_DATA SubResource; ::ZeroMemory( &SubResource, sizeof( D3D11_SUBRESOURCE_DATA ) ); SubResource.pSysMem = &initData; hr = pD3DDevice->CreateBuffer( &BufferDesc, &SubResource, &pBuf ); if( FAILED( hr ) ) goto EXIT; D3D11_UNORDERED_ACCESS_VIEW_DESC UAVDesc; ZeroMemory( &UAVDesc, sizeof(D3D11_UNORDERED_ACCESS_VIEW_DESC) ); UAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; // バッファーであることを指定する UAVDesc.Buffer.FirstElement = 0; UAVDesc.Format = DXGI_FORMAT_UNKNOWN; UAVDesc.Buffer.NumElements = 1; // リソース内の要素の数 // アンオーダード アクセス ビューを作成する hr = pD3DDevice->CreateUnorderedAccessView( pBuf, &UAVDesc, &m_Step02.pUAView ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // SRVの作成 // ***************************************************************************************************************** m_Step02.pUAView->GetResource( &pResource ); D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; ZeroMemory( &SRVDesc, sizeof( SRVDesc ) ); SRVDesc.Format = DXGI_FORMAT_UNKNOWN; SRVDesc.Buffer.ElementOffset = 0; SRVDesc.Buffer.ElementWidth = 1; SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; // シェーダーリソースビューを作成する hr = pD3DDevice->CreateShaderResourceView( pResource, &SRVDesc, &m_Step02.pSRView ); if( FAILED( hr ) ) goto EXIT; hr = S_OK; EXIT: SAFE_RELEASE( pBuf ); SAFE_RELEASE( pResource ); return hr; } // 被写界深度の初期化 HRESULT DEPTH_OF_FIELD::InitStep03( ID3D11Device* pD3DDevice , const BYTE* pVSStep03Shader, size_t VSStep03Size , const BYTE* pPSStep03Shader, size_t PSStep03Size ) { HRESULT hr = E_FAIL; D3D11_BUFFER_DESC BufferDesc; if( pD3DDevice == NULL ) goto EXIT; // 2Dポリクラスの作成処理 hr = m_Polygon2D.Create( pD3DDevice ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // 頂点シェーダーの作成 // ***************************************************************************************************************** hr = pD3DDevice->CreateVertexShader( pVSStep03Shader, VSStep03Size, NULL, &m_Step03.pVertexShader ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // 入力レイアウトの作成 // ***************************************************************************************************************** D3D11_INPUT_ELEMENT_DESC* pInputElement = NULL; UINT InputElementCount; m_Polygon2D.GetInputElement( &pInputElement, &InputElementCount ); hr = pD3DDevice->CreateInputLayout( pInputElement, InputElementCount, pVSStep03Shader, VSStep03Size, &m_Step03.pLayout ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // ピクセルェーダーの作成 // ***************************************************************************************************************** hr = pD3DDevice->CreatePixelShader( pPSStep03Shader, PSStep03Size, NULL, &m_Step03.pPixelShader ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // 定数バッファを作成 // ***************************************************************************************************************** ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) ); BufferDesc.ByteWidth = sizeof( CB_STEP03 ); // バッファサイズ BufferDesc.Usage = D3D11_USAGE_DYNAMIC; // リソース使用法を特定する BufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;// バッファの種類 BufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // CPU アクセス BufferDesc.MiscFlags = 0; // その他のフラグも設定しない hr = pD3DDevice->CreateBuffer( &BufferDesc, NULL, &m_Step03.pConstantBuffers ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // サンプラーステートの作成 // ***************************************************************************************************************** D3D11_SAMPLER_DESC samplerDesc; samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; // ブラーを適応するので CLAMP で設定する samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; // ブラーを適応するので CLAMP で設定する samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; // ブラーを適応するので CLAMP で設定する samplerDesc.MipLODBias = 0; // 計算されたミップマップ レベルからのバイアス samplerDesc.MaxAnisotropy = 1; // サンプリングに異方性補間を使用している場合の限界値。有効な値は 1 〜 16 。 samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; // 比較オプション。 ::CopyMemory( samplerDesc.BorderColor, &D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 0.0f ), sizeof( D3DXVECTOR4 ) ); // 境界色 samplerDesc.MinLOD = 0; // アクセス可能なミップマップの下限値 samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; // アクセス可能なミップマップの上限値 hr = pD3DDevice->CreateSamplerState( &samplerDesc, &m_Step03.pSamplerState ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // 深度ステンシルステートの作成 // ***************************************************************************************************************** // 深度ステンシルステートを作成する D3D11_DEPTH_STENCIL_DESC ddsDesc; ::ZeroMemory( &ddsDesc, sizeof( ddsDesc ) ); ddsDesc.DepthEnable = FALSE; // 深度テストを無効 ddsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; // 深度バッファへの書き込みを行わない ddsDesc.DepthFunc = D3D11_COMPARISON_LESS; ddsDesc.StencilEnable = FALSE; hr = pD3DDevice->CreateDepthStencilState( &ddsDesc, &m_Step03.pDepthStencilState ); if( FAILED( hr ) ) goto EXIT; hr = S_OK; EXIT: return hr; } // 初期化 HRESULT DEPTH_OF_FIELD::Init( ID3D11Device* pD3DDevice // hlsl ファイル名 , TCHAR pSrcFile[] // シェーディング , CHAR pVSStep01FunctionName[], CHAR pPSStep01FunctionName[] // 注視点の深度値取得 , CHAR pCSStep02FunctionName[] // 被写界深度レンダリング , CHAR pVSStep03FunctionName[], CHAR pPSStep03FunctionName[] ) { HRESULT hr = E_FAIL; ID3D10Blob* pBlob[2] = { NULL, NULL }; UINT Flag1 = D3D10_SHADER_PACK_MATRIX_COLUMN_MAJOR | D3D10_SHADER_ENABLE_STRICTNESS; #if defined(DEBUG) || defined(_DEBUG) Flag1 |= D3D10_SHADER_OPTIMIZATION_LEVEL0; #else Flag1 |= D3D10_SHADER_OPTIMIZATION_LEVEL3; #endif // ***************************************************************************************************************** // シェーディング用のシェーダーソースファイルのコンパイル // ***************************************************************************************************************** // 頂点シェーダーのコンパイル hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pVSStep01FunctionName, "vs_4_0", Flag1, 0, NULL, &pBlob[0], NULL, NULL ); if( FAILED( hr ) ) goto EXIT; // ピクセルシェーダーのコンパイル hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pPSStep01FunctionName, "ps_4_0", Flag1, 0, NULL, &pBlob[1], NULL, NULL ); if( FAILED( hr ) ) goto EXIT; // 初期化 hr = InitStep01( pD3DDevice , reinterpret_cast<LPBYTE>( pBlob[0]->GetBufferPointer() ), pBlob[0]->GetBufferSize() , reinterpret_cast<LPBYTE>( pBlob[1]->GetBufferPointer() ), pBlob[1]->GetBufferSize() ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // 注視点の深度値取得用のシェーダーソースファイルのコンパイル // ***************************************************************************************************************** // コンピュートシェーダーのコンパイル hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pCSStep02FunctionName, "cs_4_0", Flag1, 0, NULL, &pBlob[0], NULL, NULL ); if( FAILED( hr ) ) goto EXIT; // 初期化 hr = InitStep02( pD3DDevice , reinterpret_cast<LPBYTE>( pBlob[0]->GetBufferPointer() ), pBlob[0]->GetBufferSize() ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // DepthOfField用のシェーダーソースファイルのコンパイル // ***************************************************************************************************************** // 頂点シェーダーのコンパイル hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pVSStep03FunctionName, "vs_4_0", Flag1, 0, NULL, &pBlob[0], NULL, NULL ); if( FAILED( hr ) ) goto EXIT; // ピクセルシェーダーのコンパイル hr = D3DX11CompileFromFile( pSrcFile, NULL, NULL, pPSStep03FunctionName, "ps_4_0", Flag1, 0, NULL, &pBlob[1], NULL, NULL ); if( FAILED( hr ) ) goto EXIT; // 初期化 hr = InitStep03( pD3DDevice , reinterpret_cast<LPBYTE>( pBlob[0]->GetBufferPointer() ), pBlob[0]->GetBufferSize() , reinterpret_cast<LPBYTE>( pBlob[1]->GetBufferPointer() ), pBlob[1]->GetBufferSize() ); if( FAILED( hr ) ) goto EXIT; // ***************************************************************************************************************** // 共通項目の初期化 // ***************************************************************************************************************** hr = InitCommon( pD3DDevice ); if( FAILED( hr ) ) goto EXIT; hr = S_OK; EXIT: return hr; } // 初期化 HRESULT DEPTH_OF_FIELD::Init( ID3D11Device* pD3DDevice // シェーディング , const BYTE* pVSStep01Shader, size_t VSStep01Size, const BYTE* pPSStep01Shader, size_t PSStep01Size // 注視点の深度値取得 , const BYTE* pCSStep02Shader, size_t CSStep02Size // 被写界深度 , const BYTE* pVSStep03Shader, size_t VSStep03Size, const BYTE* pPSStep03Shader, size_t PSStep03Size ) { HRESULT hr = E_FAIL; // シェーディング用のリソースの初期化 hr = InitStep01( pD3DDevice, pVSStep01Shader, VSStep01Size, pPSStep01Shader, PSStep01Size ); if( FAILED( hr ) ) goto EXIT; // 注視点の深度値取得用のリソースの初期化 hr = InitStep02( pD3DDevice, pCSStep02Shader, CSStep02Size ); if( FAILED( hr ) ) goto EXIT; // DepthOfField用のリソースの初期化 hr = InitStep03( pD3DDevice, pVSStep03Shader, VSStep03Size, pPSStep03Shader, PSStep03Size ); if( FAILED( hr ) ) goto EXIT; // 共通項目の初期化 hr = InitCommon( pD3DDevice ); if( FAILED( hr ) ) goto EXIT; hr = S_OK; EXIT: return hr; } HRESULT DEPTH_OF_FIELD::BeginStep01( ID3D11DeviceContext* pD3DDeviceContext ) { HRESULT hr = E_FAIL; // ***************************************************************************************************************** // 入力アセンブラー ステージを設定 // ***************************************************************************************************************** pD3DDeviceContext->IASetInputLayout( m_Step01.pLayout ); // ***************************************************************************************************************** // シェーダーをデバイスに設定 // ***************************************************************************************************************** // 頂点シェーダーをデバイスに設定する。 pD3DDeviceContext->VSSetShader( m_Step01.pVertexShader, NULL, 0 ); // ハルシェーダーを無効にする。 pD3DDeviceContext->HSSetShader( NULL, NULL, 0 ); // ドメインシェーダーを無効にする。 pD3DDeviceContext->DSSetShader( NULL, NULL, 0 ); // ジオメトリシェーダーを無効にする。 pD3DDeviceContext->GSSetShader( NULL, NULL, 0 ); // ピクセルシェーダーをデバイスに設定する pD3DDeviceContext->PSSetShader( m_Step01.pPixelShader, NULL, 0 ); // ピクセルシェーダーにサンプラーステートを設定する。 pD3DDeviceContext->PSSetSamplers( 0, 1, &m_Step01.pSamplerState ); // コンピュートシェーダーを無効にする。 pD3DDeviceContext->CSSetShader( NULL, NULL, 0 ); // ***************************************************************************************************************** // 出力結合ステージを設定 // ***************************************************************************************************************** // ブレンドステートを設定 pD3DDeviceContext->OMSetBlendState( m_pBlendState, 0, 0xffffffff ); // 深度ステンシルステートを設定 pD3DDeviceContext->OMSetDepthStencilState( m_Step01.pDepthStencilState, 0 ); hr = S_OK; //EXIT: return hr; } HRESULT DEPTH_OF_FIELD::SetCBStep01( ID3D11DeviceContext* pD3DDeviceContext, D3DXMATRIX* p_matWVP, float Zfar, D3DXVECTOR4* p_vecLight, ID3D11ShaderResourceView* pDecalMap ) { HRESULT hr = E_FAIL; // ***************************************************************************************************************** // 定数バッファを設定 // ***************************************************************************************************************** D3D11_MAPPED_SUBRESOURCE mappedResource; CB_STEP01* cbuffer; hr = pD3DDeviceContext->Map( m_Step01.pConstantBuffers, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ); if( FAILED( hr ) ) goto EXIT; cbuffer = reinterpret_cast<CB_STEP01*>(mappedResource.pData); ::CopyMemory( &cbuffer->matWVP, p_matWVP, sizeof( D3DXMATRIX )); ::CopyMemory( &cbuffer->vecLight, p_vecLight, sizeof( D3DXVECTOR4 )); cbuffer->vecLight.w = Zfar; pD3DDeviceContext->Unmap( m_Step01.pConstantBuffers, 0 ); // ***************************************************************************************************************** // 定数バッファをデバイスに設定 // ***************************************************************************************************************** // 頂点シェーダーに定数バッファを設定する pD3DDeviceContext->VSSetConstantBuffers( 0, 1, &m_Step01.pConstantBuffers ); // ピクセルシェーダーに定数バッファを設定する pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_Step01.pConstantBuffers ); // デカールマップを設定する pD3DDeviceContext->PSSetShaderResources( 0, 1, &pDecalMap ); hr = S_OK; EXIT: return hr; } HRESULT DEPTH_OF_FIELD::EndStep01( ID3D11DeviceContext* pD3DDeviceContext, ID3D11ShaderResourceView* pSRView ) { HRESULT hr = E_FAIL; // ミップマップチェーンを作成する pD3DDeviceContext->GenerateMips( pSRView ); hr = S_OK; //EXIT: return hr; } // 注視点の深度値 HRESULT DEPTH_OF_FIELD::GetZofLookAt( ID3D11Device* pD3DDevice, ID3D11DeviceContext* pD3DDeviceContext , ID3D11ShaderResourceView* pSRView , D3DXVECTOR2* pLookAt , float Speed ) { HRESULT hr = E_FAIL; D3D11_BOX sourceRegion; ID3D11Resource* pZMapResource = NULL; pSRView->GetResource( &pZMapResource ); ID3D11Texture2D* pZMapTexture = reinterpret_cast<ID3D11Texture2D*>(pZMapResource); D3D11_TEXTURE2D_DESC ZMapTexDesc; // 深度マップのテクスチャーの設定を取得 pZMapTexture->GetDesc( &ZMapTexDesc ); // CPUから読み込み可能なテクスチャーを作成する ID3D11Texture2D* pCPUReadTexture = NULL; D3D11_TEXTURE2D_DESC desc; ::ZeroMemory( &desc, sizeof( D3D11_TEXTURE2D_DESC ) ); desc.Width = 1; desc.Height = 1; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = ZMapTexDesc.Format; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_STAGING; // GPU から CPU へのデータ転送 (コピー) をサポートするリソースです。 desc.BindFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.MiscFlags = 0; hr = pD3DDevice->CreateTexture2D( &desc, NULL, &pCPUReadTexture ); if( FAILED( hr ) ) goto EXIT; // コピー領域を指定 sourceRegion.left = (UINT)pLookAt->x; sourceRegion.top = (UINT)pLookAt->y; sourceRegion.front = 0; sourceRegion.right = (UINT)pLookAt->x + 1; sourceRegion.bottom = (UINT)pLookAt->y + 1; sourceRegion.back = 1; // コピー領域を指定して部分コピー // これでも遅い。。。 pD3DDeviceContext->CopySubresourceRegion( pCPUReadTexture, 0, 0, 0, 0, pZMapResource, 0, &sourceRegion ); D3D11_MAPPED_SUBRESOURCE mappedResource; // GPUアクセスをロックしてCPUから読み込み開始 // ここもパフォーマンス低下の原因になってる。。。 hr = pD3DDeviceContext->Map( pCPUReadTexture, NULL, D3D11_MAP_READ, 0, &mappedResource ); if( FAILED( hr ) ) goto EXIT; // pCPUReadTexture から注視点の深度値を取得する // DXGI_FORMAT_R16G16B16A16_FLOAT フォーマットを使用するので64Bit変数にキャストする unsigned long long* TextureBits = reinterpret_cast<unsigned long long*>(mappedResource.pData); // Z成分を抽出 // オンラインドキュメントにはデータの格納順に関する記述がないが、どうも AGBR の順に格納されているっぽい WORD ZBit = (*TextureBits)>>32 & 0xFFFF; float z = 0.0f; z = (float)ConvS10E5Format( ZBit ); pD3DDeviceContext->Unmap( pCPUReadTexture, NULL ); // 注視点の深度値の変更 if( m_ZofLookAt < z ) m_ZofLookAt += Speed; else if( m_ZofLookAt > z ) m_ZofLookAt -= Speed; if( m_ZofLookAt > 1.0 ) m_ZofLookAt = 1.0; else if( m_ZofLookAt < 0 ) m_ZofLookAt = 0; SAFE_RELEASE( pZMapResource ); SAFE_RELEASE( pCPUReadTexture ); hr = S_OK; EXIT: return hr; } // 定数バッファを設定 HRESULT DEPTH_OF_FIELD::SetCBStep02( ID3D11DeviceContext* pD3DDeviceContext, D3DXVECTOR2* pLookAt, float Speed ) { HRESULT hr = E_FAIL; // ***************************************************************************************************************** // 定数バッファを設定 // ***************************************************************************************************************** D3D11_MAPPED_SUBRESOURCE mappedResource; CB_STEP02* cbuffer; hr = pD3DDeviceContext->Map( m_Step02.pConstantBuffers, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ); if( FAILED( hr ) ) goto EXIT; cbuffer = reinterpret_cast<CB_STEP02*>(mappedResource.pData); ::CopyMemory( &cbuffer->LookAt, pLookAt, sizeof( D3DXVECTOR2 )); cbuffer->Speed = Speed; pD3DDeviceContext->Unmap( m_Step02.pConstantBuffers, 0 ); // ***************************************************************************************************************** // 定数バッファをデバイスに設定 // ***************************************************************************************************************** // コンピュートシェーダーに定数バッファを設定する pD3DDeviceContext->CSSetConstantBuffers( 0, 1, &m_Step02.pConstantBuffers ); hr = S_OK; EXIT: return hr; } // 注視点の深度値取得処理用関数 HRESULT DEPTH_OF_FIELD::StartStep02( ID3D11DeviceContext* pD3DDeviceContext, ID3D11ShaderResourceView* pSRView[2] ) { HRESULT hr = E_FAIL; // ***************************************************************************************************************** // コンピュートシェーダーで注視点の深度値を取得する // ***************************************************************************************************************** pD3DDeviceContext->CSSetShader( m_Step02.pComputeShader, NULL, 0 ); // アンオーダードアクセスビューをコンピュートシェーダーに設定 pD3DDeviceContext->CSSetUnorderedAccessViews( 0, 1, &m_Step02.pUAView, NULL ); // テクスチャーを設定する // Index0:未使用 // Index1:深度ステンシルバッファ pD3DDeviceContext->CSSetShaderResources( 0, 2, pSRView ); // コンピュートシェーダーを実行 // シングルスレッドのため ALL 1 pD3DDeviceContext->Dispatch( 1, 1, 1 ); // アンオーダードアクセスビューを無効にする ID3D11UnorderedAccessView* ppUAViewNULL[1] = { NULL }; pD3DDeviceContext->CSSetUnorderedAccessViews( 0, 1, ppUAViewNULL, NULL ); // シェーダーリソースビューを無効にする ID3D11ShaderResourceView* pSRVNull[2] = { NULL, NULL }; pD3DDeviceContext->CSSetShaderResources( 0, _countof( pSRVNull ), pSRVNull ); hr = S_OK; //EXIT: return hr; } // 定数バッファを設定 HRESULT DEPTH_OF_FIELD::SetCBStep03( ID3D11DeviceContext* pD3DDeviceContext, float MipMaxLevel, ID3D11ShaderResourceView* pSRView[2] ) { HRESULT hr = E_FAIL; // ***************************************************************************************************************** // 定数バッファを設定 // ***************************************************************************************************************** D3D11_MAPPED_SUBRESOURCE mappedResource; CB_STEP03* cbuffer; hr = pD3DDeviceContext->Map( m_Step03.pConstantBuffers, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ); if( FAILED( hr ) ) goto EXIT; cbuffer = reinterpret_cast<CB_STEP03*>(mappedResource.pData); cbuffer->MipMaxLevel = MipMaxLevel; cbuffer->ZofLookAt = m_ZofLookAt; pD3DDeviceContext->Unmap( m_Step03.pConstantBuffers, 0 ); // ***************************************************************************************************************** // 定数バッファをデバイスに設定 // ***************************************************************************************************************** // ピクセルシェーダーに定数バッファを設定する pD3DDeviceContext->PSSetConstantBuffers( 0, 1, &m_Step03.pConstantBuffers ); ID3D11ShaderResourceView* pSRVArray[3] = { pSRView[0], pSRView[1], m_Step02.pSRView }; // テクスチャーを設定する // Index0:シーンのレンダリングイメージ // Index1:深度ステンシルバッファ // Index2:注視点深度バッファ pD3DDeviceContext->PSSetShaderResources( 0, 3, pSRVArray ); hr = S_OK; EXIT: return hr; } // DepthOfField用描画関数 HRESULT DEPTH_OF_FIELD::RenderStep03( ID3D11DeviceContext* pD3DDeviceContext ) { HRESULT hr = E_FAIL; // ***************************************************************************************************************** // 入力アセンブラー ステージを設定 // ***************************************************************************************************************** // 入力レイアウト設定 pD3DDeviceContext->IASetInputLayout( m_Step03.pLayout ); // 頂点バッファはCPolygon2Dクラス内部で設定するのでここでは設定しない // ***************************************************************************************************************** // シェーダーをデバイスに設定 // ***************************************************************************************************************** // 頂点シェーダーをデバイスに設定する。 pD3DDeviceContext->VSSetShader( m_Step03.pVertexShader, NULL, 0 ); // ハルシェーダーを無効にする。 pD3DDeviceContext->HSSetShader( NULL, NULL, 0 ); // ドメインシェーダーを無効にする pD3DDeviceContext->DSSetShader( NULL, NULL, 0 ); // ジオメトリシェーダーを無効にする。 pD3DDeviceContext->GSSetShader( NULL, NULL, 0 ); // ピクセルシェーダーをデバイスに設定する。 pD3DDeviceContext->PSSetShader( m_Step03.pPixelShader, NULL, 0 ); // ピクセルシェーダーにサンプラーステートを設定する。 pD3DDeviceContext->PSSetSamplers( 0, 1, &m_Step03.pSamplerState ); // コンピュートシェーダーを無効にする。 pD3DDeviceContext->CSSetShader( NULL, NULL, 0 ); // ***************************************************************************************************************** // 出力結合ステージを設定 // ***************************************************************************************************************** // ブレンドステートを設定 pD3DDeviceContext->OMSetBlendState( m_pBlendState, 0, 0xffffffff ); // 深度ステンシルステートを設定 pD3DDeviceContext->OMSetDepthStencilState( m_Step03.pDepthStencilState, 0 ); // ***************************************************************************************************************** // 描画 // ***************************************************************************************************************** m_Polygon2D.Render( pD3DDeviceContext ); // シェーダーリソースビューを無効にする ID3D11ShaderResourceView* pSRVNull[3] = { NULL, NULL, NULL }; pD3DDeviceContext->PSSetShaderResources( 0, _countof( pSRVNull ), pSRVNull ); hr = S_OK; //EXIT: return hr; } // S10E5フォーマット形式にしたがってメモリに格納されている WORD型 変数を 浮動小数点数 で認識できるように変換する double DEPTH_OF_FIELD::ConvS10E5Format( WORD Data ) { // 指数部のビットがすべて 0 または 1 のときは 0.0をかえす if( ( Data & 0x7C00 ) == 0x0 || ( Data & 0x7C00 ) == 0x7C00 ) return 0.0; // 符号部を取得 // 0のとき+ // 1のとき- double Hugo = double( ( Data >> 15 ) & 0x1 ); // 指数部を取得 double Sisubu = double( ( Data >> 10 ) & 0x1F ) - 15.0; // 仮数部を取得 WORD Kasubu = Data & 0x3FF; double k = 1.0; for( int i=10; i>=0; i-- ) { WORD d = Kasubu & 0x1; if( d ) k+=pow( 2.0, -1.0 * (double)i ); Kasubu = Kasubu >> 1; } return pow( -1.0, Hugo ) * k * pow( 2.0, Sisubu ); }---main.cpp---
#include "../../USER/DX11User.h" #include "../../USER/D3D11User.h" #include "../../USER/DebugFontUser.h" #include "../../USER/DepthOfField.h" // FBX SDK 用 #include "../../USER/MeshUser.h" #include "../../USER/FBXSDKMeshLoaderUser.h" // シェーダーオブジェクトを作成するとき、ファイルから読むか、メモリから読むかを切り替える #if defined(DEBUG) || defined(_DEBUG) #define UNCOMPILED_SHADER // ファイルを読み込んでコンパイルする #else // 被写界深度用 #include "../../USER/HLSL/DepthOfField_Step01_VS_Main.h" #include "../../USER/HLSL/DepthOfField_Step01_PS_Main.h" #include "../../USER/HLSL/DepthOfField_Step02_CS_Main.h" #include "../../USER/HLSL/DepthOfField_Step03_VS_Main.h" #include "../../USER/HLSL/DepthOfField_Step03_PS_Main.h" #endif // アプリケーション名 TCHAR* AppName = _T("DX11_Tutrial 171 Depth Of Field"); // Direct3D関連の自作クラス D3D11USER* g_pD3D11User = NULL; // デバッグ専用のテキスト描画する自作クラス CDebugFont* g_pDebugFontUser = NULL; // FBX メッシュローダー FBXSDK_MESHLOADER_USER* g_pMeshLoader = NULL; // メッシュオブジェクト BASE_MESH_USER* g_pMesh = NULL; // Depth Of Fieldクラス DEPTH_OF_FIELD* g_pDepthOfField = NULL; // レンダーターゲットサーフェス ID3D11RenderTargetView* g_pRTView[2] = { NULL, NULL }; // 平行光源の方向ベクトル D3DXVECTOR4 g_vecLight = D3DXVECTOR4( -0.3f, -1.0f, 0.3f, 0.0f ); // 連続入力されたかを判定する際に使用するキーボード入力バッファ BYTE g_KeyBuffer[256]; // ビュー行列 D3DXMATRIX g_matView; // ミップマップチェーンの最大値。0のときすべてのミップマップチェーンを作成する。 #define MIPMAPLEVEL 7 // 節電モードの制御に使用する変数。 bool Activate = true; // ウィンドウがアクティブか bool StandBy = false; // スタンバイ状態か bool ScreenShot = false; // スクリーンショットを作成するかフラグ // リソースの初期化 HRESULT Init() { HRESULT hr = E_FAIL; // デバッグ専用フォント出力クラスの作成処理 // デバックコンパイル時のみ使用する #if defined(DEBUG) || defined(_DEBUG) g_pDebugFontUser = NEW CDebugFont(); hr = g_pDebugFontUser->Create( g_pD3D11User->m_D3DDevice, 0.015f, 0.04f ); if( FAILED( hr ) ) { ::MessageBox( NULL, _T("デバックフォントクラス初期化エラー"), _T("初期化エラー"), MB_OK ); goto EXIT; } #endif // 自作のメッシュローダーの初期化 g_pMeshLoader = NEW FBXSDK_MESHLOADER_USER(); hr = g_pMeshLoader->Initialize( g_pD3D11User->m_D3DDevice ); if( FAILED( hr ) ) goto EXIT; // 頂点情報を取得する hr = g_pMeshLoader->LoadMeshData( _T("Res/object.fbx"), &g_pMesh ); if( FAILED( hr ) ) goto EXIT; g_pDepthOfField = NEW DEPTH_OF_FIELD(); #ifndef UNCOMPILED_SHADER hr = g_pDepthOfField->Init( g_pD3D11User->m_D3DDevice , g_Step01_VS_Main, sizeof( g_Step01_VS_Main ) ,g_Step01_PS_Main, sizeof( g_Step01_PS_Main ) , g_Step02_CS_Main, sizeof( g_Step02_CS_Main ) , g_Step03_VS_Main, sizeof( g_Step03_VS_Main ) ,g_Step03_PS_Main, sizeof( g_Step03_PS_Main ) ); if( FAILED( hr ) ) goto EXIT; #else hr = g_pDepthOfField->Init( g_pD3D11User->m_D3DDevice ,_T("../../USER/HLSL/DepthOfField.hlsl") ,"Step01_VS_Main" ,"Step01_PS_Main" ,"Step02_CS_Main" ,"Step03_VS_Main" ,"Step03_PS_Main" ); if( FAILED( hr ) ) goto EXIT; #endif DXGI_SWAP_CHAIN_DESC chainDesc; // スワップチェーンの設定を取得する hr = g_pD3D11User->m_SwapChain->GetDesc( &chainDesc ); if( FAILED( hr ) ) goto EXIT; // レンダーターゲットビューの作成 hr = g_pD3D11User->CreateRenderTargetView( &g_pRTView[0], NULL, chainDesc.BufferDesc.Format, MIPMAPLEVEL ); if( FAILED( hr ) ) goto EXIT; hr = g_pD3D11User->CreateRenderTargetView( &g_pRTView[1], NULL, DXGI_FORMAT_R16G16B16A16_FLOAT ); if( FAILED( hr ) ) goto EXIT; // キーボード入力バッファの初期化 ::ZeroMemory( g_KeyBuffer, sizeof( BYTE ) * _countof( g_KeyBuffer ) ); // ビュー行列 D3DXMatrixLookAtLH( &g_matView, &D3DXVECTOR3( 0.0f, 0.0f, -20.0f ), &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ), &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) ); hr = S_OK; EXIT: return hr; } // メモリ開放 void Invalidate() { SAFE_DELETE( g_pDepthOfField ); SAFE_DELETE( g_pMesh ); SAFE_DELETE( g_pMeshLoader ); for( int i=0; i<_countof( g_pRTView ); i++ ) SAFE_RELEASE( g_pRTView[i] ); SAFE_DELETE( g_pDebugFontUser ); SAFE_DELETE( g_pD3D11User ); } // 地面描画 HRESULT RenderPlane( DEPTH_OF_FIELD* pDepthOfField, D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj, float Zfar ) { HRESULT hr = E_FAIL; D3DXMATRIX matScaling, matTranslation, matWorld, matWVP, matInv; D3DXVECTOR4 vec4LightDir; // 頂点バッファ設定 UINT stride = sizeof( MESH_USER::VERTEX_USER ); UINT offset = 0; g_pD3D11User->m_D3DDeviceContext->IASetVertexBuffers( 0, 1, &g_pMesh->MeshUser[0].VertexBuffer, &stride, &offset ); // インデックスバッファ設定 g_pD3D11User->m_D3DDeviceContext->IASetIndexBuffer( g_pMesh->MeshUser[0].IndexBuffer, DXGI_FORMAT_R32_UINT, 0 ); // 三角ポリゴン描画 g_pD3D11User->m_D3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); // デカールマップを取得 ID3D11ShaderResourceView* pDecalMap = NULL; g_pMesh->MeshUser[0].GetTexture( _T("DiffuseColor"), &pDecalMap ); // 定数バッファとシェーダーリソースビューを設定する { // ワールド行列 // スケーリング行列 D3DXMatrixScaling( &matScaling, 3.0f, 3.0f, 3.0f ); // 平行移動行列 D3DXMatrixTranslation( &matTranslation, 5.0f, 0.0f, 0.0f ); // ワールド座標系の行列の合成 matWorld = matScaling * matTranslation; // 行列を合成 matWVP = matWorld * (*pMatView) * (*pMatProj); // シェーダー内では列優先にしているので転置行列を作成する。 D3DXMatrixTranspose( &matWVP, &matWVP ); // 平行光源の方向ベクトル // ワールド行列の逆行列を作成 D3DXMatrixInverse( &matInv, NULL, &matWorld ); D3DXVec4Transform( &vec4LightDir, &g_vecLight, &matInv ); D3DXVec3Normalize( (D3DXVECTOR3*)&vec4LightDir, (D3DXVECTOR3*)&vec4LightDir ); // 定数バッファとシェーダーリソースビューを設定する pDepthOfField->SetCBStep01( g_pD3D11User->m_D3DDeviceContext, &matWVP, Zfar, &vec4LightDir, pDecalMap ); } // インデックスバッファを使用した描画 g_pD3D11User->m_D3DDeviceContext->DrawIndexed( g_pMesh->MeshUser[0].IndexesCount, 0, 0 ); hr = S_OK; //EXIT: return hr; } // 被写界深度描画 HRESULT RenderDepthOfField( DEPTH_OF_FIELD* pDepthOfField, ID3D11ShaderResourceView* pSRView[2] ) { HRESULT hr = E_FAIL; // 定数バッファとシェーダーリソースビューを設定する D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; // カラーマップのシェーダーリソースビューの設定を取得 pSRView[0]->GetDesc( &SRVDesc ); // 注視点の座標 D3DXVECTOR2 LookAt; ID3D11Resource* pZMapResource = NULL; pSRView[1]->GetResource( &pZMapResource ); ID3D11Texture2D* pZMapTexture = reinterpret_cast<ID3D11Texture2D*>(pZMapResource); D3D11_TEXTURE2D_DESC ZMapTexDesc; // 深度マップのテクスチャーの設定を取得 pZMapTexture->GetDesc( &ZMapTexDesc ); // 注視点の[ U, V ]座標を計算する LookAt = D3DXVECTOR2( (float)ZMapTexDesc.Width * 0.5f, (float)ZMapTexDesc.Height * 0.5f ); SAFE_RELEASE( pZMapResource ); //// 注視点の深度値を取得する( 激重!! ) //hr = pDepthOfField->GetZofLookAt( g_pD3D11User->m_D3DDevice, g_pD3D11User->m_D3DDeviceContext, pSRView[1], &LookAt, 0.001f ); //if( FAILED( hr ) ) // goto EXIT; // 注視点の深度値を取得する処理の定数バッファを設定する hr = pDepthOfField->SetCBStep02( g_pD3D11User->m_D3DDeviceContext, &LookAt, 0.001f ); if( FAILED( hr ) ) goto EXIT; // 注視点の深度値を取得する hr = pDepthOfField->StartStep02( g_pD3D11User->m_D3DDeviceContext, pSRView ); if( FAILED( hr ) ) goto EXIT; // 被写界深度レンダリングのための定数バッファを設定する hr = pDepthOfField->SetCBStep03( g_pD3D11User->m_D3DDeviceContext, (float)SRVDesc.Texture2D.MipLevels, pSRView ); if( FAILED( hr ) ) goto EXIT; // 被写界深度レンダリング hr = pDepthOfField->RenderStep03( g_pD3D11User->m_D3DDeviceContext ); if( FAILED( hr ) ) goto EXIT; hr = S_OK; EXIT: return hr; } // 描画処理 HRESULT Render() { HRESULT hr = E_FAIL; D3DXMATRIX matProj, m; float Zfar = 60.0f; float BackBufferClearColor[4] = { 0.3f, 0.3f, 0.9f, 1.0f }; float DepthMapClearColor[4] = { 0.0f, 0.0f, 1.0f, 1.0f }; // バックバッファをクリア g_pD3D11User->m_D3DDeviceContext->ClearRenderTargetView( g_pD3D11User->m_RenderTargetView, BackBufferClearColor ); // 深度バッファをクリア if( g_pD3D11User->m_DepthStencilView ) g_pD3D11User->m_D3DDeviceContext->ClearDepthStencilView( g_pD3D11User->m_DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 ); // 射影行列 D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 5.0f, 4.0f / 3.0f, 1.0f, Zfar ); // ビュー行列 D3DXMatrixIdentity( &m ); if( g_KeyBuffer[VK_RIGHT] ) { D3DXMatrixRotationY( &m, -0.001f ); g_matView = g_matView * m; } if( g_KeyBuffer[VK_LEFT] ) { D3DXMatrixRotationY( &m, 0.001f ); g_matView = g_matView * m; } if( g_KeyBuffer[VK_UP] ) { D3DXMatrixTranslation( &m, 0, 0, -0.01f ); g_matView = g_matView * m; } if( g_KeyBuffer[VK_DOWN] ) { D3DXMatrixTranslation( &m, 0, 0, 0.01f ); g_matView = g_matView * m; } if( g_KeyBuffer['W'] ) { D3DXMatrixRotationX( &m, 0.001f ); g_matView = g_matView * m; } if( g_KeyBuffer['S'] ) { D3DXMatrixRotationX( &m, -0.001f ); g_matView = g_matView * m; } ID3D11RenderTargetView* pOldRTView = NULL; ID3D11DepthStencilView* pOldDSView = NULL; ID3D11RenderTargetView* pRTV[2] = { NULL, NULL }; ID3D11ShaderResourceView* pSRV[2] = { NULL, NULL }; // レンダーターゲットサーフェスをクリア g_pD3D11User->m_D3DDeviceContext->ClearRenderTargetView( g_pRTView[0], BackBufferClearColor ); g_pD3D11User->m_D3DDeviceContext->ClearRenderTargetView( g_pRTView[1], DepthMapClearColor ); // 現在のレンダーターゲットサーフェスを取得 g_pD3D11User->m_D3DDeviceContext->OMGetRenderTargets( 1, &pOldRTView, &pOldDSView ); // レンダーターゲットサーフェスを切り替える g_pD3D11User->m_D3DDeviceContext->OMSetRenderTargets( 2, g_pRTView, pOldDSView ); // シェーディング処理を開始 g_pDepthOfField->BeginStep01( g_pD3D11User->m_D3DDeviceContext ); // メッシュを描画 hr = RenderPlane( g_pDepthOfField, &g_matView, &matProj, Zfar ); if( FAILED( hr ) ) goto EXIT; // レンダーターゲットをバックバッファへ戻す pRTV[0] = pOldRTView; pRTV[1] = NULL; g_pD3D11User->m_D3DDeviceContext->OMSetRenderTargets( 2, pRTV, pOldDSView ); SAFE_RELEASE( pOldRTView ); SAFE_RELEASE( pOldDSView ); // シェーダーリソースビューを取得 pSRV[0] = g_pD3D11User->GetSRViewFromRTView( g_pRTView[0] ); pSRV[1] = g_pD3D11User->GetSRViewFromRTView( g_pRTView[1] ); // シェーディング処理を終了 g_pDepthOfField->EndStep01( g_pD3D11User->m_D3DDeviceContext, pSRV[0] ); // DepthOfField適応 hr = RenderDepthOfField( g_pDepthOfField, pSRV ); if( FAILED( hr ) ) goto EXIT; SAFE_RELEASE( pSRV[0] ); SAFE_RELEASE( pSRV[1] ); if( g_pDebugFontUser ) { // デバッグ専用フォント描画 hr = g_pDebugFontUser->RenderFPS( g_pD3D11User->m_D3DDeviceContext, 0, 0 ); if( FAILED( hr ) ) goto EXIT; } // レンダリングされたイメージをユーザーに表示。 hr = g_pD3D11User->m_SwapChain->Present( 0, 0 ); if( FAILED( hr ) ) goto EXIT; if( ScreenShot ) { // スクリーンショット作成 hr = g_pD3D11User->CreateScreenShot(); if( FAILED( hr ) ) goto EXIT; ScreenShot = false; } hr = S_OK; EXIT: SAFE_RELEASE( pOldRTView ); SAFE_RELEASE( pOldDSView ); return hr; } // 節電処理および描画処理 HRESULT PowerSavingAndRender() { HRESULT hr = E_FAIL; switch( StandBy ) { // スタンバイモード case true: // テストのみ行い、描画処理は行わない。 hr = g_pD3D11User->m_SwapChain->Present( 0, DXGI_PRESENT_TEST ); switch( hr ) { // いまだスタンバイ中。。。 case DXGI_STATUS_OCCLUDED: // 電源管理によるスリープ状態の場合ここにくる。 // フルスクリーンモード時にスクリーンセーバーが起動時した場合は、表示モードが強制的にウィンドウモードに変更されるためここにこない。 goto EXIT; break; case S_OK: // フルスクリーンモード時にスクリーンセーバーが起動時した場合は表示モードが強制的にウィンドウモードに変更される。 // ウィンドウモードの場合スタンバイから復帰してしまうため、ウィンドウがアクティブになったときに復帰するようにする。 if( Activate == true ) { // たまにウィンドウが表示されないときがあるので表示するようにする ::ShowWindow( g_pD3D11User->m_hWnd, SW_SHOW ); StandBy = false; } break; default: goto EXIT; break; } break; // スタンバイモードでない case false: // 描画処理 hr = Render(); if( FAILED( hr ) ) goto EXIT; switch( hr ) { case DXGI_STATUS_OCCLUDED: // スタンバイモードへ移行 // フルスクリーンモード時のスクリーンセーバー起動時、 // スリープ状態に移行した時に発生する。 StandBy = true; goto EXIT; break; case S_OK: break; default: goto EXIT; break; } break; } hr = S_OK; EXIT: return hr; } // ウィンドウプロシージャ LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam ) { switch( msg ) { case WM_KEYDOWN: g_KeyBuffer[wParam] = 1; break; case WM_KEYUP: g_KeyBuffer[wParam] = 0; // アプリ終了 switch( wParam ) { case VK_ESCAPE: ::DestroyWindow( hWnd ); break; // F2キーを押すと、ウィンドウモードを切り替える。 // 自動的にウィンドウモードを切り替える機能もあるが、ウィンドウスタイルを自由に変更するために自分で実装することにした。 case VK_F2: g_pD3D11User->ChangeWindowMode(); break; // スクリーンショットを作成する case VK_SNAPSHOT: ScreenShot = true; break; } break; case WM_ACTIVATE: Activate = true; break; case WM_DESTROY: Invalidate(); ::PostQuitMessage(0); break; default: return ::DefWindowProc( hWnd, msg, wParam, lParam ); } return 0L; } // メイン関数 int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR, INT ) { HRESULT hr = E_FAIL; MSG msg; ::ZeroMemory(&msg, sizeof(MSG)); // メモリリーク検出 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_EVERY_1024_DF); // 表示モードを記述するための構造体。 DXGI_MODE_DESC sd; // Direct3D 関連自作クラスのインスタンスを作成 g_pD3D11User = NEW D3D11USER(); // ディスプレイモード一覧を取得する。 // 取得した値はクラス内部に保持される。 hr = g_pD3D11User->GetDisplayMode(); if( FAILED( hr ) ) { ::MessageBox( NULL, _T("ディスプレイモード取得エラー"), _T("初期化エラー"), MB_OK ); goto EXIT; } // とりあえず最初に見つかったディスプレイモードを選択する CopyMemory( &sd, &g_pD3D11User->m_DisplayModeDesc[0], sizeof( DXGI_MODE_DESC ) ); // ウィンドウの作成およびDirect3D の初期化 // マルチサンプルを無効にする hr = g_pD3D11User->InitD3D11( AppName, hInstance, WndProc, &sd, TRUE, TRUE, FALSE, TRUE ); if( FAILED( hr ) ) { ::MessageBox( NULL, _T("Direct3D 11.0 初期化エラー"), _T("初期化エラー"), MB_OK ); goto EXIT; } // リソースの初期化 hr = Init(); if( FAILED( hr ) ) { ::MessageBox( NULL, _T("リソース初期化エラー"), _T("初期化エラー"), MB_OK ); goto EXIT; } ::ShowWindow(g_pD3D11User->m_hWnd, SW_SHOW); ::UpdateWindow(g_pD3D11User->m_hWnd); // メッセージループ do { if( ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } else { hr = PowerSavingAndRender(); if( FAILED( hr ) ) ::DestroyWindow( g_pD3D11User->m_hWnd ); } }while( msg.message != WM_QUIT ); EXIT: if( g_pD3D11User && g_pD3D11User->m_hWnd ) ::DestroyWindow( g_pD3D11User->m_hWnd ); ::UnregisterClass( AppName, hInstance ); return msg.wParam; }