4. 三角形へのレンダリングとライティング パート1

此のチュートリアルシリーズを2025年7月22日午前2時から午前7時の間に始めた方へお知らせです。HomebrewがmacOSにデフォルトでインストールされていない事に気づき、インストールが非常に難しい場合がある為、libディレクトリにglfw.dylibを追加し、Xcodeプロジェクト設定を/usr/local/libのグローバルディレクトリではなくローカルディレクトリにリンクする様に変更しました。其の為、Macユーザー向けのGLFWインストール手順をGLSL 概要ページから削除しました。

Unixユーザーの場合、build_unix.shファイルに-lmフラグをリンカーに追加し、数学関数が動作する様に更新しました。

其の他の方には、includeディレクトリにvector.hファイルを追加しました。此れにより、色値を9つの異なるfloatで定義する代わりに、3つのVector3を作成出来る様になり、見た目がずっと良くなりました。其の為、グラデーションページも其れに合わせて調整しました。最後に、ページの最後で完全なソースコードを表示する代わりに、.diffファイルを共有し、その直下にプレビューを表示する様にしました。これにより、スクロール量が大幅に削減されます。

ZIP及びTARファイルも更新しました。こちらで入手出来ます。


4.1 三角形へのレンダリング

現在、シェーダーを画面全体にレンダリングしています。此れは見た目は良いですが、画面上に他に何をレンダリング出来るかという点で非常に制限があります。先ず其の問題を解決し、シェーダーを三角形にレンダリングしてみましょう。

  // 頂点データ(フルスクリーンクアッド)を設定
  float vertices[] = {
    -0.5f, -0.5f, 0.0f, 0.0f, // 左下(位置、UV)
     0.5f, -0.5f, 1.0f, 0.0f, // 右下
     0.0f,  0.5f, 0.5f, 1.0f
  };
  GLuint indices[] = { 0, 1, 2 };
  ...
      glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);

結果:

シェーダー1

4.2 ライティングの説明

次に、ライティングについて説明します。重要でない様に思えるかもしんが、複雑なモデルを使用する場合、ライティングは非常に重要な概念です。一般的な光の種類は6つあり、此の章では其の内の最初の2つを、簡単なものから難しい物の順に説明します。

アンビエントライト

アンビエントライトは理解と実装が最も簡単です。方向性を持たない均一な光で、方向や距離などの複雑な計算は必要ありません。簡単に言えば、「アンビエントライト」は「背景光」とも呼ばれます。

ディレクショナルライト

ディレクショナルライトは、光の方向と表面の法線という、3Dライティングの基本的な概念を導入します。此れも比較的簡単です。太陽光に例える事が出来ます。

ポイントライト

ポイントライトは、ディレクショナルライトに位置と減衰を追加し、距離による光の減衰の概念を導入します。電球に例える事が出来ます。

光の方向の計算:(光の位置 - フラグメントの位置)

減衰を適用するには:1 / (定数 + 線形 * d + 二次体 * d²)

スポットライト

スポットライトは、ポイントライトに方向性と円錐角度を追加した物です。懐中電灯に例える事が出来ます。

ヘミスフィアライト

ヘミスフィアライトは、アンビエントライトの特殊な形態で、方向性(空と地面)の変化を追加します。エリアライトよりは複雑ではありませんが、環境に基づくライティングの概念を導入します。屋外のライティングをシミュレートする為に使用出来ます。

エリアライト

エリアライトは最も複雑で、表面全体の積分や近似(複数のポイントライトなど)が必要です。エリアライトは、窓やパネルの様な現実世界の表面をシミュレートします。

4.3 アンビエントライト

シェーダーディレクトリに新しいファイルfrag_ambient.glslを作成します。

#version 450 core

in vec2 uVu;
out vec4 out_color;

uniform vec3 materialColor;
uniform float ambientIntensity;

void main() {
  vec3 ambient = materialColor * ambientIntensity;
  out_color = vec4(ambient, 1.0);
}

簡単そうですね?Cコードではもっと多くの作業が必要です。

  // シェーダーファイルを読み込む
#ifdef __APPLE__
  char *vertexShaderSource = readShaderFile("shader/vertex.mac.glsl");
  char *fragmentShaderSource = readShaderFile("shader/fragment.mac.glsl");
  char *fragmentAmbientSource = readShaderFile("shader/frag_ambient.mac.glsl");
#else
  char *vertexShaderSource = readShaderFile("shader/vertex.glsl");
  char *fragmentShaderSource = readShaderFile("shader/fragment.glsl");
  char *fragmentAmbientSource = readShaderFile("shader/frag_ambient.glsl");
