フォンシェーディング_wgld
ライティングには、
拡散光(ディフューズライト)
環境光(アンビエントライト)
反射光(スペキュラライト)
という三つの代表的なライティング技法があります。
それぞれの特性を活かしたライティングを行うことで、かなりリアリティのある照明効果が得られるはずです。
今回はシェーディングについて
グーローシェーディング
フォンシェーディング
について解説します。
頂点の間で色が補間されるというのは、実際にはどういうことだかわかるでしょうか。
ものすごく単純に言ってしまうと、グーローシェーディングではシェーダなどで計算された最終的な色の情報が、全て頂点に対して適用されます。そして、頂点と頂点の間で色の補間が行なわれたあと、モデルが実際にレンダリングされます。
また、グーローシェーディングでは頂点ごとに色を補間するため、色が変化する境界にジャギーが出ることがあります。これは頂点の数を増やせば増やすほど目立たなくなりますが、そうするとグーローシェーディングの利点である計算の負荷の小ささを活かせなくなるので難しいところです。
ちなみに今までの解説は全てグーローシェーディングだった
フォンシェーディングの実装
ピクセルごとの色の補間処理が必要になるため、
今までは頂点シェーダで行なっていたライティングの計算を、全てフラグメントシェーダに任せます。
具体的には、
頂点シェーダに入ってくる頂点の法線情報を varying 変数としてフラグメントシェーダに渡す
その他のライティング計算の全てをフラグメントシェーダ内へ移します。
頂点シェーダのソース
code:glsl
attribute vec3 position;
attribute vec3 normal;
attribute vec4 color;
uniform mat4 mvpMatrix;
varying vec3 vNormal;
varying vec4 vColor;
void main(void){
vNormal = normal;
vColor = color;
gl_Position = mvpMatrix * vec4(position, 1.0);
}
今までとは違い、新たに vNormal という varying 変数を定義し法線情報をフラグメントシェーダに渡していますね。
頂点の色情報を渡す部分や、座標変換行列を適用する部分などはそのままです。
続いてフラグメントシェーダ。
フラグメントシェーダのソース
code:glsl
precision mediump float;
uniform mat4 invMatrix;
uniform vec3 lightDirection;
uniform vec3 eyeDirection;
uniform vec4 ambientColor;
varying vec3 vNormal;
varying vec4 vColor;
void main(void){
vec3 invLight = normalize(invMatrix * vec4(lightDirection, 0.0)).xyz;
vec3 invEye = normalize(invMatrix * vec4(eyeDirection, 0.0)).xyz;
vec3 halfLE = normalize(invLight + invEye);
float diffuse = clamp(dot(vNormal, invLight), 0.0, 1.0);
float specular = pow(clamp(dot(vNormal, halfLE), 0.0, 1.0), 50.0);
vec4 destColor = vColor * vec4(vec3(diffuse), 1.0) + vec4(vec3(specular), 1.0) + ambientColor;
gl_FragColor = destColor;
}
逆行列やライトベクトル、視線ベクトルなどの
今まで頂点シェーダ内で使っていたデータが全てフラグメントシェーダ内に移植されています。
さらに、先ほど頂点シェーダで定義した varying 変数の vNormal を使って、ライティングの計算を行なっていますね。
計算する手法自体には何も変更はありません。あくまでも、頂点シェーダからフラグメントシェーダへ、処理が移植されただけです。
今回の変更によって、新たに uniform 修飾子付きの変数を追加したりはしていません。
uniformの登録処理は同じ
uniformで登録したものは頂点シェーダ、フラグメントシェーダどちらからも参照できる
どちらの技法を選択するのかは、
レンダリングするモデルの頂点数や、
どのように世界を演出したいのか
によって変わってきます。
また、どの程度の負荷を実行する側に要求するのかによっても変わってくるでしょう。
利用するシーンや、描画されるモデルに応じてうまく使い分けることが重要ですね。
https://gyazo.com/6bc10d419bf424bba6fd56920a59466d