Maverick Project
 Microsoft Visual C++ 2012 Express
 Direct3D 11.0
 Kinect for Windows SDK v1.7
 DirectXTex texture processing library

■Kinect 深度カメラ Prev Top Next
関連ページ:Direct3D 自作の共通ライブラリ


深度カメラから取得した深度値をもとにフォグ

今回は深度カメラをやります。フォグかけているためおかしな画像になってます。
深度値を使った簡単なシェーダーと考えて思いついたのがフォグですが、思いっきり使いどころを間違ってますな。

UCommon.h 共通で使用するヘッダファイル。
UException.h 例外処理クラスのヘッダファイル。
UDirect3D11.h Direct3Dクラスのヘッダーファイル。
UDirect3D11.cpp Direct3Dクラスのソースファイル。
UGraphicsPipeline.h グラフィックパイプラインクラスのヘッダーファイル。
UGraphicsPipeline.cpp グラフィックパイプラインクラスのソースファイル。
UMesh.h メッシュの抽象クラスのヘッダーファイル。
UMesh.cpp メッシュの抽象クラスのソースファイル。
UPlane02.h メッシュクラスのヘッダーファイル
UPlane02.cpp メッシュクラスのソースファイル
Sample02.hlsl hlslファイル
UKinect02.h Kinectクラスのヘッダーファイル
UKinect02.cpp Kinectクラスのソースファイル
main.cpp main関数のソースファイル

---UPlane02.h---  ↑


#ifndef UPLANE02_H
#define UPLANE02_H

#include "../../Common/Header/UCommon.h"
#include <NuiApi.h>
#include "../../Common/Header/UException.h."
#include "../../Common/Header/UMesh.h"
#include "../../Common/Header/UDirect3D11.h"

class UCPlane02: public UIMesh
{
private:
   // 頂点定義
   typedef struct _VERTEX
   {
      // 頂点座標
      float x, y, z;
      // テクセル
      float tu, tv;
   }VERTEX;

   // 頂点バッファ
   ID3D11Buffer* m_pVertexBuffer;

   // インデックスバッファ
   ID3D11Buffer* m_pIndexBuffer;

   // シェーダーリソースビュー
   ID3D11ShaderResourceView* m_pSRView;

   // サンプラーステート
   ID3D11SamplerState* m_pSamplerState;

public:
   UCPlane02();
   ~UCPlane02();
   void Invalidate();
   void CreateMesh( ID3D11Device* pD3DDevice, UINT Width, UINT Height );
   void NextFrame( ID3D11DeviceContext* pD3DDeviceContext, NUI_LOCKED_RECT ColorData );
   void Render( ID3D11DeviceContext* pD3DDeviceContext );
};

#endif

---UPlane02.cpp---  ↑

#include "UPlane02.h"

UCPlane02::UCPlane02()
{
   m_pVertexBuffer = nullptr;
   m_pIndexBuffer = nullptr;
   m_pSRView = nullptr;
   m_pSamplerState = nullptr;
}

UCPlane02::~UCPlane02()
{
   Invalidate();
}

void UCPlane02::Invalidate()
{
   SAFE_RELEASE( m_pSamplerState );
   SAFE_RELEASE( m_pSRView );
   SAFE_RELEASE( m_pIndexBuffer );
   SAFE_RELEASE( m_pVertexBuffer );
}