#endif
  if (!vertexShaderSource || !fragmentShaderSource || !fragmentAmbientSource) {
    puts("シェーダーファイルの読み込みに失敗しました");
    if (vertexShaderSource) free(vertexShaderSource);
    if (fragmentShaderSource) free(fragmentShaderSource);
    if (fragmentAmbientSource) free(fragmentAmbientSource);
    glfwDestroyWindow(window);
    glfwTerminate();
    return -1;
  }

  // シェーダーをコンパイル
  GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vertexShader, 1, (const char **)&vertexShaderSource, NULL);
  glCompileShader(vertexShader);
  checkShaderCompile(vertexShader);

  GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragmentShader, 1, (const char **)&fragmentShaderSource, NULL);
  glCompileShader(fragmentShader);
  checkShaderCompile(fragmentShader);

  GLuint fragmentAmbientShader = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragmentAmbientShader, 1, (const char **)&fragmentAmbientSource, NULL);
  glCompileShader(fragmentAmbientShader);
  checkShaderCompile(fragmentAmbientShader);

  // 三角形のシェーダープログラムをリンク
  GLuint shaderProgram = glCreateProgram();
  glAttachShader(shaderProgram, vertexShader);
  glAttachShader(shaderProgram, fragmentShader);
  glLinkProgram(shaderProgram);
  checkProgramLink(shaderProgram);

  // アンビエントシェーダープログラムをリンク
  GLuint ambientShaderProgram = glCreateProgram();
  glAttachShader(ambientShaderProgram, vertexShader);
  glAttachShader(ambientShaderProgram, fragmentAmbientShader);
  glLinkProgram(ambientShaderProgram);
  checkProgramLink(ambientShaderProgram);

  glDeleteShader(vertexShader);
  glDeleteShader(fragmentShader);
  glDeleteShader(fragmentAmbientShader);
  free(vertexShaderSource);
  free(fragmentShaderSource);
  free(fragmentAmbientSource);

  // 頂点データ(三角形)を設定:三角形用(左にオフセット)
  float vertices[] = {
    -0.8f, -0.5f, 0.0f, 0.0f, // 左下(位置、UV)
    -0.3f, -0.5f, 1.0f, 0.0f, // 右下
    -0.55f, 0.5f, 0.5f, 1.0f  // 上
  };
  GLuint indices[] = { 0, 1, 2 };

  // 頂点データ(三角形)を設定:アンビエント用(右にオフセット)
  float verticesAmbient[] = {
     0.3f, -0.5f, 0.0f, 0.0f, // 左下(位置、UV)
     0.8f, -0.5f, 1.0f, 0.0f, // 右下
     0.55f, 0.5f, 0.5f, 1.0f  // 上
  };

  // VAO、VBO、EBOを三角形用に設定
  GLuint VAO, VBO, EBO;
  glGenVertexArrays(1, &VAO);
  glGenBuffers(1, &VBO);
  glGenBuffers(1, &EBO);

  glBindVertexArray(VAO);
  glBindBuffer(GL_ARRAY_BUFFER, VBO);
  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

  // 頂点属性:位置(location 0)、UV(location 1)
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
  glEnableVertexAttribArray(0);
  size_t offset = 2 * sizeof(float);
  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)offset);
  glEnableVertexAttribArray(1);

  // VAO、VBO、EBOをアンビエント用に設定
  GLuint VAOAmbient, VBOAmbient, EBOAmbient;
  glGenVertexArrays(1, &VAOAmbient);
  glGenBuffers(1, &VBOAmbient);
  glGenBuffers(1, &EBOAmbient);

  glBindVertexArray(VAOAmbient);
  glBindBuffer(GL_ARRAY_BUFFER, VBOAmbient);
  glBufferData(GL_ARRAY_BUFFER, sizeof(verticesAmbient), verticesAmbient, GL_STATIC_DRAW);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOAmbient);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)offset);
  glEnableVertexAttribArray(1);

  // メインレンダリングループ
  while (!glfwWindowShouldClose(window)) {
    // 画面をクリア
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // シェーダープログラムを使用
    glUseProgram(shaderProgram);

    // 時間に基づいて色をアニメーション
    float time = (float)glfwGetTime();
    float speed = 1.0f; // アニメーションの速度
    float phase = 2.0f * 3.14159f / 3.0f; // // 120度の位相差(3色用)

    // uColorA: 赤 -> 緑 -> 青
    Vector3 colorA;
    colorA.r = sin(time * speed + 0.0f) * 0.5f + 0.5f; // 0.0 to 1.0
    colorA.g = sin(time * speed + phase) * 0.5f + 0.5f;
    colorA.b = sin(time * speed + 2.0f * phase) * 0.5f + 0.5f;

    // uColorB: 緑 -> 青 -> 赤
    Vector3 colorB;
    colorB.r = sin(time * speed + 2.0f * phase) * 0.5f + 0.5f;
    colorB.g = sin(time * speed + 0.0f) * 0.5f + 0.5f;
    colorB.b = sin(time * speed + phase) * 0.5f + 0.5f;

    // uColorC: 青 -> 赤 -> 緑
    Vector3 colorC;
    colorC.r = sin(time * speed + phase) * 0.5f + 0.5f;
    colorC.g = sin(time * speed + 2.0f * phase) * 0.5f + 0.5f;
    colorC.b = sin(time * speed + 0.0f) * 0.5f + 0.5f;

    // ユニフォームを設定
    glUniform3f(glGetUniformLocation(shaderProgram, "uColorA"), colorA.r, colorA.g, colorA.b); // 赤
    glUniform3f(glGetUniformLocation(shaderProgram, "uColorB"), colorB.r, colorB.g, colorB.b); // 緑
    glUniform3f(glGetUniformLocation(shaderProgram, "uColorC"), colorC.r, colorC.g, colorC.b); // 青

    // クアッドを描画
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);

    // アンビエントシェーダープログラムを使用(右の三角形)
    glUseProgram(ambientShaderProgram);

    // ユニフォームを設定(アンビエントシェーダー)
    Vector3 materialColor = { 0.8f, 0.2f, 0.3f }; // 赤みがかった色
    float ambientIntensity = 0.6f; // アンビエント光の強さ(0.0~1.0)

    glUniform3f(glGetUniformLocation(ambientShaderProgram, "materialColor"), materialColor.r, materialColor.g, materialColor.b);
    glUniform1f(glGetUniformLocation(ambientShaderProgram, "ambientIntensity"), ambientIntensity);

    // 右の三角形を描画(アンビエントシェーダー)
    glBindVertexArray(VAOAmbient);
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);

    // バッファをスワップし、イベントを処理
    glfwSwapBuffers(window);
    glfwPollEvents();
  }

  // クリーンアップ
  glDeleteVertexArrays(1, &VAO);
  glDeleteBuffers(1, &VBO);
  glDeleteBuffers(1, &EBO);
  glDeleteVertexArrays(1, &VAOAmbient);
  glDeleteBuffers(1, &VBOAmbient);
  glDeleteBuffers(1, &EBOAmbient);
  glDeleteProgram(shaderProgram);
  glDeleteProgram(ambientShaderProgram);
  glfwDestroyWindow(window);
  glfwTerminate();

