HLSL:クック・トランス金属反射

フォン鏡面反射はプラスチックのような材質を表現するのに適していました。
金属のような材質はクック・トランス金属反射を使います。

HLSL.cpp

#include <d3dx9.h>
#include <string>
#define WINDOW_WIDTH  640 //ウインドウの幅
#define WINDOW_HEIGHT  480 //ウインドウの高さ
#define SAFE_RELEASE(x) if(x){x->Release();} 

#define vec3 D3DXVECTOR3
using namespace std;

LPDIRECT3D9             g_pD3D       = NULL;//Direct3D9
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL;//レンダリングデバイス
LPD3DXEFFECT     m_pEffect; // ★シェーダ
D3DXHANDLE      m_hTechnique;// ★テクニック
D3DXHANDLE      m_hmWVP; // ★ワールド~射影行列
D3DXHANDLE      m_hvLightDir;
D3DXHANDLE      m_hvColor;
D3DXHANDLE      m_hvEyePos;
LPDIRECT3DVERTEXDECLARATION9 m_pDecl; // 頂点宣言

struct VECTOR3D
{
 vec3 Pos;
 vec3 Size;
 vec3 Angle;
};
class MODEL{
 public:
  LPD3DXMESH    Mesh;//メッシュ
  D3DMATERIAL9*   Material;//マテリアル
  LPDIRECT3DTEXTURE9*  Texture;//テクスチャ
  DWORD PartsNumber;//マテリアル数
  VECTOR3D Local;
  void LoadXFile(string);
  void XFileDraw();
};

//Xファイル描画
void MODEL::XFileDraw()
{
 D3DXMATRIXA16 m,matWorld,matView,matScale,matRotation,matProj,matPosition[4],matPos;
 D3DXMatrixIdentity(&matWorld);
 D3DXMatrixScaling(&matScale,Local.Size.x,Local.Size.y,Local.Size.z);
    D3DXMatrixMultiply(&matWorld,&matWorld,&matScale);
  //ワールドトランスフォーム(絶対座標変換)
 D3DXMatrixIdentity(&matRotation);

 D3DXMatrixRotationY( &matRotation, Local.Angle.y );
 D3DXMatrixMultiply(&matWorld,&matWorld,&matRotation);
 D3DXMatrixRotationX( &matRotation, Local.Angle.x );
 D3DXMatrixMultiply(&matWorld,&matWorld,&matRotation);
 D3DXMatrixRotationZ( &matRotation, Local.Angle.z );

 D3DXMatrixMultiply(&matWorld,&matWorld,&matRotation);
 D3DXMatrixTranslation(&matPos,Local.Pos.x,Local.Pos.y,Local.Pos.z);
 D3DXMatrixMultiply(&matWorld,&matWorld,&matPos);

 // ビュートランスフォーム(視点座標変換)
 D3DXVECTOR3 vecEyePt( 0.0f, 7.0f,-3.5f ); //カメラ(視点)位置
 D3DXVECTOR3 vecLookatPt( 0.0f, 0.0f, 0.0f );//注視位置
 D3DXVECTOR3 vecUpVec( 0.0f, 1.0f, 0.0f );//上方位置
 D3DXMatrixLookAtLH( &matView, &vecEyePt, &vecLookatPt, &vecUpVec );
 // プロジェクショントランスフォーム(射影変換)
 D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
 m = (matWorld * matView * matProj);

 m_pEffect->SetMatrix( m_hmWVP, &m );

 D3DXVECTOR4 v;
 //light
 D3DXVECTOR4 light_pos = D3DXVECTOR4(-0.577f,-0.577f,-0.577f,0);
 D3DXMatrixInverse(&m,NULL,&matWorld);
 D3DXVec4Transform(&v,&light_pos,&m);
 D3DXVec3Normalize((D3DXVECTOR3 *)&v,(D3DXVECTOR3 *)&v);// 正規化
 v.w = -0.3f;// 環境光の強さ
 m_pEffect->SetVector(m_hvLightDir,&v);

 // 視点
   m = matWorld * matView;
   D3DXMatrixInverse( &m, NULL, &m);
   v = D3DXVECTOR4( 0, 0, 0, 1);
   D3DXVec4Transform( &v, &v, &m );
   m_pEffect->SetVector( m_hvEyePos, &v );

 //-------------------------------------------------
 // ★シェーダの設定
 //-------------------------------------------------
 m_pEffect->SetTechnique( m_hTechnique );
 m_pEffect->Begin( NULL, 0 );
 m_pEffect->BeginPass( 0 );

 g_pd3dDevice->SetFVF( D3DFVF_XYZ | D3DFVF_NORMAL);

 m_pEffect->SetTexture("Tex", Texture[0]);
 //-------------------------------------------------
 // 描画
 //-------------------------------------------------
 g_pd3dDevice->SetVertexDeclaration( m_pDecl );

 D3DMATERIAL9 *pMtrl = &Material[0];
 for( DWORD i=0; i<PartsNumber; i++ )
        {
   v.x=pMtrl->Diffuse.r/1.3f;
   v.y=pMtrl->Diffuse.g/1.3f;
   v.z=pMtrl->Diffuse.b/1.3f;
   m_pEffect->SetVector( m_hvColor, &v );

   g_pd3dDevice->SetTexture( 0,Texture[i] );
   Mesh->DrawSubset( i );
   pMtrl++;
        }
 m_pEffect->EndPass();
 m_pEffect->End();
}
//Xファイル読み込み
void MODEL::LoadXFile(string FileName)
{
 // Xファイルからメッシュをロードする
 LPD3DXBUFFER pD3DXMtrlBuffer = NULL;

 D3DXLoadMeshFromXA( FileName.c_str(), D3DXMESH_SYSTEMMEM,g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL,&PartsNumber, &Mesh);
 D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
    Material = new D3DMATERIAL9[PartsNumber];
    Texture  = new LPDIRECT3DTEXTURE9[PartsNumber];

 for( DWORD i=0; i<PartsNumber; i++ )
 {
  Material[i] = d3dxMaterials[i].MatD3D; 
        Material[i].Ambient = Material[i].Diffuse;
        Texture[i] = NULL;
        if( d3dxMaterials[i].pTextureFilename != NULL &&lstrlenA(d3dxMaterials[i].pTextureFilename) > 0)
        {     
           D3DXCreateTextureFromFileA(g_pd3dDevice,d3dxMaterials[i].pTextureFilename,&Texture[i]);
        }
    }
 pD3DXMtrlBuffer->Release();
}


 MODEL Model[2];//モデル用

 HWND hwnd;