void UCPlane02::CreateMesh( ID3D11Device* pD3DDevice, UINT Width, UINT Height )
{
   // 頂点データを格納する
   VERTEX v[] = { 
       1,  1, 0.0f, 1.0f, 0.0f,
      -1,  1, 0.0f, 0.0f, 0.0f,
       1, -1, 0.0f, 1.0f, 1.0f,
      -1, -1, 0.0f, 0.0f, 1.0f,
   };
      
   // 頂点バッファを作成する
   m_pVertexBuffer = CreateVertexBuffer( pD3DDevice, v, sizeof( v ), 0 );

   UINT Index[] = { 0, 1, 2, 3 };

   // インデックスバッファを作成する。
   m_pIndexBuffer = CreateIndexBuffer( pD3DDevice, Index, sizeof( Index ), 0 );

   // 空のデカールマップ用シェーダーリソースビューを作成する
   // GPU (読み取りのみ) と CPU (書き込みのみ) によるアクセスが可能なリソースとして作成する設定
   m_pSRView = CreateSRViewForDecalMap( pD3DDevice, Width, Height, UD3D11_FORMAT, UEACCESS_FLAG::UPDATE_SUBRESOURCE );

   // サンプラーステートを作成する
   m_pSamplerState = CreateSamplerState( pD3DDevice, D3D11_TEXTURE_ADDRESS_CLAMP );
}

void UCPlane02::NextFrame( ID3D11DeviceContext* pD3DDeviceContext, NUI_LOCKED_RECT ColorData )
{
   ID3D11Resource* pResource = nullptr;

   __try
   {
      // シェーダーリソースビューからテクスチャーを取得する
      m_pSRView->GetResource( &pResource );

      // シェーダーリソースビューに色情報を設定する
      pD3DDeviceContext->UpdateSubresource( pResource, 0, nullptr, ColorData.pBits, ColorData.Pitch, 0 );
   }
   __finally
   {
      SAFE_RELEASE( pResource );
   }
}

void UCPlane02::Render( ID3D11DeviceContext* pD3DDeviceContext )
{
   // 頂点バッファ設定
   UINT stride = sizeof( UCPlane02::VERTEX );
   UINT offset = 0;
   pD3DDeviceContext->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &stride, &offset );

   // インデックスバッファ設定
   pD3DDeviceContext->IASetIndexBuffer( m_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );

   // プリミティブ タイプおよびデータの順序に関する情報を設定
   pD3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

   // ピクセルシェーダーのサンプラーステートを設定する
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_pSamplerState );

   // デカールマップを設定する
   pD3DDeviceContext->PSSetShaderResources( 0, 1, &m_pSRView );

   // インデックスバッファを使用した描画
    pD3DDeviceContext->DrawIndexed( 4, 0, 0 );
}

---Sample02.hlsl---  ↑

// 定数バッファ
cbuffer cbSize : register( b0 )
{
   float4 g_Size : packoffset( c0 );
};

// テクスチャー
Texture2D g_Tex : register( t0 );

// サンプラーステート
SamplerState  g_Sampler : register( s0 );

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos   : POSITION;   // 頂点座標
   float2 texel : TEXCOORD;   // テクセル
};

// 頂点シェーダーの出力パラメータ
struct VS_OUT_PS_IN
{
   float4 pos    : SV_POSITION;
   float2 texel  : TEXCOORD0;
};

// 頂点シェーダー
VS_OUT_PS_IN VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out = { float4( In.pos, 1.0f ), In.texel };
   return Out;
}

// ピクセルシェーダ
float4 PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   float z[8];
   int cnt = 0;
   float a = 0;

   // 色取得
   float4 col = g_Tex.Sample( g_Sampler, In.texel );
   
   // アルファ値には深度値が格納されている
   a = col.a;

   // ノイズを除去
   if( a == 0.0f )
   {
      // テクセルのオフセット値計算
      float2 offset = (float2)( 3.0f / g_Size.x, 3.0f / g_Size.y );
   
      // オフセット位置の深度値を取得
      z[0] = g_Tex.Sample( g_Sampler, In.texel + float2( 0, offset.y ) ).a;
      z[1] = g_Tex.Sample( g_Sampler, In.texel + float2( 0, -offset.y ) ).a;
      z[2] = g_Tex.Sample( g_Sampler, In.texel + float2( offset.x, 0 ) ).a;
      z[3] = g_Tex.Sample( g_Sampler, In.texel + float2( -offset.x, 0 ) ).a;
   
      z[4] = g_Tex.Sample( g_Sampler, In.texel + float2( offset.x, offset.y ) ).a;
      z[5] = g_Tex.Sample( g_Sampler, In.texel + float2( offset.x, -offset.y ) ).a;
      z[6] = g_Tex.Sample( g_Sampler, In.texel + float2( -offset.x, offset.y ) ).a;
      z[7] = g_Tex.Sample( g_Sampler, In.texel + float2( -offset.x, -offset.y ) ).a;
   
      // 適当に補正
      for( int i=0; i<8; i++ )
      {
         if( z[i] > 0.0f )
         {
            cnt++;
            a += z[i];
         }
      }

      if( cnt > 0 )
         a /= (float)cnt;
   }
   
   // 深度値を0.0f側に寄せる
   a *= a;
   
