GLSLを用いてフォンシェーディングを実装する.ここではまず,反射モデルとシェーディング方法に分けてそれぞれ説明する.



反射モデル

反射モデルは光の物体表面における反射をモデル化したものであり, ここでは,反射を環境光,拡散反射,鏡面反射に分けて考えるPhong反射モデルを用いる.

eq_Is.gif

k_e,k_a,k_dはそれぞれ物体表面の放射,環境,拡散反射色であり,l_a,l_dは光源色である. I_s は鏡面反射項であり,以下で説明する鏡面反射モデルにより計算する.

reflection.gif

Phong 鏡面反射モデル*1, *2

eq_Phong.gif

k_s は物体の鏡面反射色,m は鏡面反射指数でハイライトの強さを制御する.l_s は光源の鏡面反射色である. また,R は以下で計算される.

eq_R.gif

Blinn-Phong 鏡面反射モデル

Blinn により,R をハーフベクトルH に置き換えるモデルが提案されている.

eq_BlinnPhong.gif
eq_H.gif

Blinn 鏡面反射モデル*3

Torrance-Sparrow モデルを基にして,反射面を微少面(micro facet) の集合と捉えるのが,Blinn モデルである.

eq_Blinn.gif

D,G,Fそれぞれの項は,

  • D : 微少面分布関数であり,法線がH であるmicro facet の割合を示す.
    • Phongモデル : eq_D1.gif
    • Torrance-Sparrowモデル : eq_D2.gif
    • TrowbridgeとReitzのモデル : eq_D3.gif

が用いられる.α はNHのなす角(eq_alpha.gif), c_2 は分布の標準偏差,c_3 は楕円の偏心度で0ならハイライトがとても強い表面に,1 なら拡散面に近くなる.

  • G : 微少面に入射する光,もしくは,微少面から反射する光は近傍の微少面による凸凹により遮蔽される. これにより,鏡面反射が暗くなる現象を表すための項である.
    eq_G.gif
    1 は光が遮断されない場合,G1 は反射項の一部が遮断される場合,G2 は入射項の一部が遮断される場合である.
  • F : フレネル項であり,θ1 を入射角,θ2 は透過角とすると,
    eq_F1.gif
    鏡面反射に関わる微少面の法線ベクトルはHとなっていることから,eq_theta.gifとなる. これにより,上式を整理していくと以下のようになる.
    eq_F2.gif
    ここで,eq_n.gifは屈折率である.

Cook-Torrance 鏡面反射モデル*4

Blinn モデルを改良して,微少面分布関数D にBeckmann 分布関数を用いたものである.

eq_CookTorrance.gif

グーローとフォンシェーディング

反射モデルに基づき,画面にCGモデルを描画する際にどのように各ピクセルの色を決定するのかが問題となる. CG分野ではグーローシェーディングとフォンシェーディングの2種類が用いられている.

グーローシェーディングはまず,頂点ごとに上記の反射モデルに基づき色を決定し, その後,ピクセルごとの処理において頂点色を線形補間することでレンダリングを行う. 一方,フォンシェーディングはピクセルごとに色を計算する方法である.

OpenGLの描画ではグーローシェーディングが採用されている. そのため,フォンシェーディングを行いたい場合,GLSLやNVIDIA Cgのようなシェーディング言語を用いて実装しなければならない.

GLSLによるフォンシェーディング

GLSLを用いてフォンシェーディングを行う場合は,フラグメントシェーダ側でライティングの計算を行う. そのため,頂点シェーダは単純に透視投影変換前の視点座標系における頂点座標と法線を計算してフラグメントシェーダに送るだけである.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24

#version 120
 
varying vec3 vPos;
varying vec3 vNrm;
 
void main(void)
{
        vPos = (gl_ModelViewMatrix*gl_Vertex).xyz;
    vNrm = gl_NormalMatrix*gl_Normal;
 
        gl_Position = ftransform();
}

フラグメントシェーダでは,Blinn-Phongの鏡面反射モデルを用いてPhongシェーディングを行う. 以下にコード例を示す.コード例では上記の式との対応関係が分かりやすくなるように記述しているが, 実際には,表面の色とライトの色の掛け算などは gl_FrontLightProduct[0] で取得することもできる.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62

#version 120
 
varying vec3 vPos;
varying vec3 vNrm;
 