HRESULT Init()
{
 HRESULT hr;

 // ★シェーダの読み込み
    LPD3DXBUFFER pErr=NULL;
    if( FAILED( hr = D3DXCreateEffectFromFileA(
                g_pd3dDevice, "hlsl.fx", NULL, NULL,
                0 , NULL, &m_pEffect, &pErr ))){

        // シェーダの読み込みの失敗
        MessageBoxA( NULL, (LPCSTR)pErr->GetBufferPointer()
                    , "ERROR", MB_OK);
    }else{
        m_hTechnique = m_pEffect->GetTechniqueByName( "TShader" );
        m_hmWVP = m_pEffect->GetParameterByName( NULL, "mWVP" );
  m_hvLightDir = m_pEffect->GetParameterByName( NULL, "vLightDir" );
  m_hvColor = m_pEffect->GetParameterByName( NULL, "vColor" );
  m_hvEyePos   = m_pEffect->GetParameterByName( NULL, "vEyePos" );
    }
    SAFE_RELEASE(pErr);

 return true;
}
void FrameUpDate()
{
 Model[0].Local.Pos=vec3(0.0f,0.0f,0.0f);
 Model[0].Local.Angle=vec3(0.5f,timeGetTime()/10000.0f,0.0f);
 Model[0].Local.Size=vec3(1.0f,1.0f,1.0f);

 Model[1].Local.Pos=vec3(0.0f,0.0f,3.0f);
 Model[1].Local.Angle=vec3(0.5f,timeGetTime()/300.0f,0.0f);
 Model[1].Local.Size=vec3(1.0f,1.0f,1.0f);

}
void ScreenDraw()
{

// 画面をクリアする
    g_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
                         0x000000ff, 1.0f, 0L );
    //シーンの開始
    if(SUCCEEDED(g_pd3dDevice->BeginScene()))
    {

  Model[0].XFileDraw();
  Model[1].XFileDraw();
  
        //シーンの終了
        g_pd3dDevice->EndScene();
    }

    //バックバッファを表画面に反映させる
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

 

}
void GetFPS()
{
  FrameUpDate();
  ScreenDraw();
  Sleep(16);
}
DWORD WINAPI MainLoop(LPVOID vdParam)
{
 while(TRUE){
  GetFPS();
 }
 return 0;
}
HRESULT InitD3D( HWND hWnd )
{
 if(NULL==(g_pD3D=Direct3DCreate9(D3D_SDK_VERSION))){return E_FAIL;}

    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    d3dpp.BackBufferCount = 1;
    d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
    d3dpp.MultiSampleQuality = 0;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    d3dpp.hDeviceWindow = hWnd;
    d3dpp.Flags = 0;
    d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE ;

    if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice))){
        if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice))){
   return(E_FAIL);
        }
    }

 // Xファイルからメッシュをロードする
 Model[0].LoadXFile("land.x");
 Model[1].LoadXFile("ufo.x");

 Init();
    return S_OK;
}
LRESULT CALLBACK MsgProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
 switch (msg) {
  case WM_DESTROY:
   PostQuitMessage(0);
   return 0;
 }
 return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,PSTR lpCmdLine , int nCmdShow )
{
 MSG msg;
 DWORD dwID;


    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
                      GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                      L"Window1", NULL };
    RegisterClassEx( &wc );

 RECT rect;
 SetRect(&rect,0,0,WINDOW_WIDTH,WINDOW_HEIGHT);
 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
 SetRect(&rect,0,0,rect.right-rect.left,rect.bottom-rect.top);

    hwnd = CreateWindow( L"Window1", L"HLSL",
    WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, rect.right, rect.bottom,
                              NULL, NULL, wc.hInstance, NULL );

 if (hwnd == NULL) return 0;

  timeBeginPeriod(1);

 if(SUCCEEDED(InitD3D(hwnd))){
  ShowWindow(hwnd,SW_SHOWDEFAULT);
        UpdateWindow(hwnd);

  CreateThread(NULL , 0 , MainLoop , (LPVOID)hwnd , 0 , &dwID);
  while (GetMessage(&msg , NULL , 0 , 0 )) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }

 }
 UnregisterClass(L"Window1",wc.hInstance);
 timeEndPeriod(1);

 SAFE_RELEASE( m_pEffect );  // シェーダ
 SAFE_RELEASE( m_pDecl );  // 頂点宣言
 SAFE_RELEASE(g_pd3dDevice);
    SAFE_RELEASE(g_pD3D);
 return 0;
}