// フォグかます
//   return col.bgra * ( 1.0f - a ) + a;

// フォグかまさず補正あり
//   return a;

// フォグかまさず補正なし
   return col.a;
}

Kinectから取得した深度値は結構ノイズが多いため、シェーダー内で補正しています。
補正ありとなしを比較します。

補正なし
補正あり

だいぶましな感じになっていると思います。
黒い四角領域がありますが、これはノートPCのモニターとテレビです。 Kinectでは赤外線センサーを使用して深度値を取得しているらしいので、
赤外線を吸収する黒い物体の深度値は正しく取得できないのでしょう。

---UKinect02.h---  ↑


#ifndef KINECT02_H
#define KINECT02_H

#include "../../Common/Header/UCommon.h"
#include <NuiApi.h>
#include "../../Common/Header/UException.h"

// Kinect用ライブラリ
#pragma comment( lib, "Kinect10.lib" )

class UCKinect02
{
private:
   typedef struct _IMAGEFRAMESET
   {
      HANDLE ImageStreamHandle;
      NUI_IMAGE_FRAME ImageFrame;
   }IMAGEFRAMESET;

   INuiSensor* m_pKinectSensor;
   IMAGEFRAMESET m_ImageFrame, m_DepthFrame;
   DWORD m_Flags;

   static const NUI_IMAGE_RESOLUTION m_ImageResolution = NUI_IMAGE_RESOLUTION_640x480;
   static const NUI_IMAGE_RESOLUTION m_DepthResolution = NUI_IMAGE_RESOLUTION_640x480;

   NUI_LOCKED_RECT CreateData( IMAGEFRAMESET* pImageFrame );
   void ReleaseData( IMAGEFRAMESET* pImageFrame );

public:
   UCKinect02();
   ~UCKinect02();
   void CreateKinect( DWORD Flags, DWORD& pWidth, DWORD& pHeight );
   // カラーデータを取得
   NUI_LOCKED_RECT CreateImageData();
   NUI_LOCKED_RECT CreateDepthData();
   // カラーデータのa成分に深度値を格納する
   void MergeImageDataAndDepthData( NUI_LOCKED_RECT* pImageData, NUI_LOCKED_RECT* pDepthData, float ZFar );
   // メモリ解放
   void ReleaseImageData();
   void ReleaseDepthData();
};

#endif

---UKinect02.cpp---  ↑

#include "../../Common/Header/UKinect02.h"

UCKinect02::UCKinect02()
{
   m_pKinectSensor = nullptr;
}

UCKinect02::~UCKinect02()
{
   if( m_pKinectSensor != nullptr )
      m_pKinectSensor->NuiShutdown();

   SAFE_RELEASE( m_pKinectSensor );
}

