Cook-Torrance

今回は、金属の反射をシミュレートするcook-torranceを実装します。

Beckmann分布関数、幾何学減衰率とフレネル項を使って表現しています。

説明すると、数式ばかりになってしまうので、細かい説明は省きます。

以下、実装

 //グローバル変数宣言
 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; //ビューベクトル
 	float3 halfAngle : TEXCOORD3; //二等分ベクトル
 };
 
 //頂点シェーダー
 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;
 	
 	//二等分ベクトル
 	float3 H = normalize( L+V );
 	output.halfAngle = H;
 	
 	//ビューベクトルの設定
 	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 Ka = float4( 0.2f*0.486f, 0.2f*0.433f, 0.2f*0.185f, 1.0f );
 float4 Kd = float4( 0.486f, 0.433f, 0.185f, 1.0f );
 float4 Ks = float4( 2.0f*0.486f, 2.0f*0.433f, 2.0f*0.185f, 1.0f );
 
 //荒さ
 float harsh = 0.35f;
 //複素屈折率の実数部
 float real = 20.0f;
 
 //入力ピクセル構造体
 struct PS_INPUT
 {
 	float4 color	: COLOR0; //色
 	float3 normal	: TEXCOORD1; //法線
 	float3 light	: TEXCOORD0; //ライトベクトル
 	float3 view		 : TEXCOORD2; //ビューベクトル
 	float3 halfAngle : TEXCOORD3; //二等分ベクトル
 };  
 
 //ピクセルシェーダー
 float4 ps_main( 
 	PS_INPUT input,
 	uniform float4 Ambient,
 	uniform float4 Diffuse,
 	uniform float4 Ka,
 	uniform float4 Kd,
 	uniform float4 Ks,
 	uniform float harsh,
 	uniform float real
 ) : COLOR0
 {
 	//ライトベクトルの正規化
 	float3 L = normalize( input.light );
 	//法線の正規化
 	float3 N = normalize( input.normal );
 	//ビューベクトルの正規化
 	float3 V = normalize( input.view );
 	//二等分べkとるの正規化
  	float3 H = normalize( input.halfAngle );
 	
 	//ディフーズ
 	float diffuse = max( dot( L, N ), 0 );
 	
 	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 );
 	
 	//Beckmann分布関数
 	float NH2 = NH * NH;
 	float D = exp( -( 1 - NH2 ) / ( NH2 * harsh * harsh ) ) / ( 4 * harsh * harsh * NH2 *  NH2 );
 	
 	//幾何減衰率
 	float G = min( 1, min( 2 * NH * NV / VH, 2 * NH * NL / VH ) );
 	
 	//フレネル
 	float g = sqrt( real * real + 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 totalAmbient = Ambient * Ka * input.color;
 	//拡散反射光
 	float4 totalDiffuse = Kd * Diffuse * diffuse * input.color;
 	//鏡面反射光
 	float4 totalSpecular = Ks * max( 0, F * D * G / NV );
 	
 	return totalAmbient + totalDiffuse + totalSpecular;
 }
 
 //テクニックの指定
 technique cooktorrance
 {	
 	//パスの指定
 	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, Ka, Kd, Ks, harsh, real );
 	}
 }

実行結果は、

となります。

金属っぽく見えますかね?

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

下から選んでください:

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