ランバートシェーダーは、拡散照明の陰影処理を行うための、シェーダーで、
視線方向に依存しない光源の入射方向(面から光源方向へのベクトル)と面の向き(法線)だけあれば実装できるシェーダーです。
ごつごつした岩や、木材などを表現することはできますが、プラスチックなどのハイライトの出る物体を表現することはできません。
ランバートシェーダーでは、ランバートの余弦則
「その地点の明るさは、面の向きを光の入射方向が織り成す角度θのCOSθに比例する」と定義されています。
数式にあらわすと
I = Id * Kd * cosθ = Id * Kd * (N・L)
となっています。
記号の意味は
Id = 光の強さ
Kd = 反射係数
θ = 入射角
N = 法線ベクトル
L = ライトベクトル
解説は、このあたりにして実装へといきましょうか。
float3 light = float3( 10.0f, 10.0f, 10.0f ); // ライトの位置
//入力頂点構造体
struct VS_INPUT
{
float4 position : POSITION; //頂点座標
float3 normal : NORMAL; //法線ベクトル
float4 color : COLOR0; //色
};
//出力頂点構造体
struct VS_OUTPUT
{
float4 position : POSITION; //頂点座標
float3 normal : TEXCOORD1; //法線ベクトル
float4 color : COLOR0; //色
float3 light : TEXCOORD0; //ライトベクトル
};
//頂点シェーダー
VS_OUTPUT vs_main(
VS_INPUT input,
uniform float4x4 world,
uniform float4x4 view,
uniform float4x4 projection,
uniform float3 light
)
{
VS_OUTPUT output;
・・・・・ //省略
//ライトベクトルの設定
output.light = light - output.position.xyz;
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.2f, 0.2f, 1.0f );
float4 Kd = float4( 1.0f, 1.0f, 1.0f, 1.0f );
//入力ピクセル構造体
struct PS_INPUT
{
float4 color : COLOR0; //色
float3 normal : TEXCOORD1; //法線
float3 light : TEXCOORD0; //ライトベクトル
};
//ピクセルシェーダー
float4 ps_main(
PS_INPUT input,
uniform float4 Ambient,
uniform float4 Diffuse,
uniform float4 Ka,
uniform float4 Kd
) : COLOR0
{
//ライトベクトルの正規化
float3 L = normalize( input.light );
//法線の正規化
float3 N = normalize( input.normal );
//ランバート
float diffuse = max( dot( L, N ), 0 );
//環境光
float4 totalAmbient = Ambient * Ka * input.color;
//拡散光
float4 totalDiffuse = Kd * Diffuse * diffuse * input.color;
return totalAmbient + totalDiffuse;
}
//テクニックの指定
technique lambert
{
//パスの指定
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 );
}
}
EmptyProjectに同梱してある、test.cgfxを上記のように修正していただくと
固定機能でレンダリングしたような、以下のようなトーラスが描画されると思います。
より陰の部分を、現実に近づけたいなら、以下の部分を
float diffuse = max( dot( L, N ), 0 );
以下のように変更してください
float diffuse = max( dot( L, N ), 0 ) * 0.5 + 0.5f;
diffuse = diffuse * diffuse;
変更して実行すると、以下のように陰の部分が薄くなっています。
これは、ハーフランバートシェーダーと呼ばれています。
ハーフライフなどを制作したValveSoftwereという会社独自の
擬似ラジオシティライティング技法だそうです。
あくまで、擬似的なので物理的には正しくないようです。
現実では、あちこちから光が反射してくるので
以前のプログラムで出た結果のように
陰の部分が真っ黒になることは少ないと思いますので、
ハーフランバートを使ったほうがより自然に見せることができます。
今回は、ここまで。
最終更新:2009年01月22日 22:31