void main(void)
{
        vec3 La = gl_LightSource[0].ambient.xyz;        vec3 Ld = gl_LightSource[0].diffuse.xyz;        vec3 Ls = gl_LightSource[0].specular.xyz;        vec3 Lp = gl_LightSource[0].position.xyz;     
        vec3 Ke = gl_FrontMaterial.emission.xyz;        vec3 Ka = gl_FrontMaterial.ambient.xyz;            vec3 Kd = gl_FrontMaterial.diffuse.xyz;            vec3 Ks = gl_FrontMaterial.specular.xyz;        float shine = gl_FrontMaterial.shininess;
 
    vec3 V = normalize(-vPos.xyz);            vec3 N = normalize(vNrm);                vec3 L = normalize(Lp-vPos.xyz);     
        vec3 emissive = Ke;
 
        vec3 ambient = Ka*La;     
        float diffuseLight = max(dot(L, N), 0.0);
    vec3 diffuse = Kd*Ld*diffuseLight;
 
        vec3 specular = vec3(0.0);
    if(diffuseLight > 0.0){
                //vec3 R = reflect(-L, N);
                //float specularLight = pow(max(dot(R, N), 0.0), shine);
 
                vec3 H = normalize(L+V);
        float specularLight = pow(max(dot(H, N), 0.0), shine);
 
        specular = Ks*Ls*specularLight;
    }
 
    gl_FragColor.xyz = emissive+ambient+diffuse+specular;
    gl_FragColor.w = 1.0;
}

以下のコード例はCook-Torrance鏡面反射モデルに基づくフラグメントプログラムである.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78

#version 120
 
uniform float m;
uniform float refrac;
 
varying vec3 vPos;
varying vec3 vNrm;
 
void main(void)
{
        vec3 La = gl_LightSource[0].ambient.xyz;        vec3 Ld = gl_LightSource[0].diffuse.xyz;        vec3 Ls = gl_LightSource[0].specular.xyz;        vec3 Lp = gl_LightSource[0].position.xyz;     
        vec3 Ke = gl_FrontMaterial.emission.xyz;        vec3 Ka = gl_FrontMaterial.ambient.xyz;            vec3 Kd = gl_FrontMaterial.diffuse.xyz;            vec3 Ks = gl_FrontMaterial.specular.xyz;        float shine = gl_FrontMaterial.shininess;
 
    vec3 V = normalize(-vPos.xyz);            vec3 N = normalize(vNrm);                vec3 L = normalize(Lp-vPos.xyz);        vec3 H = normalize(L+V);             
        vec3 emissive = Ke;
 
        vec3 ambient = Ka*La;     
        float diffuseLight = max(dot(L, N), 0.0);
    vec3 diffuse = Kd*Ld*diffuseLight;
 
        vec3 specular = vec3(0.0);
    if(diffuseLight > 0.0){
         
        float NH = dot(N, H);
        float VH = dot(V, H);
        float NV = dot(N, V);
        float NL = dot(N, L);
 
        float alpha = acos(NH);
 
                float D = (1.0/(4*m*m*NH*NH*NH*NH))*exp((NH*NH-1)/(m*m*NH*NH));
 
                float G = min(1, min((2*NH*NV)/VH, (2*NH*NL)/VH));
 
                float c = VH;
        float g = sqrt(refrac*refrac+c*c-1);
        float F = ((g-c)*(g-c)/((g+c)*(g+c)))*(1+(c*(g+c)-1)*(c*(g+c)-1)/((c*(g-c)-1)*(c*(g-c)-1)));
 
        float specularLight = D*G*F/NV;
        specular = Ks*Ls*specularLight;
    }
 
    gl_FragColor.xyz = emissive+ambient+diffuse+specular;
    gl_FragColor.w = 1.0;
}

レンダリング結果

左からグーローシェーディング,フォンシェーディング(Phong反射モデル),フォンシェーディング(Cook-Torrance反射モデル)の結果である. gouraud_shading_1.jpg phong_shading_1.jpg ct_shading_1.jpg

ソースコード

Visual Studio 2010用のソースコードを以下に置く.


*1 B. Phong, "Illumination for computer-generated images", PhD thesis, The University of Utah, 1973.
*2 B. Phong, "Illumination for computer generated pictures", Commun. ACM, Vol.18, pp.311-317, 1975.
*3 J. Blinn, "Models of light reflection for computer synthesized pictures", SIGGRAPH Comput. Graph., Vol.11, pp.192-198, 1977.
*4 R. Cook and K. Torrance, "A reflectance model for computer graphics", SIGGRAPH Comput. Graph., Vol.15, pp.307-316, 1981.

添付ファイル: filephong_shading_1.jpg 2013件 [詳細] filegouraud_shading_1.jpg 1923件 [詳細] filereflection.gif 2274件 [詳細] fileglsl_phong.zip 1723件 [詳細] fileeq_D3.gif 2025件 [詳細] fileeq_Is.gif 1962件 [詳細] fileeq_G.gif 2022件 [詳細] fileeq_alpha.gif 1763件 [詳細] fileeq_F1.gif 1835件 [詳細] fileeq_n.gif 1748件 [詳細] fileeq_Phong.gif 1950件 [詳細] fileeq_H.gif 2152件 [詳細] fileeq_R.gif 1953件 [詳細] fileeq_F2.gif 1950件 [詳細] fileeq_theta.gif 1769件 [詳細] fileeq_Blinn.gif 1983件 [詳細] fileeq_D2.gif 1880件 [詳細] fileeq_BlinnPhong.gif 1954件 [詳細] fileeq_CookTorrance.gif 1825件 [詳細] filect_shading_1.jpg 1932件 [詳細] fileeq_D1.gif 1976件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2022-11-30 (水) 13:48:07