結果は次の様になります:

シェーダー2

4.4 ディレクショナルライト

此のチュートリアルではディレクショナルライトは似た様に見えるかもしんが、実際の複雑な環境では全く異なる物です。同じ様に見える理由は、影を落とす3Dオブジェクトがない為です。

新しいファイルvertex_directional.glslを作成し、以下を挿入します:

#version 450 core

layout(location = 0) in vec2 aPosition;
layout(location = 1) in vec2 aUv;
layout(location = 2) in vec3 aNormal;

out vec2 vUv;
out vec3 vNormal;

void main() {
  vUv = aUv;
  vNormal = aNormal;
  gl_Position = vec4(aPosition, 0.0, 1.0);
}

layout(location = 2) in vec3 aNormal; は、頂点の法線のための3Dベクトル入力を定義し、属性2に割り当てます。法線は頂点が「向いている」方向を示し、光が各頂点にどの様に当たるかを決定します。vNormal = aNormal; で此の値を変更せずにフラグメントシェーダーに渡します。

新しいファイルfrag_directional.glslを作成し、以下を挿入します:

#version 450 core

in vec2 vUv;
out vec4 out_color;

uniform vec3 materialColor;
uniform vec3 lightDirection;
uniform float lightIntensity;

void main() {
  vec3 normal = vec3(0.0, 0.0, 1.0);

  float diffuseFactor = max(dot(normal, -normalize(lightDirection)), 0.0);
  vec3 diffuse = materialColor * diffuseFactor * lightIntensity;
  out_color = vec4(diffuse, 1.0);
}

in vec3 vNormal;は、頂点シェーダーから受け取った法線ベクトルを追加します。uniform vec3 materialColor;は、三角形の基本色(RGB)を保持します。此れはuniformであり、Cプログラムから設定され、全てのピクセルで同じままです。uniform vec3 lightDirection;は、光が来る方向の座標(XYZ)を保持します。此れは、太陽の様に直線的な光の方向をシェーダーに伝えます。uniform float lightIntensity;は、光の明るさを保持し、0.0が最も暗く(光なし)、1.0が最も明るいです。

vec3 normal = normalize(vNormal);は、補間された法線(vNormal)を取り、長さを1にスケールします(normalize)。此れにより、正確なライティング計算が保証されます。normalize(lightDirection)は、lightDirectionベクトルを長さ1にスケールし、一貫した計算を保証します。-normalize(lightDirection)は、光の方向を反転させ、表面に向かって光が来る様にします。dot(normal, -normalize(lightDirections))は、法線と反転した光の方向の間の角度のコサインを計算します。max(..., 0.0)は、結果が負にならない様にし(負の値は表面の裏から来る光を意味し、それを無視します)。

main.cで:

  // 頂点データ(三角形)を設定:ディレクショナル用(右にオフセット)
  float verticesDirectional[] = {
     0.3f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, 0.707f, // 左下(位置、UV、形動ノーマル)
     0.8f, -0.5f, 1.0f, 0.0f,  0.5f, -0.5f, 0.707f, // 右下
     0.55f, 0.5f, 0.5f, 1.0f,  0.0f,  0.5f, 0.707f  // 上
  };
  ...
    // VAO、VBO、EBOをディレクショナル用に設定
  GLuint VAODirectional, VBODirectional, EBODirectional;
  glGenVertexArrays(1, &VAODirectional);
  glGenBuffers(1, &VBODirectional);
  glGenBuffers(1, &EBODirectional);

  glBindVertexArray(VAODirectional);
  glBindBuffer(GL_ARRAY_BUFFER, VBODirectional);
  glBufferData(GL_ARRAY_BUFFER, sizeof(verticesDirectional), verticesDirectional, GL_STATIC_DRAW);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBODirectional);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void *)0);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void *)(2 * sizeof(float)));
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void *)(4 * sizeof(float)));
  glEnableVertexAttribArray(2);
  ...
    // ディレクショナルシェーダープログラムを使用(右の三角形)
    glUseProgram(directionalShaderProgram);

    // ユニフォームを設定(アンビエントシェーダー)
    Vector3 materialColor = { 0.8f, 0.2f, 0.3f }; // 赤みがかった色
    Vector3 lightDirection = { 0.0f, 0.0f, -1.0f }; // ライトの方向(正規化不要、シェーダーで処理)
    float lightIntensity = 1.0f; // ライトの強さ(0.0~1.0)

    glUniform3f(glGetUniformLocation(directionalShaderProgram, "materialColor"), materialColor.r, materialColor.g, materialColor.b);
    glUniform3f(glGetUniformLocation(directionalShaderProgram, "lightDirection"), lightDirection.x, lightDirection.y, lightDirection.z);
    glUniform1f(glGetUniformLocation(directionalShaderProgram, "lightIntensity"), lightIntensity);