void UCKinect02::CreateKinect( DWORD Flags, DWORD& pWidth, DWORD& pHeight )
{
   HRESULT hr = E_FAIL;
   int count = 0;

   pWidth = 0;
   pHeight = 0;
   m_Flags = Flags;

   // マシンに接続されている Kinectセンサー 数を取得する。
   if( FAILED( hr = ::NuiGetSensorCount( &count ) ) )
      throw( UCException( hr, _T("UCKinect02::CreateKinect()でエラーが発生しました。接続されているKinectセンサーの数を取得できません。") ) );

   if( count == 0 )
      throw( UCException( -1, _T("UCKinect02::CreateKinect()でエラーが発生しました。Kinectセンサーが接続されていません。") ) );

   // 指定したインデックスの INuiSensor のインスタンスを作成する
   // ここでは 0 番目のインスタンスのみ作成する
   if( FAILED( hr = ::NuiCreateSensorByIndex( 0, &m_pKinectSensor ) ) )
      throw( UCException( hr, _T("UCKinect02::CreateKinect()でエラーが発生しました。Kinectセンサーが接続されていません。") ) );

   HRESULT status = E_FAIL;

   for( int i=0; i<50; i++ )
   {
      TCHAR msg[256];

      // Kinectセンサー の接続状態を取得する
      status = m_pKinectSensor->NuiStatus();
   
      // 正常
      if( status == S_OK )
         break;
      // Kinectセンサーが接続されているが、初期化中
      // Kinectセンサー接続直後にアプリを起動するとこの状態になるときがある
      else if( status == S_NUI_INITIALIZING )
      {
         _stprintf_s( msg, _T("■□■HRESULT:0x%x [ %s ]\n"), hr, _T(":Kinectセンサーが接続されているが、初期化中\n") );
         OutputDebugString( msg );
      }
      // Kinectセンサーが接続されているが、エラーが発生
      // Kinectセンサー接続直後にアプリを起動するとこの状態になるときがある
      else
      {
         _stprintf_s( msg, _T("■□■HRESULT:0x%x [ %s ]\n"), hr, _T(":Kinectセンサーが接続されているが、エラーが発生\n") );
         OutputDebugString( msg );
      }

      Sleep( 1000 );
   }
   if( status != S_OK )
      throw( UCException( -1, _T("UCKinect02::CreateKinect()でエラーが発生しました。Kinectセンサーが接続されているが、初期化が完了しなかった") ) );

   // Kinectを初期化する。
   if( FAILED( hr = m_pKinectSensor->NuiInitialize( m_Flags ) ) )
      throw( UCException( -1, _T("UCKinect02::CreateKinect()でエラーが発生しました。Kinectの初期化に失敗した") ) );

   if( m_Flags & NUI_INITIALIZE_FLAG_USES_COLOR )
   {
      // イメージストリームをオープンする
      if( FAILED( hr = m_pKinectSensor->NuiImageStreamOpen( 
                            NUI_IMAGE_TYPE_COLOR,                   // カラーデータを取得する
                            m_ImageResolution,                      // イメージストリームの解像度を指定する
                            0, 2, nullptr, 
                            &m_ImageFrame.ImageStreamHandle         // 開始されたイメージストリームのハンドル
                            ) ) )
        throw( UCException( hr, _T("UCKinect02::CreateKinect()でエラーが発生しました。イメージストリームをオープンできなかった") ) );
   }

   if( m_Flags & NUI_INITIALIZE_FLAG_USES_DEPTH )
   {
      // イメージストリームをオープンする
      if( FAILED( hr = m_pKinectSensor->NuiImageStreamOpen( 
                            NUI_IMAGE_TYPE_DEPTH,                   // 深度データを取得する
                            m_DepthResolution,                      // 深度ストリームの解像度を指定する
                            0, 2, nullptr, 
                            &m_DepthFrame.ImageStreamHandle         // 開始された深度ストリームのハンドル
                            ) ) )
        throw( UCException( hr, _T("UCKinect02::CreateKinect()でエラーが発生しました。深度ストリームをオープンできなかった") ) );
   }

   // NUI_IMAGE_RESOLUTION列挙型の値から実際の解像度値を取得する
   ::NuiImageResolutionToSize( m_ImageResolution, pWidth, pHeight );
}

