機械学習基礎理論独習

誤りがあればご指摘いただけると幸いです。数式が整うまで少し時間かかります。リンクフリーです。

勉強ログです。リンクフリーです
目次へ戻る

【VS2022】OpenGLメモ【C++】

glDrawElementsのみを使う想定

glDrawElementsを使う方が速いので描画関数はこれしか使わない。

頂点の設定の流れ

頂点座標、法線、インデックスの場合
VAO,VBO,VBO,EBO って感じで設定する。

VAO

glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
...
glBindVertexArray(0);

VBO

// VBO --- 位置属性 (location = 0) ---
glBindBuffer(GL_ARRAY_BUFFER, vbo_positions_);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(
  0, // シェーダー側の layout(location = 0) に対応する番号。
  3, // 1 頂点あたりの要素数。ここでは vec3 なので 3。
  GL_FLOAT, // データ型。頂点配列の要素が float 型であることを指定。
  GL_FALSE, // 正規化フラグ。整数型を 0〜1 に正規化するかどうかを指定するが、float なので不要。
  3 * sizeof(float), // ストライド(1 頂点分のバイト幅)。
  (void*)0  // バッファ内のオフセット。ここでは VBO の先頭から読む。
);
glEnableVertexAttribArray(0);

// VBO --- 法線属性 (location = 1) ---
glBindBuffer(GL_ARRAY_BUFFER, vbo_normals_);
glBufferData(GL_ARRAY_BUFFER, sizeof(normals), normals, GL_STATIC_DRAW);
glVertexAttribPointer(
  1,              // layout(location = 1)
  3,              // vec3
  GL_FLOAT,
  GL_FALSE,
  3 * sizeof(float), // ストライド(1 頂点分のバイト幅)。
  (void*)0
);
glEnableVertexAttribArray(1);
...
glBindBuffer(GL_ARRAY_BUFFER, 0); // 解除してもしなくてもよい

EBO

EBOにはVBOのglVertexAttribPointerに相当するものは無い。
なぜならglDrawElementsでオフセットを指定できるから。
またglBufferDataで解除してはいけない

// EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

Shader Programの切り替え

glUseProgramで切り替える

Shaderの行列は列優先


Uniform は location を指定できる

画像の読み込みには stb_image.h を使う

単一ヘッダなのでこちらダウンロードしてプロジェクトに追加するだけ。
#include の前に #define をする必要あり。

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

int width, height, channels;
unsigned char *data = stbi_load("image.png", &width, &height, &channels, 0);
if (data) {
    // 画像データを利用
    stbi_image_free(data);
}

glTexImage2D - stb_image.h を使用する例

int width, height, channels;
unsigned char* data = stbi_load("image0.png", &width, &height, &channels, 0);
if (data) {
  GLenum format = GL_RGB;
  if (channels == 1) format = GL_RED;
  else if (channels == 3) format = GL_RGB;
  else if (channels == 4) format = GL_RGBA;
  // 画像データを利用
  glTexImage2D(GL_TEXTURE_2D, 0, format, width, height,
               0, GL_RGB, GL_UNSIGNED_BYTE, data);
  glGenerateMipmap(GL_TEXTURE_2D);
  stbi_image_free(data);
}

glTexImage2D - CImage を使用する例

少しハマったのでメモ
CImage の pitch とパディングを考慮して連続バッファにコピーする
あとBGRにする。

unsigned char* src = (unsigned char*)img.GetBits();
std::vector<unsigned char> buffer(width * height * (bpp / 8));
int pitch = img.GetPitch();
for (int y = 0; y < height; ++y) {
  memcpy(&buffer[y * width * (bpp / 8)],
         src + y * pitch,
         width * (bpp / 8));
}
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height,
             0, format, GL_UNSIGNED_BYTE, buffer.data());
glGenerateMipmap(GL_TEXTURE_2D);
目次へ戻る