TOP

ABOUT

PROGRAM

DIALY







ライティング(1) Phong

 1.はじめに…
 今更ですが…Phongシェーディングを全然やっていなかったので,Phongシェーディングのプログラムをつくってみました。
ちなみにプログラムはピクセル単位で計算するようになっています。




 2.Phong Shading
 照明効果は全然やったことがないので,まず有名なPhongの鏡面反射モデルをやります。
フォンのモデルは光沢のあるプラスティックなどの鏡面反射の計算によく使われるそうです。



フォンさんは何をやったかというと,視線が物体で跳ね返ったときの反射ベクトルRを求めて,反射ベクトルとライトベクトルLと近ければ強い光に,RとLが離れていれば弱い光になるように定式化したそうです。
数式で表すと下のようになります。


ここで,Ia, Id, Isは環境光,拡散反射光,鏡面反射光の強さで,ka, kd, ksはそれぞれの反射係数を表します。
反射ベクトルRはどうやって求めるかというとつぎの公式で求めます。


Eは視線ベクトルで物体から視点を見た方向です。
ここで問題になるのは内積を計算して内積の値が負になる場合があるのことです。またライトベクトルの向きが反対を向いてしまう場合も問題が生じるので,こういった場合には光が当たらないものとして強さを0にしてしまいます。
あとは,計算ですね。ワールド座標系で計算すると行列の転置をもとめたりと,何かと面倒なようなのでローカル座標系で計算します。
ライトの方向が何もしないとワールド座標系のままになってしまうで,ワールド行列の逆行列をライトの位置ベクトルにかけてやってローカル座標系へとアプリケーション側で変換してからGPU側におくります。
逆行列の求め方は大学1年ぐらいの線形代数でやるとおもうので,教科書の後ろにある索引とかで余因子展開を調べて,該当するページをみつけてやれば出てくると思うので式は各自本を参照してください。
とりあえず,長いですが4×4の逆行列を求めるプログラムを下に載せておきます。

  1931 : 	template<class T> inline T MatrixDeterminant(const AsuraMatrix<T> &mat)
  1932 : 		{
  1933 : 			T det = mat._11*mat._22*mat._33*mat._44 + mat._11*mat._23*mat._34*mat._42 
  1934 : 				+ mat._11*mat._24*mat._32*mat._43 + mat._12*mat._21*mat._34*mat._43 
  1935 : 				+ mat._12*mat._23*mat._31*mat._44 + mat._12*mat._24*mat._33*mat._41
  1936 : 				+ mat._13*mat._21*mat._32*mat._44 + mat._13*mat._22*mat._34*mat._41
  1937 : 				+ mat._13*mat._24*mat._31*mat._42 + mat._14*mat._21*mat._33*mat._42
  1938 : 				+ mat._14*mat._22*mat._31*mat._43 + mat._14*mat._23*mat._32*mat._41
  1939 : 				- mat._11*mat._22*mat._34*mat._43 - mat._11*mat._23*mat._32*mat._44
  1940 : 				- mat._11*mat._24*mat._33*mat._42 - mat._12*mat._21*mat._33*mat._44
  1941 : 				- mat._12*mat._23*mat._34*mat._41 - mat._12*mat._24*mat._31*mat._43
  1942 : 				- mat._13*mat._21*mat._34*mat._42 - mat._13*mat._22*mat._31*mat._44
  1943 : 				- mat._13*mat._24*mat._32*mat._41 - mat._14*mat._21*mat._32*mat._43
  1944 : 				- mat._14*mat._22*mat._33*mat._41 - mat._14*mat._23*mat._31*mat._42;
  1945 : 			return det;
  1946 : 		}
  1947 : 	

  2026 : 	template<class T> inline AsuraMatrix<T> MatrixInverse(AsuraMatrix<T>&output, const AsuraMatrix<T> &mat)
  2027 : 		{
  2028 : 			T det = MatrixDeterminant(mat);
  2029 : 	
  2030 : 			output._11 = mat._22*mat._33*mat._44 + mat._23*mat._34*mat._42 + mat._24*mat._32*mat._43 - mat._22*mat._34*mat._43 - mat._23*mat._32*mat._44 - mat._24*mat._33*mat._42;
  2031 : 			output._12 = mat._12*mat._34*mat._43 + mat._13*mat._32*mat._44 + mat._14*mat._33*mat._42 - mat._12*mat._33*mat._44 - mat._13*mat._34*mat._42 - mat._14*mat._32*mat._43;
  2032 : 			output._13 = mat._12*mat._23*mat._44 + mat._13*mat._24*mat._42 + mat._14*mat._22*mat._43 - mat._12*mat._24*mat._43 - mat._13*mat._22*mat._44 - mat._14*mat._23*mat._42;
  2033 : 			output._14 = mat._12*mat._24*mat._33 + mat._13*mat._22*mat._34 + mat._14*mat._23*mat._32 - mat._12*mat._23*mat._34 - mat._13*mat._24*mat._32 - mat._14*mat._22*mat._33;
  2034 : 	
  2035 : 			output._21 = mat._21*mat._34*mat._43 + mat._23*mat._31*mat._44 + mat._24*mat._33*mat._41 - mat._21*mat._33*mat._44 - mat._23*mat._34*mat._41 - mat._24*mat._31*mat._43;
  2036 : 			output._22 = mat._11*mat._33*mat._44 + mat._13*mat._34*mat._41 + mat._14*mat._31*mat._43 - mat._11*mat._34*mat._43 - mat._13*mat._31*mat._44 - mat._14*mat._33*mat._41;
  2037 : 			output._23 = mat._11*mat._24*mat._43 + mat._13*mat._21*mat._44 + mat._14*mat._23*mat._41 - mat._11*mat._23*mat._44 - mat._13*mat._24*mat._41 - mat._14*mat._21*mat._43;
  2038 : 			output._24 = mat._11*mat._23*mat._34 + mat._13*mat._24*mat._31 + mat._14*mat._21*mat._33 - mat._11*mat._24*mat._33 - mat._13*mat._21*mat._34 - mat._14*mat._23*mat._41;
  2039 : 	
  2040 : 			output._31 = mat._21*mat._32*mat._44 + mat._22*mat._34*mat._41 + mat._24*mat._31*mat._42 - mat._21*mat._34*mat._42 - mat._22*mat._31*mat._44 - mat._24*mat._32*mat._41;
  2041 : 			output._32 = mat._11*mat._34*mat._42 + mat._12*mat._31*mat._44 + mat._14*mat._32*mat._41 - mat._11*mat._32*mat._44 - mat._12*mat._34*mat._41 - mat._14*mat._31*mat._42;
  2042 : 			output._33 = mat._11*mat._22*mat._44 + mat._12*mat._24*mat._41 + mat._14*mat._21*mat._42 - mat._11*mat._24*mat._42 - mat._12*mat._21*mat._44 - mat._14*mat._22*mat._41;
  2043 : 			output._34 = mat._11*mat._24*mat._32 + mat._12*mat._21*mat._34 + mat._14*mat._22*mat._31 - mat._11*mat._22*mat._34 - mat._12*mat._24*mat._31 - mat._14*mat._21*mat._32;
  2044 : 	
  2045 : 			output._41 = mat._21*mat._33*mat._42 + mat._22*mat._31*mat._43 + mat._23*mat._32*mat._41 - mat._21*mat._32*mat._43 - mat._22*mat._33*mat._41 - mat._23*mat._31*mat._42;
  2046 : 			output._42 = mat._11*mat._32*mat._43 + mat._12*mat._33*mat._41 + mat._13*mat._31*mat._42 - mat._11*mat._33*mat._42 - mat._12*mat._31*mat._43 - mat._13*mat._32*mat._41;
  2047 : 			output._43 = mat._11*mat._23*mat._42 + mat._12*mat._21*mat._43 + mat._13*mat._22*mat._41 - mat._11*mat._22*mat._43 - mat._12*mat._23*mat._41 - mat._13*mat._21*mat._42;
  2048 : 			output._44 = mat._11*mat._22*mat._33 + mat._12*mat._23*mat._31 + mat._13*mat._21*mat._32 - mat._11*mat._23*mat._32 - mat._12*mat._21*mat._33 - mat._13*mat._22*mat._31;
  2049 : 	
  2050 : 			output = ((T)1.0/det) * output;
  2051 : 			return output;
  2052 : 		}
  2053 : 	