NUI_LOCKED_RECT UCKinect02::CreateData( IMAGEFRAMESET* pImageFrame )
{
   HRESULT hr = E_FAIL;
   NUI_LOCKED_RECT imageData;

   ::ZeroMemory( &imageData, sizeof( NUI_LOCKED_RECT ) );

   // 指定されたイメージストリームから次のイメージフレームを取得する
   if( FAILED( hr = m_pKinectSensor->NuiImageStreamGetNextFrame( pImageFrame->ImageStreamHandle, INFINITE, &pImageFrame->ImageFrame ) ) )
      throw( UCException( hr, _T("UCKinect02::CreateData()でエラーが発生しました。次のイメージフレームを取得できなかった") ) );

   // イメージフレームからカラーデータを取得する
   if( FAILED( hr = pImageFrame->ImageFrame.pFrameTexture->LockRect( 0, &imageData, nullptr, 0 ) ) )
      throw( UCException( hr, _T("UCKinect02::CreateData()でエラーが発生しました。イメージフレームからイメージデータを取得できなかった") ) );

   return imageData;
}

NUI_LOCKED_RECT UCKinect02::CreateImageData()
{
   return CreateData( &m_ImageFrame );
}

NUI_LOCKED_RECT UCKinect02::CreateDepthData()
{
   return CreateData( &m_DepthFrame );
}

// カラーデータのa成分に深度値を格納する
void UCKinect02::MergeImageDataAndDepthData( NUI_LOCKED_RECT* pImageData, NUI_LOCKED_RECT* pDepthData, float ZFar )
{   
   HRESULT hr = E_FAIL;

   if( ZFar <= 0 )
      throw( UCException( -1, _T("UCKinect02::MergeImageDataAndDepthData()でエラーが発生しました。ZFar仮引数に0以下の値は指定できません") ) );

   // 解像度を取得する
   DWORD imageWidth, imageHeight, depthWidth, depthHeight;
   ::NuiImageResolutionToSize( m_ImageResolution, imageWidth, imageHeight );
   ::NuiImageResolutionToSize( m_DepthResolution, depthWidth, depthHeight );

   USHORT* depth = (USHORT*)pDepthData->pBits;

   // 深度データをループ
   for( DWORD i=0; i<(pDepthData->size/sizeof(USHORT)); i++ )
   {
      // 深度フレームの X 方向の位置
      LONG depthX = i % depthWidth;
      // 深度フレームの Y 方向の位置
      LONG depthY = i / depthWidth;

      LONG colorX = 0;
      LONG colorY = 0;

      // 深度イメージの座標をカラーイメージの座標に変換する
      if( FAILED( hr = m_pKinectSensor->NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution(
                                                         m_ImageResolution,
                                                         m_DepthResolution,
                                                         0,
                                                         depthX, depthY,
                                                         depth[i],
                                                         &colorX, &colorY ) ) )
         throw( UCException( hr, _T("UCKinect02::MergeImageDataAndDepthData()でエラーが発生しました。深度イメージの座標をカラーイメージの座標に変換できなかった") ) );

      // 誤差をで吸収する
      if( colorX > (LONG)imageWidth )
         colorX = imageWidth;

      if( colorY > (LONG)imageHeight )
         colorY = imageHeight;

      // カラーイメージのピクセル単位でのインデックス値
      int index = ((colorY * imageWidth) + colorX) * 4;
      BYTE* colorBits = pImageData->pBits;

      // プレイヤーIDを取り除いて深度値を取得する
      USHORT distance = ::NuiDepthPixelToDepth( depth[i] );

      if( distance < ZFar )
         colorBits[index+3] = (BYTE)( distance * 255/ ZFar );
      else
         colorBits[index+3] = 255;         
   }
}

void UCKinect02::ReleaseData( IMAGEFRAMESET* pImageFrame )
{
   HRESULT hr = E_FAIL;

   // ロックを解除する
   if( FAILED( hr = pImageFrame->ImageFrame.pFrameTexture->UnlockRect( 0 ) ) )
      throw( UCException( hr, _T("UCKinect02::ReleaseData()でエラーが発生しました。ロックを解除できなかった") ) );

   // イメージストリームから取得したイメージフレームを解放する
   if( FAILED( hr = m_pKinectSensor->NuiImageStreamReleaseFrame( pImageFrame->ImageStreamHandle, &pImageFrame->ImageFrame ) ) )
      throw( UCException( hr, _T("UCKinect02::ReleaseData()でエラーが発生しました。イメージストリームから取得したイメージフレームを解放できなかった") ) );
}

