~プログラミング~ DirectX 11でフォン反射モデル

 

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

今回はオブジェクトの質感を設定してみようと思います。

 

質感はオブジェクトに当たった光をどのように反射するかを求める事で表現出来そうです。ライティングの方法はいくつもありますが最もオーソドックスなものを使ってみます。

 


局所照明モデルと大域照明モデル

局所照明モデルとは、物体に対して直接的な光に対してのみ計算を行うものです。現実世界では他の物体から反射した光によっても照らされる為リアルさでは劣るものの、その分計算が単純で高速である為リアルタイムレンダリングでは多く使われる手法です。

 

大域照明モデルは間接光などの影響も含めて計算を行うもので、よりリアルな表現を可能にします。


フォン反射モデル

フォン反射モデルは局所照明モデルの一つで、物体に直接あたる光を計算していきます。

 

フォン反射モデルでは、物体に直接あたる光を拡散反射鏡面反射環境反射の3つに分けて考えます。

各反射の詳細な計算方法などはリンク先のページでご確認ください。

拡散反射・鏡面反射・環境反射を足し合わせて色が決まります。

 

拡散・鏡面・環境それぞれに対してどのように光を反射するのかを決めていくことで、物体がの色や質感を表現していきます。


ピクセルシェーダー

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

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

struct Light {
    float4 pos;               //座標(x,y,z)
    float4 diffuse;           //拡散(r,g,b)
    float4 specular;          //反射(r,g,b)
    float4 attenuate;         //減衰(a,b,c)
};

struct Material {
    float4 ambient;           //環境(r,g,b)
    float4 diffuse;           //拡散(r,g,b)
    float4 specular;          //反射(r,g,b,光沢度係数)
};

cbuffer ConstantBuffer {
    float4   eyePos;          //視点座標
    float4   ambient;         //環境光(r,g,b)
    Light    pntLight;        //点光源
    Material material;        //物体の質感
};

float4 ps_main( PS_IN input ) : SV_Target
{
    float3 n;
    float3 v;
    float3 l;
    float3 r;
    float  d;
    float  a;
    float3 iA;
    float3 iD;
    float3 iS;

    n = normalize(input.norw.xyz);
    v = normalize(eyePos.xyz - input.posw.xyz);
    l = pntLight.pos.xyz - input.posw.xyz;
    d = length(l);                                                                                         //光源距離
    l = normalize(l);                                                                                      //正規化光源ベクトル
    r = 2.0 * n * dot(n, l) - l;                                                                           //正規化反射ベクトル
    a = saturate(1.0f / (pntLight.attenuate.x + pntLight.attenuate.y * d + pntLight.attenuate.z * d * d)); //減衰

    iA =                                                 material.ambient.xyz  * ambient.xyz;
    iD =     saturate(dot(l, n))                       * material.diffuse.xyz  * pntLight.diffuse.xyz  * a;
    iS = pow(saturate(dot(r, v)), material.specular.w) * material.specular.xyz * pntLight.specular.xyz * a;

    return float4(saturate(iA + iD + iS), 1.0);
}