OpenGLでもd3dx10mathみたいな算術ヘルパー関数とかがあればいいですけどね。ないのでこの辺の計算ライブラリを自分で実装するとなると余計な時間がかかっていやなんですよね〜。
GPU側はさっきの反射ベクトルを求める公式をつかって求めることと,内積が負にならないようにmax()関数を使って,値が負にならないようにしてやります。そこだけを押さえておけば問題ないと思います。
    54 : 	//
    55 : 	// Pixel Shader
    56 : 	//
    57 : 	float4 PhongPS(VertexOutput input) : COLOR
    58 : 	{
    59 : 		float3 P = input.objPosition.xyz;
    60 : 		float3 N = normalize(input.normal);
    61 : 	
    62 : 		// Ambient Color
    63 : 		float3 ambient = gAmbient * Ka;
    64 : 		
    65 : 		// Diffuse Color
    66 : 		float3 L = normalize(lightPosition - P);	// ローカル座標系のでのライトベクトル
    67 : 		float diffuseLight = max(dot(L, N), 0);
    68 : 		float3 diffuse = Kd * lightColor * diffuseLight;
    69 : 	
    70 : 		// Specular Color
    71 : 		float3 V = normalize(eyePosition - P);
    72 : 		float3 R = -V + 2.0f *dot(N, V) * N;	// 反射ベクトル
    73 : 		float3 specularLight = pow(max(dot(L, R), 0), power);
    74 : 		float3 specular = Ks * lightColor * specularLight;
    75 : 	
    76 : 		return float4(ambient + diffuse + specular, 1.0f);
    77 : 	}
    78 : 	

Phong Shadingをやって,ようやくちょっと現代にちょっと近づいてきましたかね?


 Download
本ソースコードおよびプログラムを使用したことによる如何なる損害も製作者は責任を負いません。
本ソースコードおよびプログラムは自己責任でご使用ください。
プログラムの作成にはMicrosoft Visual Studio 2005 SP1 Professional, Cg Toolkit 2.0 Decemberを用いています。