void UCKinect02::ReleaseImageData()
{
   ReleaseData( &m_ImageFrame );
}

void UCKinect02::ReleaseDepthData()
{
   ReleaseData( &m_DepthFrame );
}

参考にした書籍、Kinect for Windows SDK C++編によると、距離カメラとRGBカメラはハード的に離れているため、取得したイメージにずれが発生します。
近距離であるほどそのずれは顕著になります。その変換を行うためにINuiSensor::NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution()関数を使用します。
この関数は深度イメージ配列の各要素それぞれに対応するカラーイメージの縦横の座標を返します。

次に深度値は4バイトではなく、2バイト配列で取得されます。そして先頭の13bitに深度値が格納され、残りの3bitはプレイヤーIDが格納されます。
そのため深度値を取得するために右に3bitシフト演算を行います。この処理を行うのが、::NuiDepthPixelToDepth()関数です。
関数使うまでもないのですが、今後のSDKの修正でこの辺の内部仕様が変更になった場合でも提供されている関数を使うようにしておけば
アプリ側の修正が不要となると考えて関数を使うようにしています。

---main.cpp---  ↑

#include "../../Common/Header/UCommon.h"
#include "../../Common/Header/UException.h"
#include "../../Common/Header/UDirect3D11.h"
#include "../../Common/Header/UGraphicsPipeline.h"
#include "../../Common/Header/UKinect02.h"
#include "UPlane02.h"
#include <NuiApi.h>

// 定数バッファ用定義
typedef struct _VECTOR4
{
    float x, y, z, w;
}VECTOR4;

// シェーダーオブジェクトを作成するとき、ファイルから読むか、メモリから読むかを切り替える
#if defined(DEBUG) || defined(_DEBUG)
   #define UNCOMPILED_SHADER     // ファイルを読み込んでコンパイルする
#else
   #include "../../Common/HLSL/Sample02_VS_Main.h"
   #include "../../Common/HLSL/Sample02_PS_Main.h"
#endif

// アプリケーション名
TCHAR* AppName = _T("Kinect_Tutrial02");

// Direct3D関連の自作クラス
UCDirect3D11* g_pDirect3D11 = nullptr;

// グラフィックパイプライン関連の自作クラス
UCGraphicsPipeline* g_pGraphicsPipeline = nullptr;

// シェーダー用定数バッファ
ID3D11Buffer* g_pConstantBuffers[1] = { nullptr };

// Kinectセンサーオブジェクト
UCKinect02* g_pKinect02 = nullptr;

// 平面オブジェクト
UCPlane02* g_pPlane02 = nullptr;

// メモリ解放
void Invalidate()
{
   for( int i=0; i<_countof( g_pConstantBuffers ); i++ )
      SAFE_RELEASE( g_pConstantBuffers[i] );

   SAFE_DELETE( g_pKinect02 );
   SAFE_DELETE( g_pPlane02 );
   SAFE_DELETE( g_pGraphicsPipeline );
   SAFE_DELETE( g_pDirect3D11 );
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam )
{
   switch( msg )
   {
   case WM_KEYUP:
      // アプリ終了
      if( wParam == VK_ESCAPE )
         ::DestroyWindow( hWnd );
      break;

   case WM_DESTROY:
      ::PostQuitMessage(0);
      break;

   default:
      return ::DefWindowProc( hWnd, msg, wParam, lParam );
   }

   return 0L;
}

