Phong

今回は、
プラスティックなどの光の反射をシミュレートできる
フォンシェーダーを実装します。

基本的には、
 ランバートシェーダーの実装 + 鏡面反射の計算を行うだけです。

細かい解説は、Wikipediaの方に投げてしまおうと思います。
http://ja.wikipedia.org/wiki/Phong%E3%81%AE%E5%8F%8D%E5%B0%84%E3%83%A2%E3%83%87%E3%83%AB

以下 実装

 //グローバル変数宣言
 float4x4 world;			// ワールド行列
 float4x4 view;			// ビュー行列
 float4x4 projection;	// 透視変換行列
 float3 light = float3( 10.0f, 10.0f, 10.0f ); // ライトの位置
 
 //入力頂点構造体
 struct VS_INPUT
 { 
   	float4 position : POSITION; //頂点座標
   	float3 normal   : NORMAL;	//法線ベクトル
   	float4 color	: COLOR00;	//色
 };
 
 //出力頂点構造体
 struct VS_OUTPUT
 {
   	float4 position  : POSITION;  //頂点座標
   	float3 normal	 : TEXCOORD1; //法線ベクトル
   	float4 color	 : COLOR0;	  //色
   	float3 light	 : TEXCOORD0; //ライトベクトル
   	float3 view		 : TEXCOORD2; //ビューベクトル
 };
 
 //頂点シェーダー
 VS_OUTPUT vs_main(
   	VS_INPUT input,
   	uniform float4x4 world,
   	uniform float4x4 view,
   	uniform float4x4 projection,
   	uniform float3 light
 )
 {
   	VS_OUTPUT output;
   	
   	//モデルビュー行列
   	float4x4 WV = mul( world, view );
   
   	//法線ベクトルの座標変換
  	output.normal = mul(input.normal,(float3x3)WV);
   	
   	//モデルビュー透視変換行列
    	float4x4 WVP = mul( WV, projection );
   	
   	//頂点座標の座標変換
   	output.position = mul(input.position,WVP);
   	
   	//色の設定
   	output.color = input.color;
   	
       /* 追加 */
 
   	//視点座標系の頂点座標を求める
   	float3 PosEye = mul( input.position, WV );
   	//視点座標系のライト座標を求める
   	float3 LightPosEye = mul( light, (float3x3)view );
   	
   	//ライト方向のベクトル
   	float3 L = normalize( LightPosEye - PosEye );
   	output.light =L;
   	
   	//視点方向のベクトル
   	float3 V = normalize(-PosEye);
   	output.view = V;
   	
   	//ビューベクトルの設定
   	output.view = V;
 
   	/* 追加終了 */
       
   	return output;
 }
 
 //ライトカラー
 float4 Ambient = float4( 1.0f, 1.0f, 1.0f, 1.0f );
 float4 Diffuse = float4( 1.0f, 1.0f, 1.0f, 1.0f );
 float4 Specular = float4( 1.0f, 1.0f, 1.0f, 1.0f );
 //マテリアルカラー
 float4 Ka = float4( 0.2f, 0.2f, 0.2f, 1.0f );
 float4 Kd = float4( 0.6f, 0.6f, 0.6f, 1.0f );
 float4 Ks = float4( 1.0f, 1.0f, 1.0f, 1.0f );
 float power = 90.0f;
 
 //入力ピクセル構造体
 struct PS_INPUT
 {
 	float4 color	: COLOR0; //色
 	float3 normal	: TEXCOORD1; //法線
 	float3 light	: TEXCOORD0; //ライトベクトル
 	float3 view		 : TEXCOORD2; //ビューベクトル
 };
 
 //ピクセルシェーダー
 float4 ps_main( 
 	PS_INPUT input,
 	uniform float4 Ambient,
 	uniform float4 Diffuse,
 	uniform float4 Specular,
 	uniform float4 Ka,
 	uniform float4 Kd,
 	uniform float4 Ks,
 	uniform float power
 ) : COLOR0
 {
 	//ライトベクトルの正規化
 	float3 L = normalize( input.light );
 	//法線の正規化
 	float3 N = normalize( input.normal );
 	//ビューベクトルの正規化
 	float3 V = normalize( input.view );
 	//反射ベクトルを求める
 	float3 R = -V + 2.0f * dot( N, V ) * N;
 	
 	//ディフーズ
 	float diffuse = max( dot( L, N ), 0 );
 	//スペキュラ
 	float specular = pow( max( dot( L, R ), 0 ), power );
 	
 	
 	//環境光
 	float4 totalAmbient = Ambient * Ka * input.color;
 	//拡散反射光
 	float4 totalDiffuse = Kd * Diffuse * diffuse * input.color;
 	//鏡面反射光
 	float4 totalSpecular = Ks * Specular * specular;
 	
 	return totalAmbient + totalDiffuse + totalSpecular;
 }
 
 //テクニックの指定
 technique phong
 {	
 	//パスの指定
 	pass Pass_0
 	{
 		DepthTestEnable = true; //デプステストを有効
 		BlendEnable = true; //ブレンドを有効
 		BlendFunc = float2( SrcAlpha,OneMinusSrcAlpha ); //ブレンド関数を設定
 		VertexProgram = compile arbvp1 vs_main( world, view, projection, light );
     		FragmentProgram = compile arbfp1 ps_main( Ambient, Diffuse, Specular, Ka, Kd, Ks, power );
   	}
 }

以下のように鏡面反射が出ていれば成功です

今回は、ここまで。
最終更新:2009年01月31日 21:53
ツールボックス

下から選んでください:

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