OpenGLサンプル6 – ライティング

OpenGL

ライティングでフラットシェーディング、グーローシェーディング、フォンシェーディングを行うように修正します。

プログラムはこちらで公開しています。
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;

コメント

タイトルとURLをコピーしました