// Direct3Dの作成
void CreateDirect3D( HINSTANCE hInstance, DWORD Width, DWORD Height )
{
   DXGI_MODE_DESC* pModeDescArray = nullptr;

   __try
   {
      DXGI_MODE_DESC  ModeDesc;
      UINT num;

      // ディスプレイモード一覧の数を取得する
      g_pDirect3D11->GetDisplayMode( nullptr, &num );

      pModeDescArray = NEW DXGI_MODE_DESC[num];
      // ディスプレイモード一覧を取得する
      g_pDirect3D11->GetDisplayMode( pModeDescArray, &num );

      bool find = false;
      for( UINT i=0; i<num; i++ )
      {
         // 適切な解像度のディスプレイモードを検索する
         if( pModeDescArray[i].Width == Width && pModeDescArray[i].Height == Height )
         {
            find = true;
            ::CopyMemory( &ModeDesc, &pModeDescArray[i], sizeof( DXGI_MODE_DESC ) );
            break;
         }
      }

      if( find == false )
         throw( UCException( -1, _T("InitDirect3D()でエラーが発生しました。適切なディスプレイモードの解像度を取得できません。") ) );

      // ウィンドウの作成およびDirect3D の作成
      g_pDirect3D11->CreateDirect3D11( AppName, hInstance, WndProc, &ModeDesc, TRUE, TRUE );
   }
   __finally
   {
      SAFE_DELETE_ARRAY( pModeDescArray );
   }
}

void CreateGraphicePipeline( DWORD Width, DWORD Height )
{
   D3D11_INPUT_ELEMENT_DESC layout[] = {
         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
   };

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   g_pGraphicsPipeline->CreateVertexShaderFromFile( g_pDirect3D11->m_pD3DDevice, _T("../../Common/HLSL/Sample02.hlsl"), "VS_Main", layout, _countof( layout ) );
   g_pGraphicsPipeline->CreatePixelShaderFromFile(  g_pDirect3D11->m_pD3DDevice, _T("../../Common/HLSL/Sample02.hlsl"), "PS_Main" );
#else
   g_pGraphicsPipeline->CreateVertexShaderFromMemory( g_pDirect3D11->m_pD3DDevice, (LPBYTE)g_VS_Main, sizeof( g_VS_Main ), layout, _countof( layout ) );
   g_pGraphicsPipeline->CreatePixelShaderFromMemory(  g_pDirect3D11->m_pD3DDevice, (LPBYTE)g_PS_Main, sizeof( g_PS_Main ) );
#endif

   // ラスタライザーステートを作成する
   g_pGraphicsPipeline->CreateRasterizerState( g_pDirect3D11->m_pD3DDevice, D3D11_CULL_MODE::D3D11_CULL_BACK );

   // 深度ステンシルステートを作成する
   g_pGraphicsPipeline->CreateDepthStencilState( g_pDirect3D11->m_pD3DDevice, FALSE, D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ALL );

   // ブレンドステートを作成する
   UCGraphicsPipeline::UEBLEND_STATE BlendStateType[1] = { UCGraphicsPipeline::UEBLEND_STATE::NONE };
   g_pGraphicsPipeline->CreateBlendState( g_pDirect3D11->m_pD3DDevice, BlendStateType, 1 );

   // シェーダー用の定数バッファを作成する
   VECTOR4 vec;
   vec.x = (float)Width;
   vec.y = (float)Height;
   g_pConstantBuffers[0] = g_pGraphicsPipeline->CreateConstantBuffer( g_pDirect3D11->m_pD3DDevice, (LPVOID)&vec, sizeof( VECTOR4 ), 0 );
}

// 各種リソースを作成する
void CreateMesh( DWORD Width, DWORD Height )
{
   g_pPlane02->CreateMesh( g_pDirect3D11->m_pD3DDevice, Width, Height );
}

void NextFrame()
{
   NUI_LOCKED_RECT imageData = g_pKinect02->CreateImageData();
   NUI_LOCKED_RECT depthData = g_pKinect02->CreateDepthData();

   // カラーデータのa成分に深度値を格納する
   g_pKinect02->MergeImageDataAndDepthData( &imageData, &depthData, 3800.0f );

   g_pPlane02->NextFrame( g_pDirect3D11->m_pD3DDeviceContext, imageData );

   g_pKinect02->ReleaseImageData();
   g_pKinect02->ReleaseDepthData();
}

