OpenGLでobjをBlinn-Phongシェーダで表示してみる

はじめに

この記事はシリーズ記事です。目次はこちら。

この記事ではobjファイルを読み込み、鏡面反射項にBlinn-Phongを利用して表示するところまでを行います。

screenshot 0

プログラムの変更点

次に前回からのプログラムの変更点を示します。

シェーダの変更点

フラグメントシェーダを次のように書き換えます。

shader.frag
#version 460

in vec3 vWorldPosition;
in vec3 vWorldNormal;

layout (location = 0) out vec4 fragment;

uniform vec3 worldCameraPosition;

const vec3 worldLightPosition = vec3(0.0, 5.0, 2.0);

const vec3 lightColor = vec3(1.0);

const vec3 Kdiff = vec3(0.8, 0.5, 0.2);
const vec3 Kspec = vec3(1.0);
const float shininess = 50;

void main() {
  vec3 L = normalize(worldLightPosition - vWorldPosition);
  vec3 V = normalize(worldCameraPosition - vWorldPosition);
  vec3 N = normalize(vWorldNormal);
  vec3 H = normalize(L + V);

  // Lambert
  vec3 diffuse = max(dot(L, N), 0) * Kdiff * lightColor;

  // Blinn-phong
  vec3 specular = pow(max(dot(N, H), 0), shininess) * Kspec * lightColor;

  vec3 color = diffuse + specular;

  fragment = vec4(color, 1.0);
}

Uniform変数でカメラのワールド座標系での位置を取得しています。

Kspecは鏡面反射係数で、shininessは輝き係数です。

ViewベクトルVとライトベクトルLから中間ベクトルHを計算しています。

NHの内積をshininess乗して鏡面反射成分を計算しています。

拡散反射について反射係数を前回から変更して色を変えています。

Applicationクラスの変更点

worldCameraPosition用のメンバ変数を追加します。

application.h
  GLFWwindow* window_;
  GLuint program_;
  GLuint model_loc_;
  GLuint model_it_loc_;
  GLuint view_projection_loc_;
+  GLuint world_camera_position_loc_;
  std::vector<MeshEntity> mesh_entities_;
  std::unique_ptr<Camera> camera_;

Application::Initの中のUniform変数のlocationの取得の部分に追記します。

application.cpp
  // Uniform変数の位置を取得
  model_loc_ = glGetUniformLocation(program_, "Model");
  model_it_loc_ = glGetUniformLocation(program_, "ModelIT");
  view_projection_loc_ = glGetUniformLocation(program_, "ViewProjection");
+  world_camera_position_loc_ =
+      glGetUniformLocation(program_, "worldCameraPosition");

Application::Updateを次のように書き換えます。

application.cpp
void Application::Update(const double delta_time) {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glUseProgram(program_);

  auto view_projection = camera_->GetViewProjectionMatrix();
+  auto camera_position = camera_->GetPosition();

  glUniformMatrix4fv(view_projection_loc_, 1, GL_FALSE, &view_projection[0][0]);
+  glUniform3fv(world_camera_position_loc_, 1, &camera_position[0]);

  for (auto&& mesh_entity : mesh_entities_) {
    auto model = mesh_entity.GetModelMatrix();
    auto model_it = glm::inverseTranspose(model);

    glUniformMatrix4fv(model_loc_, 1, GL_FALSE, &model[0][0]);
    glUniformMatrix4fv(model_it_loc_, 1, GL_FALSE, &model_it[0][0]);

    mesh_entity.mesh_->Draw();
  }
}

実行結果

実行結果は次のようになります。

screenshot 0

プログラム全文

プログラム全文はGitHubにアップロードしてあります。

GitHub: MatchaChoco010/OpenGL-PBR-Map at v5