シェーダー3

最終的な変更: DIFFをダウンロード

ファイル: a/main-ambient.c

151 // シェーダーファイルを読み込む 151 // シェーダーファイルを読み込む
152 #ifdef __APPLE__ 152 #ifdef __APPLE__
153 char *vertexShaderSource = readShaderFile("shader/vertex.mac.glsl"); 153 char *vertexShaderSource = readShaderFile("shader/vertex.mac.glsl");
154 char *fragmentShaderSource = readShaderFile("shader/fragment.mac.glsl"); 154 char *fragmentShaderSource = readShaderFile("shader/fragment.mac.glsl");
155   155 char *fragmentAmbientSource = readShaderFile("shader/frag_ambient.mac.glsl");
156 #else 156 #else
157 char *vertexShaderSource = readShaderFile("shader/vertex.glsl"); 157 char *vertexShaderSource = readShaderFile("shader/vertex.glsl");
158 char *fragmentShaderSource = readShaderFile("shader/fragment.glsl"); 158 char *fragmentShaderSource = readShaderFile("shader/fragment.glsl");
159   159 char *fragmentAmbientSource = readShaderFile("shader/frag_ambient.glsl");
160 #endif 160 #endif
161 if (!vertexShaderSource || !fragmentShaderSource) { 161 if (!vertexShaderSource || !vertexDirectionalSource || !fragmentShaderSource || !fragmentAmbientSource) {
162 puts("シェーダーファイルの読み込みに失敗しました"); 162 puts("シェーダーファイルの読み込みに失敗しました");
163 if (vertexShaderSource) free(vertexShaderSource); 163 if (vertexShaderSource) free(vertexShaderSource);
164 if (fragmentShaderSource) free(fragmentShaderSource); 164 if (fragmentShaderSource) free(fragmentShaderSource);
165   165 if (fragmentAmbientSource) free(fragmentAmbientSource);
166 glfwDestroyWindow(window); 166 glfwDestroyWindow(window);
167 glfwTerminate(); 167 glfwTerminate();
168 return -1; 168 return -1;
171   181 glCompileShader(vertexShader);
172   182 checkShaderCompile(vertexShader);
173   183  
174   184 GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
175   185 glShaderSource(fragmentShader, 1, (const char **)&fragmentShaderSource, NULL);
176   186 glCompileShader(fragmentShader);
177   187 checkShaderCompile(fragmentShader);
178   188  
179   189 GLuint fragmentAmbientShader = glCreateShader(GL_FRAGMENT_SHADER);
180   190 glShaderSource(fragmentAmbientShader, 1, (const char **)&fragmentAmbientSource, NULL);
181 glCompileShader(vertexShader); 191 glCompileShader(fragmentAmbientShader);
182 checkShaderCompile(vertexShader); 192 checkShaderCompile(fragmentAmbientShader);
183   193  
184 GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 194 // 三角形のシェーダープログラムをリンク
185 glShaderSource(fragmentShader, 1, (const char **)&fragmentShaderSource, NULL); 195 GLuint shaderProgram = glCreateProgram();
186 glCompileShader(fragmentShader); 196 glAttachShader(shaderProgram, vertexShader);
187 checkShaderCompile(fragmentShader); 197 glAttachShader(shaderProgram, fragmentShader);
188   198 glLinkProgram(shaderProgram);
189 // シェーダープログラムをリンク 199 checkProgramLink(shaderProgram);
190   200  
191   201 // アンビエントシェーダープログラムをリンク
192   202 GLuint ambientShaderProgram = glCreateProgram();
193   203 glAttachShader(ambientShaderProgram, vertexShader);
194   204 glAttachShader(ambientShaderProgram, fragmentAmbientShader);
195 GLuint shaderProgram = glCreateProgram(); 205 glLinkProgram(ambientShaderProgram);
196 glAttachShader(shaderProgram, vertexShader); 206 checkProgramLink(ambientShaderProgram);
197 glAttachShader(shaderProgram, fragmentShader); 207  
198 glLinkProgram(shaderProgram); 208 glDeleteShader(vertexShader);
199 checkProgramLink(shaderProgram); 209 glDeleteShader(fragmentShader);
200   210 glDeleteShader(fragmentAmbientShader);
201   211 free(vertexShaderSource);
202   212 free(vertexDirectionalSource);
203   213 free(fragmentShaderSource);
204   214 free(fragmentAmbientSource);
205   215  
206   216 // 頂点データ(三角形)を設定:三角形用(左にオフセット)
207   217 float vertices[] = {
208 glDeleteShader(vertexShader); 218 -0.8f, -0.5f, 0.0f, 0.0f, // 左下(位置、UV)
209 glDeleteShader(fragmentShader); 219 -0.3f, -0.5f, 1.0f, 0.0f, // 右下
210   220 -0.55f, 0.5f, 0.5f, 1.0f // 上
211 free(vertexShaderSource); 221 };
212   222 GLuint indices[] = { 0, 1, 2 };
213 free(fragmentShaderSource); 223  
214   224 // 頂点データ(三角形)を設定:アンビエント用(右にオフセット)
215   225 float verticesAmbient[] = {
216 // 頂点データ(フルスクリーンクアッド)を設定 226 0.3f, -0.5f, 0.0f, 0.0f, // 左下(位置、UV)
217 float vertices[] = { 227 0.8f, -0.5f, 1.0f, 0.0f, // 右下
218 -1.0f, -1.0f, 0.0f, 0.0f, // 左下(位置、UV) 228 0.55f, 0.5f, 0.5f, 1.0f // 上
219 1.0f, -1.0f, 1.0f, 0.0f, // 右下 229 };
220 1.0f, 1.0f, 1.0f, 1.0f, // 右上 230  
221 -1.0f, 1.0f, 0.0f, 1.0f // 左上 231 // VAO、VBO、EBOを三角形用に設定
222 GLuint indices[] = { 0, 1, 2, 2, 3, 0 }; 232 GLuint VAO, VBO, EBO;
223   233 glGenVertexArrays(1, &VAO);
224   234 glGenBuffers(1, &VBO);
225   267 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
226   268 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
227   269  
228   270  
229   271 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
230   272 glEnableVertexAttribArray(0);
231   273 size_t offset = 2 * sizeof(float);
232 GLuint VAO, VBO, EBO; 274 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)offset);
233 glGenVertexArrays(1, &VAO); 275 glEnableVertexAttribArray(1);
234 glGenBuffers(1, &VBO); 276  
208   277 // VAO、VBO、EBOをアンビエント用に設定
209   278 GLuint VAOAmbient, VBOAmbient, EBOAmbient;
210   279 glGenVertexArrays(1, &VAOAmbient);
211   280 glGenBuffers(1, &VBOAmbient);
212   281 glGenBuffers(1, &EBOAmbient);
213   282  
214   283 glBindVertexArray(VAOAmbient);
215   284 glBindBuffer(GL_ARRAY_BUFFER, VBOAmbient);
216   285 glBufferData(GL_ARRAY_BUFFER, sizeof(verticesAmbient), verticesAmbient, GL_STATIC_DRAW);
217   286 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOAmbient);
218   287 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
219   288  
220   289 // メインレンダリングループ
221   290 while (!glfwWindowShouldClose(window)) {
222   291 // 画面をクリア
223   344  
224   345 // クアッドを描画
225   346 glBindVertexArray(VAO);
226   347 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
227   348  
228   349 // アンビエントシェーダープログラムを使用(右の三角形)
229   350 glUseProgram(ambientShaderProgram);
230   351  
231   352 // ユニフォームを設定(アンビエントシェーダー)
232   353 Vector3 materialColor = { 0.8f, 0.2f, 0.3f }; // 赤みがかった色
233   354 Vector3 lightDirection = { -0.5f, -0.5f, -0.707f }; // ライトの方向(正規化不要、シェーダーで処理)
234   355 float ambientIntensity = 0.6f; // アンビエント光の強さ(0.0~1.0)
235   356  
236   357 glUniform3f(glGetUniformLocation(directionalShaderProgram, "materialColor"), materialColor.r, materialColor.g, materialColor.b);
237   358 glUniform3f(glGetUniformLocation(directionalShaderProgram, "lightDirection"), lightDirection.x, lightDirection.y, lightDirection.z);
238   359 glUniform1f(glGetUniformLocation(ambientShaderProgram, "ambientIntensity"), ambientIntensity);
239   360  
240   361 // 右の三角形を描画(アンビエントシェーダー)
241   362 glBindVertexArray(VAOAmbient);
242   363 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
243   364  
244   365 // バッファをスワップし、イベントを処理
245   366 glfwSwapBuffers(window);
246   377 glDeleteVertexArrays(1, &VAO);
247   378 glDeleteBuffers(1, &VBO);
248   379 glDeleteBuffers(1, &EBO);
249   380 glDeleteVertexArrays(1, &VAOAmbient);
250   381 glDeleteBuffers(1, &VBOAmbient);
251   382 glDeleteBuffers(1, &EBOAmbient);
252   383 glDeleteProgram(shaderProgram);
253   384 glDeleteProgram(ambientShaderProgram);
254   385 glfwDestroyWindow(window);
255   386 glfwTerminate();
256   387  
257   388 return 0;
258   389 }
259      
260      
261      
262      
263      
264      
265      
266      
267 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);    
268 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);    
269      
270 頂点属性:位置(location 0)、UV(location 1)    
271 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);    
272 glEnableVertexAttribArray(0);    
273 size_t offset = 2 * sizeof(float);    
274 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)offset);    
275 glEnableVertexAttribArray(1);    
276      
277      
278      
279      
280      
281      
282      
283      
284      
285      
286      
287      
288      
289 // メインレンダリングループ    
290 while (!glfwWindowShouldClose(window)) {    
291 // 画面をクリア    
254      
255      
256      
257      
258      
259      
260      
261      
262      
263      
264      
265      
266      
267      
268      
269      
270      
271      
272      
273      
274      
275      
276      
277      
278      
279      
280      
281      
282      
283      
284      
285      
286      
287      
288      
289      
290      
291      
292      
293      
294      
295      
296      
297      
298      
299      
300      
301      
302      
303      
304      
305      
306      
307      
308      
309      
310      
311      
312      
313      
314      
315      
316      
317      
318      
319      
320      
321      
322      
323      
324      
325      
326      
327      
328      
329      
330      
331      
332      
333      
334      
335      
336      
337      
338      
339      
340      
341      
342      
343      
344      
345 // クアッドを描画    
346 glBindVertexArray(VAO);    
347 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);    
348      
349      
350      
351      
352      
353      
354      
355      
356      
357      
358      
359      
360      
361      
362      
363      
364      
365 // バッファをスワップし、イベントを処理    
366 glfwSwapBuffers(window);    
265      
266      
267      
268      
269      
270      
271      
272      
273      
274      
275      
276      
277      
278      
279      
280      
281      
282      
283      
284      
285      
286      
287      
288      
289      
290      
291      
292      
293      
294      
295      
296      
297      
298      
299      
300      
301      
302      
303      
304      
305      
306      
307      
308      
309      
310      
311      
312      
313      
314      
315      
316      
317      
318      
319      
320      
321      
322      
323      
324      
325      
326      
327      
328      
329      
330      
331      
332      
333      
334      
335      
336      
337      
338      
339      
340      
341      
342      
343      
344      
345      
346      
347      
348      
349      
350      
351      
352      
353      
354      
355      
356      
357      
358      
359      
360      
361      
362      
363      
364      
365      
366      
367      
368      
369      
370      
371      
372      
373      
374      
375      
376      
377 glDeleteVertexArrays(1, &VAO);    
378 glDeleteBuffers(1, &VBO);    
379 glDeleteBuffers(1, &EBO);    
380      
381      
382      
383 glDeleteProgram(shaderProgram);    
384      
385 glfwDestroyWindow(window);    
386 glfwTerminate();    
387      
388 return 0;    
389 }    