// 描画処理
HRESULT Render()
{
   float ClearColor[4] = { 0.0f, 0.125f, 0.6f, 1.0f };

   // バックバッファをクリアする。
   g_pDirect3D11->ClearBackBuffer( ClearColor ); 

   // 深度バッファをクリアする。
   g_pDirect3D11->ClearDepthStencilView( D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );

   // グラフィックパイプラインの設定
   {
      g_pGraphicsPipeline->SetVertexShader( g_pDirect3D11->m_pD3DDeviceContext );
      g_pGraphicsPipeline->SetPixelShader( g_pDirect3D11->m_pD3DDeviceContext );
      g_pGraphicsPipeline->SetRasterizerState( g_pDirect3D11->m_pD3DDeviceContext );
      g_pGraphicsPipeline->SetDepthStencilState( g_pDirect3D11->m_pD3DDeviceContext );
      g_pGraphicsPipeline->SetBlendState( g_pDirect3D11->m_pD3DDeviceContext );

      // 定数バッファを設定
      g_pDirect3D11->m_pD3DDeviceContext->VSSetConstantBuffers( 0, _countof( g_pConstantBuffers ), g_pConstantBuffers );
      g_pDirect3D11->m_pD3DDeviceContext->PSSetConstantBuffers( 0, _countof( g_pConstantBuffers ), g_pConstantBuffers );
   }

   // レンダリング
   {
      g_pPlane02->Render( g_pDirect3D11->m_pD3DDeviceContext );
   }

   // レンダリングされたイメージをユーザーに表示。
   return g_pDirect3D11->Present( 0, 0 );
}
 
// メイン関数
int APIENTRY _tWinMain( HINSTANCE hInstance,
                        HINSTANCE /*hPrevInstance*/,
                        LPTSTR    /*lpCmpLine*/,
                        INT       /*nCmdShow*/ )
{
   // メモリリーク検出
   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_EVERY_1024_DF);

   MSG msg = {0};

   try
   {
      // Direct3D 関連自作クラスのインスタンスを作成
      // CreateDirect3D()関数内でインスタンスの作成を行うと、C2712 エラーが発生するのでここで行う。
      g_pDirect3D11 = NEW UCDirect3D11();
      g_pGraphicsPipeline = NEW UCGraphicsPipeline();
      g_pPlane02 = NEW UCPlane02();
      g_pKinect02 = NEW UCKinect02();

      DWORD Width = 0, Height = 0;

      // Kinectセンサーオブジェクトを作成
      g_pKinect02->CreateKinect( NUI_INITIALIZE_FLAG_USES_COLOR | NUI_INITIALIZE_FLAG_USES_DEPTH, Width, Height );

      // Direct3Dの作成
      CreateDirect3D( hInstance, Width, Height );

      // グラフィックパイプラインリソースの作成
      CreateGraphicePipeline( Width, Height );

      // リソースの作成
      CreateMesh( Width, Height );

      ::ShowWindow( g_pDirect3D11->m_hWnd, SW_SHOW );
      ::UpdateWindow( g_pDirect3D11->m_hWnd );

      // メッセージループ
      do
      { 
        if( ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
        {
          ::TranslateMessage(&msg); 
          ::DispatchMessage(&msg); 
        }
        else
        {
          NextFrame();
          Render();
        }
      }while( msg.message != WM_QUIT );
   }
   catch( UCException ex )
   {
      ::MessageBox( nullptr, ex.m_pErrorStr, _T("エラー"), MB_OK );
   }

   Invalidate();
   ::UnregisterClass( AppName, hInstance );

   return msg.wParam;
}

以上です。

web拍手 by FC2

Prev Top Next

inserted by FC2 system