はじめに
今回は、平行光源の光に、光の色を足してみましょう。
あらゆる光源には、光の色があります。現実世界では、完全な白い光というのはほとんど見ることはありません。蛍光灯であれば青っぽい光、電灯であればオレンジっぽい光の色があり、それに照らされたオブジェクトは、その光の影響を受けて、やはり青っぽい色やオレンジっぽい色で見えることになります。
1. 頂点シェーダにコードを追加する
平行光源の光の色を表す変数として、uniform 変数として、diffuse_color
変数を頂点シェーダに追加します。「diffuse」は「拡散光」を表す英単語です。そして out 変数である color
変数の値を計算する時に、頂点の色を表す vertex_color
にこの変数の値を掛け算することで、頂点から拡散される光の色をフィルタリングする効果が得られるのです。
#version 410
layout (location=0) in vec3 vertex_pos;
layout (location=1) in vec3 vertex_normal;
layout (location=2) in vec4 vertex_color;
uniform vec3 light_dir;
uniform mat4 pvm_mat;
uniform mat4 model_mat;
uniform vec4 diffuse_color;
out vec4 color;
void main()
{
gl_Position = vec4(vertex_pos, 1.0) * pvm_mat;
vec3 normal = normalize((vec4(vertex_normal, 0.0) * model_mat).xyz);
float power = dot(normal, -normalize(light_dir));
power = clamp(power, 0.0, 1.0);
color = vertex_color * diffuse_color * power;
}
たとえば (1, 1, 1) の光の色を設定するということは、RGBすべての光の要素をそのままオブジェクトの色に反映させるということです。それに対して、(1.0, 0.5, 0.5) の光の色を設定したとすると、Rの光の要素はそのままオブジェクトの色に反映させますが、GとBの光の要素は半分の強さでオブジェクト表面で拡散するということになります。このフィルタリング効果は、頂点の色に光の色を掛け算することで得られます。
2. 描画コードを追加する
頂点シェーダに追加した diffuse_color
変数の値をセットするためのコードを、Render() 関数に追加します。ここでは、ほんのり黄色いライトを想定して、RGBA の成分が (1.0, 0.9, 0.7, 1.0) の光が平行光源として当たっていることにしてみます。
void Game::Render()
{
...
program->SetUniform("diffuse_color", GLKVector4Make(1.0f, 0.9f, 0.7f, 1.0f));
glDrawElements(GL_TRIANGLES, (GLsizei)data.size(), GL_UNSIGNED_SHORT, (void *)0);
}
それでは、実行してみましょう。比較のために、光の色を足す前の実行結果を見ておきます。次のように、白いウサギがレンダリングされています。
ほんのり黄色いライトを設定したものが、次の実行結果です。ライトの色を受けて、ウサギの色が黄色くレンダリングされるようになったことが分かります。
ここまでのプロジェクト:MyGLGame_step4-3.zip
3. まとめ
今回は、平行光源の光の色を設定できるようにしました。
冒頭でも書きましたが、現実世界では、完全な白・完全な黒というものを目にすることはまずありません。レンダリングしようとしている空間の光源を考えた時に、それが太陽なのか、蛍光灯なのか、電灯なのかということをしっかりと分析し、それを光源の色に反映させてやることがとても重要です。