ファイル: a/main-directional.c

151 // シェーダーファイルを読み込む 151 // シェーダーファイルを読み込む
152 #ifdef __APPLE__ 152 #ifdef __APPLE__
153 char *vertexShaderSource = readShaderFile("shader/vertex.mac.glsl"); 153 char *vertexShaderSource = readShaderFile("shader/vertex.mac.glsl");
154   154 char *vertexDirectionalSource = readShaderFile("shader/vertex_directional.mac.glsl");
155 char *fragmentShaderSource = readShaderFile("shader/fragment.mac.glsl"); 155 char *fragmentShaderSource = readShaderFile("shader/fragment.mac.glsl");
156   156 char *fragmentDirectionalSource = readShaderFile("shader/frag_directional.mac.glsl");
157 #else 157 #else
158 char *vertexShaderSource = readShaderFile("shader/vertex.glsl"); 158 char *vertexShaderSource = readShaderFile("shader/vertex.glsl");
159   159 char *vertexDirectionalSource = readShaderFile("shader/vertex_directional.glsl");
160 char *fragmentShaderSource = readShaderFile("shader/fragment.glsl"); 160 char *fragmentShaderSource = readShaderFile("shader/fragment.glsl");
161   161 char *fragmentDirectionalSource = readShaderFile("shader/frag_directional.glsl");
162 #endif 162 #endif
163 if (!vertexShaderSource || !fragmentShaderSource) { 163 if (!vertexShaderSource || !vertexDirectionalSource || !fragmentShaderSource || !fragmentDirectionalSource) {
164 puts("シェーダーファイルの読み込みに失敗しました"); 164 puts("シェーダーファイルの読み込みに失敗しました");
165 if (vertexShaderSource) free(vertexShaderSource); 165 if (vertexShaderSource) free(vertexShaderSource);
166   166 if (vertexDirectionalSource) free(vertexDirectionalSource);
167 if (fragmentShaderSource) free(fragmentShaderSource); 167 if (fragmentShaderSource) free(fragmentShaderSource);
168   168 if (fragmentDirectionalSource) free(fragmentDirectionalSource);
169 glfwDestroyWindow(window); 169 glfwDestroyWindow(window);
170 glfwTerminate(); 170 glfwTerminate();
171 return -1; 171 return -1;
171   181 glCompileShader(vertexShader);
172   182 checkShaderCompile(vertexShader);
173   183  
174   184 GLuint vertexDirectionalShader = glCreateShader(GL_VERTEX_SHADER);
175   185 glShaderSource(vertexDirectionalShader, 1, (const char **)&vertexDirectionalSource, NULL);
176   186 glCompileShader(vertexDirectionalShader);
177   187 checkShaderCompile(vertexDirectionalShader);
178   188  
179   189 GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
180   190 glShaderSource(fragmentShader, 1, (const char **)&fragmentShaderSource, NULL);
181 glCompileShader(vertexShader); 191 glCompileShader(fragmentShader);
182 checkShaderCompile(vertexShader); 192 checkShaderCompile(fragmentShader);
183   193  
184   194 GLuint fragmentDirectionalShader = glCreateShader(GL_FRAGMENT_SHADER);
185   195 glShaderSource(fragmentDirectionalShader, 1, (const char **)&fragmentDirectionalSource, NULL);
186   196 glCompileShader(fragmentDirectionalShader);
187   197 checkShaderCompile(fragmentDirectionalShader);
188   198  
189 GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 199 // 三角形のシェーダープログラムをリンク
190 glShaderSource(fragmentShader, 1, (const char **)&fragmentShaderSource, NULL); 200 GLuint shaderProgram = glCreateProgram();
191 glCompileShader(fragmentShader); 201 glAttachShader(shaderProgram, vertexShader);
192 checkShaderCompile(fragmentShader); 202 glAttachShader(shaderProgram, fragmentShader);
193   203 glLinkProgram(shaderProgram);
194   204 checkProgramLink(shaderProgram);
195   205  
196   206 // ディレクショナルシェーダープログラムをリンク
197   207 GLuint directionalShaderProgram = glCreateProgram();
198   208 glAttachShader(directionalShaderProgram, vertexDirectionalShader);
199   209 glAttachShader(directionalShaderProgram, fragmentDirectionalShader);
200 GLuint shaderProgram = glCreateProgram(); 210 glLinkProgram(directionalShaderProgram);
201 glAttachShader(shaderProgram, vertexShader); 211 checkProgramLink(directionalShaderProgram);
202 glAttachShader(shaderProgram, fragmentShader); 212  
203 glLinkProgram(shaderProgram); 213 glDeleteShader(vertexShader);
204 checkProgramLink(shaderProgram); 214 glDeleteShader(vertexDirectionalShader);
205   215 glDeleteShader(fragmentShader);
206   216 glDeleteShader(fragmentDirectionalShader);
207   217 free(vertexShaderSource);
208   218 free(vertexDirectionalSource);
209   219 free(fragmentShaderSource);
210   220 free(fragmentDirectionalSource);
211   221  
212   222 // 頂点データ(三角形)を設定:三角形用(左にオフセット)
213 glDeleteShader(vertexShader); 223 float vertices[] = {
214   224 -0.8f, -0.5f, 0.0f, 0.0f, // 左下(位置、UV)
215 glDeleteShader(fragmentShader); 225 -0.3f, -0.5f, 1.0f, 0.0f, // 右下
216   226 -0.55f, 0.5f, 0.5f, 1.0f // 上
217 free(vertexShaderSource); 227 };
218   228 GLuint indices[] = { 0, 1, 2 };
219 free(fragmentShaderSource); 229  
220   230 // 頂点データ(三角形)を設定:ディレクショナル用(右にオフセット)
221   231 float verticesDirectional[] = {
222 // 頂点データ(フルスクリーンクアッド)を設定 232 0.3f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, 0.707f, // 左下(位置、UV、形動ノーマル)
223 float vertices[] = { 233 0.8f, -0.5f, 1.0f, 0.0f, 0.5f, -0.5f, 0.707f, // 右下
224 -1.0f, -1.0f, 0.0f, 0.0f, // 左下(位置、UV) 234 0.55f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.707f // 上
225 1.0f, -1.0f, 1.0f, 0.0f, // 右下 235 };
226 1.0f, 1.0f, 1.0f, 1.0f, // 右上 236  
227 -1.0f, 1.0f, 0.0f, 1.0f // 左上 237  
228   238 // VAO、VBO、EBOを三角形用に設定
229   239 GLuint VAO, VBO, EBO;
230   240 glGenVertexArrays(1, &VAO);
231   241 glGenBuffers(1, &VBO);
232   267 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
233   268 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
234   269  
235 }; 270 // 頂点属性:位置(location 0)、UV(location 1)、ノーマル (2)
236 GLuint indices[] = { 0, 1, 2, 2, 3, 0 }; 271 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
237   272 glEnableVertexAttribArray(0);
238   273 size_t offset = 2 * sizeof(float);
239 GLuint VAO, VBO, EBO; 274 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)offset);
240 glGenVertexArrays(1, &VAO); 275 glEnableVertexAttribArray(1);
241 glGenBuffers(1, &VBO); 276  
208   277 // VAO、VBO、EBOをディレクショナル用に設定
209   278 GLuint VAODirectional, VBODirectional, EBODirectional;
210   279 glGenVertexArrays(1, &VAODirectional);
211   280 glGenBuffers(1, &VBODirectional);
212   281 glGenBuffers(1, &EBODirectional);
213   282  
214   283 glBindVertexArray(VAODirectional);
215   284 glBindBuffer(GL_ARRAY_BUFFER, VBODirectional);
216   285 glBufferData(GL_ARRAY_BUFFER, sizeof(verticesDirectional), verticesDirectional, GL_STATIC_DRAW);
217   286 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBODirectional);
218   287 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
219   288  
220   289 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void *)0);
221   290 glEnableVertexAttribArray(0);
222   291 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void *)(2 * sizeof(float)));
223   292 glEnableVertexAttribArray(1);
224   293 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void *)(4 * sizeof(float)));
225   294 glEnableVertexAttribArray(2);
226   295  
227   296 // メインレンダリングループ
228   297 while (!glfwWindowShouldClose(window)) {
229   298 // 画面をクリア
230   344  
231   345 // クアッドを描画
232   346 glBindVertexArray(VAO);
233   347 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
234   348  
235   349 // ディレクショナルシェーダープログラムを使用(右の三角形)
236   350 glUseProgram(directionalShaderProgram);
237   351  
238   352 // ユニフォームを設定(アンビエントシェーダー)
239   353 Vector3 materialColor = { 0.8f, 0.2f, 0.3f }; // 赤みがかった色
240   354 Vector3 lightDirection = { -0.5f, -0.5f, -0.707f }; // ライトの方向(正規化不要、シェーダーで処理)
241   355 float lightIntensity = 1.0f; // ライトの強さ(0.0~1.0)
242   356  
243   357 glUniform3f(glGetUniformLocation(directionalShaderProgram, "materialColor"), materialColor.r, materialColor.g, materialColor.b);
244   358 glUniform3f(glGetUniformLocation(directionalShaderProgram, "lightDirection"), lightDirection.x, lightDirection.y, lightDirection.z);
245   359 glUniform1f(glGetUniformLocation(directionalShaderProgram, "lightIntensity"), lightIntensity);
246   360  
247   361 // 右の三角形を描画(ディレクショナルシェーダー)
248   362 glBindVertexArray(VAODirectional);
249   363 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
250   364  
251   365 // バッファをスワップし、イベントを処理
252   366 glfwSwapBuffers(window);
253   377 glDeleteVertexArrays(1, &VAO);
254   378 glDeleteBuffers(1, &VBO);
255   379 glDeleteBuffers(1, &EBO);
256   380 glDeleteVertexArrays(1, &VAODirectional);
257   381 glDeleteBuffers(1, &VBODirectional);
258   382 glDeleteBuffers(1, &EBODirectional);
259   383 glDeleteProgram(shaderProgram);
260   384 glDeleteProgram(directionalShaderProgram);
261   385 glfwDestroyWindow(window);
262   386 glfwTerminate();
263   387  
264   388 return 0;
265   389 }
266      
267 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);    
268 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);    
269      
270 // 頂点属性:位置(location 0)、UV(location 1)    
271 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);    
272 glEnableVertexAttribArray(0);    
273 size_t offset = 2 * sizeof(float);    
274 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)offset);    
275 glEnableVertexAttribArray(1);    
276      
277      
278      
279      
280      
281      
282      
283      
284      
285      
286      
287      
288      
289      
290      
291      
292      
293      
294      
295      
296 // メインレンダリングループ    
297 while (!glfwWindowShouldClose(window)) {    
298 // 画面をクリア    
254      
255      
256      
257      
258      
259      
260      
261      
262      
263      
264      
265      
266      
267      
268      
269      
270      
271      
272      
273      
274      
275      
276      
277      
278      
279      
280      
281      
282      
283      
284      
285      
286      
287      
288      
289      
290      
291      
292      
293      
294      
295      
296      
297      
298      
299      
300      
301      
302      
303      
304      
305      
306      
307      
308      
309      
310      
311      
312      
313      
314      
315      
316      
317      
318      
319      
320      
321      
322      
323      
324      
325      
326      
327      
328      
329      
330      
331      
332      
333      
334      
335      
336      
337      
338      
339      
340      
341      
342      
343      
344      
345 // クアッドを描画    
346 glBindVertexArray(VAO);    
347 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);    
348      
349      
350      
351      
352      
353      
354      
355      
356      
357      
358      
359      
360      
361      
362      
363      
364      
365 // バッファをスワップし、イベントを処理    
366 glfwSwapBuffers(window);    
265      
266      
267      
268      
269      
270      
271      
272      
273      
274      
275      
276      
277      
278      
279      
280      
281      
282      
283      
284      
285      
286      
287      
288      
289      
290      
291      
292      
293      
294      
295      
296      
297      
298      
299      
300      
301      
302      
303      
304      
305      
306      
307      
308      
309      
310      
311      
312      
313      
314      
315      
316      
317      
318      
319      
320      
321      
322      
323      
324      
325      
326      
327      
328      
329      
330      
331      
332      
333      
334      
335      
336      
337      
338      
339      
340      
341      
342      
343      
344      
345      
346      
347      
348      
349      
350      
351      
352      
353      
354      
355      
356      
357      
358      
359      
360      
361      
362      
363      
364      
365      
366      
367      
368      
369      
370      
371      
372      
373      
374      
375      
376      
377 glDeleteVertexArrays(1, &VAO);    
378 glDeleteBuffers(1, &VBO);    
379 glDeleteBuffers(1, &EBO);    
380      
381      
382      
383 glDeleteProgram(shaderProgram);    
384      
385 glfwDestroyWindow(window);    
386 glfwTerminate();    
387      
388 return 0;    
389 }    

