鏡面反射のシェーディングモデルの1つであるクック・トランス(Cook-Torrance)のモデルを実装してみる。クック・トランスのモデルでは金属の反射に適しているらしい。
調べてみたところクック・トランスのモデルの式がどれも若干違っていた。英語のwikipediaの参考されていたpdfを元にしてみる。(リンクとリンク先がどうも違う論文のようであるが)
クック・トランスのモデルの鏡面反射は以下のようになる。
上記の式でRsは反射率、Fはフレネル項、Dは微小面の分布関数、Gは幾何学的減衰係数、Nは法線、Lは光源へのベクトル、Vは視点へのベクトルである。Dはベックマン分布が用いられる。(DはdistributionのD)
αはNとH(ハーフベクトル)のなす角度なのでcosα=N・H。mは面の粗さを調整するパラメータ。
3つのうち最小のものをGにする。フレネル項は
nは相対屈折率。nは反射率から求められる。F0はθが0のときの反射率。金属の反射率は光の波長に依存するのでF0をベクトルにしておく。
Wikipediaだとフレネル項が近似式になっている。
上記の式はSchlickの近似となっているが詳しいことは不明。(そもそもλが何を表している?)実際Schlickの近似でググると出てくるのは以下の式。
今回はフレネルの式をそのまま使った。左がCook-Torranceで右側がBlinnのモデルで描画した結果。
uniform vec4 diffuse; // 拡散反射係数 uniform vec4 specular; // 鏡面反射係数 uniform vec4 ambient; // 環境光 uniform float microfacet; // 面の粗さ varying vec3 vNormal; varying vec3 vView; varying vec3 vLightDirection; // Beckman分布 float BechmannDistribution(float d, float m) { float d2 = d * d; float m2 = m * m; return exp((d2 - 1.0) / (d2 * m2)) / (m2 * d2 * d2); } // フレネル項 float Fresnel(float c, float f0) { float sf = sqrt(f0); float n = (1.0 + sf) / (1.0 - sf); float g = sqrt(n * n + c * c - 1.0); float ga = (c * (g + c) - 1.0) * (c * (g + c) - 1.0); float gb = (c * (g - c) + 1.0) * (c * (g - c) + 1.0); return (g - c) * (g - c) / (2.0 * (g + c) + (g + c)) * (1.0 + ga / gb); } void main() { vec3 l = normalize(vLightDirection); vec3 n = normalize(vNormal); vec3 v = normalize(vView); vec3 h = normalize(l + v); float hn = dot(h, n); float ln = dot(l, n); float lh = dot(l, h); float vn = dot(v, n); // Cook-Torrance vec3 f = vec3(Fresnel(lh, specular.x), Fresnel(lh, specular.y), Fresnel(lh, specular.z)); float d = BechmannDistribution(hn, microfacet); float t = 2.0 * hn / dot(v, h); float g = min(1.0, min(t * vn, t * ln)); float m = 3.14159265 * vn * ln; vec3 spe = max(f * d * g / m, 0.0); vec3 dif = max(ln, 0.0) * diffuse.xyz; vec3 amb = ambient.xyz; gl_FragColor = vec4(spe + dif + amb, 1.0); }
参考にした論文
http://inst.eecs.berkeley.edu/~cs283/sp13/lectures/cookpaper.pdf
式が何パターンか見つかることについての話が以下のところに書いてあるような
http://www.gamedev.net/topic/638197-cook-torrance-brdf-general/
[…] Cook-Torranceのシェーディングモデルでフレネルを式を使ったが、フレネルの式の近似としてSchlickの近似というものがある。実際にどのくらい正しいのかグラフを書いてみた。ちなみにCook-Torranceの論文にも似たような近似式が載っていた。 […]
By: フレネルの式の近似 | 生存日記 on 2013年3月14日
at 1:14 午前