~プログラミング~ DirectX 11で拡散反射 (Diffuse reflection)

C++言語でDirectX 11を使ったアプリケーションを開発してみよう。

今回はライティングの手法の一つ拡散反射についてまとめてみようと思います。

 

ちなみに平行光源ライティング点光源ライティングではこの拡散反射を使ったものになっています。


拡散反射 (Diffuse reflection)

拡散反射はザラザラした表面からの光の反射を表現します。

物体に当たった光は様々な方向に乱反射するという考え方で反射光は全方向に均等に広がっていくので、見ている人の位置は関係なく計算できます。

 

拡散反射の強さはランバートの余弦則というもので計算できます。ランバートの余弦則とは、入射光と面の法線との間の角度θの余弦と正比例することを示す法則です。

 

同じ強さの光でも入射角が大きくなるほど広い面積が照らされる事になるため、同一面積当たりの光は弱くなるという理屈です。

法則を計算式にすると以下のようになります。

 

I =(L・N)* D * ID

 

面の正規化法線ベクトルと面から光源への正規化ベクトルの内積を計算し、そこに面の色Dと入射光の輝度Dを掛け合わせて求められます。

 

※Lは方向に注意(面から光源へ)

※内積の結果がマイナスの場合は裏側から光が当たっている状態。マイナスのままではなく0にして計算する必要がある

 


ピクセルシェーダー

上記の計算をHLSLで書くとこんな感じになります。

struct PS_IN
{
    float4 pos  : SV_POSITION;
    float4 posw : POSITION0;    //ワールド座標系の座標
    float4 norw : NORMAL0;      //ワールド座標系の法線
};

cbuffer ConstantBuffer
{
    float4 pntlightPos;       //点光源座標
    float4 pntlightCol;       //点光源の色
    float4 materialDiffuse;   //物体の色
}

float4 ps_main( PS_IN input ) : SV_Target
{
    float3 l;
    float3 n;
    float  i;

    l = normalize(pntlightPos.xyz - input.posw.xyz);
    n = normalize(input.norw.xyz);
    i = saturate(dot(l, n));

    return float4(i * materialDiffuse.xyz * pntlightCol.xyz, 1.0);
}

ピクセルの座標と光源の座標から光源へ向かう正規化ベクトルを求めます。(21行目)

法線ベクトルも正規化します(頂点シェーダーでやっておくべきかもしれませんが)。(22行目)

dot(内積)で角度を求めsturateでマイナスの時は0になるようにします。(23行目)