ファイル: a/shader/frag_ambient.glsl

    1 #version 450 core
    2  
    3 in vec2 uVu;
    4 out vec4 out_color;
    5  
    6 uniform vec3 materialColor;
    7 uniform float ambientIntensity;
    8  
    9 void main() {
    10 vec3 ambient = materialColor * ambientIntensity;
    11 out_color = vec4(ambient, 1.0);
    12 }

ファイル: a/shader/frag_directional.glsl

    1 #version 450 core
    2  
    3 in vec2 vUv;
    4 in vec3 vNormal;
    5 out vec4 out_color;
    6  
    7 uniform vec3 materialColor;
    8 uniform vec3 lightDirection;
    9 uniform float lightIntensity;
    10  
    11 void main() {
    12 vec3 normal = normalize(vNormal);
    13  
    14 float diffuseFactor = max(dot(normal, -normalize(lightDirection)), 0.0);
    15 vec3 diffuse = materialColor * diffuseFactor * lightIntensity;
    16 out_color = vec4(diffuse, 1.0);
    17 }

ファイル: a/shader/vertex_directional.glsl

    1 #version 450 core
    2  
    3 layout(location = 0) in vec2 aPosition;
    4 layout(location = 1) in vec2 aUv;
    5 layout(location = 2) in vec3 aNormal;
    6  
    7 out vec2 vUv;
    8 out vec3 vNormal;
    9  
    10 void main() {
    11 vUv = aUv;
    12 vNormal = aNormal;
    13 gl_Position = vec4(aPosition, 0.0, 1.0);
    14 }