ライティングでフラットシェーディング、グーローシェーディング、フォンシェーディングを行うように修正します。
プログラムはこちらで公開しています。
https://github.com/matsushima-terunao/opengl_sample
シェーダー
バーテックスシェーダー・フラグメントシェーダー共通のライティングです。
/** バーテックス・フラグメントシェーダーのライティングソースプログラム。 */
#version 410 core
#define MODE_COLOR_NONE 1
#define MODE_COLOR_VERTEX 2
#define MODE_COLOR_TEXTURE 4
#define MODE_SHADING_FLAT 8
#define MODE_SHADING_GOUROUD 16
#define MODE_SHADING_PHONG 32
#define MODE_LIGHTING 64
#define MODE_PROJECTION_ORTHO 128
#define MODE_PROJECTION_PERSPECTIVE 256
/**
* uniform block 構造体定義、現在データ。
* @see struct uniform_block
*/
layout(std140) uniform uniform_block {
int mode, pad11, pad12, pad13; // rendering mode
// model view projection matrix
mat4 modelview_matrix;
mat4 modelview_normal_matrix; // transpose(inverse(modelview_matrix))
mat4 modelview_projection_matrix;
// ライティング情報
float Ka; // ambient reflection coefficient
float Kd; // diffuse reflection coefficient
float Ks; // specular reflection coefficient
float shininess;
vec3 ambient_color; float pad21;
vec3 diffuse_color; float pad22;
vec3 specular_color; float pad23;
vec3 light_position;
};
/**
* ライティング。
*/
vec4 lighting(vec3 vertex_normal, vec3 vertex_position) {
// Ip = ka*ia + Σlights(kd(L*N)id + ks(R*V)^a*is)
// ambient
vec3 ambient = Ka * ambient_color;
// diffse
vec3 N = normalize(vertex_normal); // point normal
vec3 L = normalize(light_position - vertex_position); // point to light direction
float lambertian = max(dot(N, L), 0.0);
vec3 diffuse = clamp(Kd * lambertian * diffuse_color, 0.0, 1.0);
// specular
vec3 R = reflect(-L, N); // point to light direction
vec3 V = normalize(-vertex_position); // point to view direction
vec3 specular = clamp(Ks * pow(max(dot(R, V), 0.0), shininess) * specular_color, 0.0, 1.0);
return vec4(ambient + diffuse + specular, 1.0);
}
フラットシェーディング・グーローシェーディングはライティングをバーテックスシェーダーで行います。
/** バーテックスシェーダーのソースプログラム。 */
/*
* 頂点情報の location。
* @see struct Vertex
* @see vertex_shader_src: layout (location = _location) in ...;
* @see create_vertex: glEnableVertexAttribArray(_location);
* @see create_vertex: glVertexAttribPointer(_location, ...);
*/
layout (location = 0) in vec3 position; // x, y, z: 頂点座標
layout (location = 1) in vec3 color; // r, g, b: 頂点カラー
layout (location = 2) in vec2 texture_uv; // u, v: テクスチャーのUVマッピング座標
layout (location = 3) in vec3 normal; // nx, ny, nz: 頂点の法線ベクトル
// バーテックスシェーダーからフラグメントシェーダーへ渡す情報
out vec3 vertex_position; // 頂点座標
out vec3 vertex_normal; // 頂点の法線ベクトル
out vec4 vertex_color; // 頂点カラー
flat out vec4 vertex_color_flat; // フラットシェーディングの頂点カラー
out vec2 vertex_texture_uv; // テクスチャーのUVマッピング座標
void main() {
gl_Position = modelview_projection_matrix * vec4(position, 1.0); // 頂点座標
vertex_position = vec3(modelview_matrix * vec4(position, 1.0)); // 頂点座標
vertex_normal = vec3(modelview_normal_matrix * vec4(normal, 0.0)); // 頂点の法線ベクトル
vertex_color = vec4(1.0, 1.0, 1.0, 1.0); // 頂点カラー
// 頂点カラーを使用
if ((mode & MODE_COLOR_VERTEX) == MODE_COLOR_VERTEX) {
vertex_color = vec4(color, 1.0);
}
// フラットシェーディング・グーローシェーディングはライティングをバーテックスシェーダーで行う
if ((mode & MODE_LIGHTING) == MODE_LIGHTING
&& (mode & MODE_SHADING_PHONG) != MODE_SHADING_PHONG) {
vertex_color = lighting(vertex_normal, vertex_position) * vertex_color;
}
// フラットシェーディングの頂点カラー
vertex_color_flat = vertex_color;
// テクスチャーのUVマッピング座標
vertex_texture_uv = texture_uv;
}
フォンシェーディングはライティングをフラグメントシェーダーで行います。
/** フラグメントシェーダーのソースプログラム。 */
uniform sampler2D fragment_texture; // テクスチャー @see glBindTexture(GL_TEXTURE_2D, ...);
// バーテックスシェーダーからフラグメントシェーダーへ渡す情報
in vec3 vertex_position; // 頂点座標
in vec3 vertex_normal; // 頂点の法線ベクトル
in vec4 vertex_color; // 頂点カラー
flat in vec4 vertex_color_flat; // フラットシェーディングの頂点カラー
in vec2 vertex_texture_uv; // テクスチャーのUVマッピング座標
// 出力データ
out vec4 fragment_color; // 出力ピクセルカラー
void main() {
// 頂点カラー
fragment_color = vertex_color;
// フラットシェーディングの頂点カラー
if ((mode & MODE_SHADING_FLAT) == MODE_SHADING_FLAT) {
fragment_color = vertex_color_flat;
}
// テクスチャーのカラー
if ((mode & MODE_COLOR_TEXTURE) == MODE_COLOR_TEXTURE) {
fragment_color = texture(fragment_texture, vertex_texture_uv) * fragment_color;
}
// フォンシェーディングはライティングをフラグメントシェーダーで行う
if ((mode & MODE_LIGHTING) == MODE_LIGHTING
&& (mode & MODE_SHADING_PHONG) == MODE_SHADING_PHONG) {
fragment_color = lighting(vertex_normal, vertex_position) * fragment_color;
}
}
フラットシェーディング
フラットシェーディングを使用するには、初期化時に以下を実行します。
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); // フラットシェーディング
フラットシェーディングのライティングは頂点に対して行うので、バーテックスシェーダーで行います。また、バーテックスシェーダーからフラグメントシェーダーに渡す頂点カラー変数に flat を付けます。
/** バーテックスシェーダーのソースプログラム。 */
// バーテックスシェーダーからフラグメントシェーダーへ渡す情報
flat out vec4 vertex_color_flat; // フラットシェーディングの頂点カラー
void main() {
// フラットシェーディング・グーローシェーディングはライティングをバーテックスシェーダーで行う
vertex_color = lighting(vertex_normal, vertex_position) * vertex_color;
// フラットシェーディングの頂点カラー
vertex_color_flat = vertex_color;
...
/** フラグメントシェーダーのソースプログラム。 */
// バーテックスシェーダーからフラグメントシェーダーへ渡す情報
flat in vec4 vertex_color_flat; // フラットシェーディングの頂点カラー
// 出力データ
out vec4 fragment_color; // 出力ピクセルカラー
void main() {
// 頂点カラー
fragment_color = vertex_color_flat;
...
グーローシェーディング
グーローシェーディングのライティングは頂点に対して行うので、バーテックスシェーダーで行います。
/** バーテックスシェーダーのソースプログラム。 */
// バーテックスシェーダーからフラグメントシェーダーへ渡す情報
out vec4 vertex_color; // 頂点カラー
void main() {
// フラットシェーディング・グーローシェーディングはライティングをバーテックスシェーダーで行う
vertex_color = lighting(vertex_normal, vertex_position) * vertex_color;
...
/** フラグメントシェーダーのソースプログラム。 */
// 出力データ
out vec4 fragment_color; // 出力ピクセルカラー
void main() {
// 頂点カラー
fragment_color = vertex_color;
...
フォンシェーディング
フォンシェーディングのライティングはピクセルに対して行うので、フラグメントシェーダーで行います。
/** バーテックスシェーダーのソースプログラム。 */
// バーテックスシェーダーからフラグメントシェーダーへ渡す情報
out vec4 vertex_color; // 頂点カラー
void main() {
vertex_color = vec4(1.0, 1.0, 1.0, 1.0); // 頂点カラー
...
/** フラグメントシェーダーのソースプログラム。 */
// バーテックスシェーダーからフラグメントシェーダーへ渡す情報
in vec4 vertex_color; // 頂点カラー
// 出力データ
out vec4 fragment_color; // 出力ピクセルカラー
void main() {
// 頂点カラー
fragment_color = vertex_color;
// フォンシェーディングはライティングをフラグメントシェーダーで行う
fragment_color = lighting(vertex_normal, vertex_position) * fragment_color;
コメント