hlsl.fx

//グローバル変数
float4x4 mWVP;//ローカルから射影空間への座標変換

//テクスチャ
texture Tex;
sampler Samp = sampler_state
{
 Texture =<Tex>;
 MinFilter =LINEAR;
 MagFilter =LINEAR;
 MipFilter =NONE;

 AddressU =Clamp;
 AddressV =Clamp;
};

float4 vLightDir; // ライトの方向
float4 vColor;  // ライト*メッシュの色
float3 vEyePos; //カメラの位置
// 光の強さ
float4 I_a = { 0.3f, 0.3f, 0.3f, 0.0f };    // ambient
float4 I_d = { 0.7f, 0.7f, 0.7f, 0.0f };    // diffuse

// 反射率
float4 k_a = { 1.0f, 1.0f, 1.0f, 1.0f };    // ambient
float4 k_d = { 1.0f, 1.0f, 1.0f, 1.0f };    // diffuse

// 頂点シェーダからピクセルシェーダに渡すデータ
struct VS_OUTPUT
{
    float4 Pos  : POSITION;
    float4 Color  : COLOR0;
    float3 N  : TEXCOORD0;
    float3 X  : TEXCOORD1;
float2 Tex : TEXCOORD2;
    //float3 Eye  : TEXCOORD1;
};

//頂点シェーダプログラム
VS_OUTPUT VS(
      float4 Pos    : POSITION,          // ローカル位置座標
      float4 Normal : NORMAL,            // 法線ベクトル
float2 Tex : TEXCOORD
){
 VS_OUTPUT Out = (VS_OUTPUT)0;        // 出力データ
 
 // 座標変換
 Out.Pos = mul(Pos, mWVP);

 float amb = -vLightDir.w;//環境光の強さ
 float3 L = -vLightDir;//ライトベクトル
 Out.Color = vColor * max(amb,dot(Normal,-vLightDir));

 Out.N = Normal.xyz;
 Out.X = Pos.xyz;
 //Out.Eye =vEyePos - Pos.xyz;
Out.Tex = Tex;//テクスチャ座標

 return Out;
}
// -------------------------------------------------------------
float4 PS(VS_OUTPUT In) : COLOR
{  
 float3 L = -vLightDir.xyz;//ライトベクトル
 //float3 H = normalize(L+normalize(In.Eye));
 float3 N = normalize(In.N);
 float3 V = normalize(vEyePos - In.X);
 float3 H = normalize(L + V);

 float NV = dot(N,V);
 float NH = dot(N,H);
 float VH = dot(V,H);
 float NL = dot(N,L);
 float LH = dot(L,H);

 const float m =0.35f;
 float NH2 = NH * NH;
 float D = exp(-(1-NH2)/(NH2*m*m))/(4*m*m*NH2*NH2);
 float G = min(1,min(2*NH*NV/VH,2*NH*NL/VH));
 float n = 20.0f;
 float g = sqrt(n*n+LH*LH-1);
 float gpc = g+LH;
 float gnc = g-LH;
 float cgpc = LH*gpc-1;
 float cgnc = LH*gnc+1;
 float F = 0.5f*gnc*gnc*(1+cgpc*cgpc/(cgnc*cgnc))/(gpc*gpc);
 float4 ks = {2.0f*0.486f,2.0f*0.433f,2.0f*0.185f,1.0f};
 return In.Color*1.5*tex2D( Samp, In. Tex)+ks*max(0,F*D*G/NV)/2;

//return In.Color+pow(max(0,dot(N,H)),50);
}

// -------------------------------------------------------------
// テクニック
// -------------------------------------------------------------
technique TShader
{
    pass P0
    {
        VertexShader = compile vs_3_0 VS();
        PixelShader  = compile ps_3_0 PS();
    }
}

最終更新:2009年06月02日 22:11
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。
添付ファイル