しらべたこと
シェーダー関係
glCreateProgram
- 戻り値 (GLuint) プログラムオブジェクトのハンドル
0が返ってきた場合はプログラムオブジェクトの作成に失敗している - 引数 なし
空のプログラムオブジェクトを作成し、0以外の値を返す
- プログラムオブジェクトとは
シェーダーオブジェクトをアタッチ可能なオブジェクト
※シェーダーオブジェクトについては後述する
glCreateShader
- 戻り値 (GLuint) シェーダーオブジェクトのハンドル
- 引数 (GLenum shaderType) シェーダーの種類
空のプログラムオブジェクトを作成し、0以外の値を返す
シェーダーの種類はいくつか存在して
コンピュートシェーダ、頂点シェーダー、ピクセルシェーダー、テッセレーションシェーダ、ジオメトリシェーダなどを指定する(GL_***_SHADERがそれらに該当する)
※コンピュートシェーダーはGLバージョン4.3以上で使用が可能
- シェーダーオブジェクトとは
シェーダーコードの維持(?)に使用されるオブジェクト
自分は、自前のシェーダーをデータとして保持するためのオブジェクトという解釈をしている
glShaderSource
-
戻り値 なし
-
引数 (GLenum shaderType, GLsizei count, const GLchar** string, const GLint* length)
- shaderType シェーダーオブジェクトのハンドルを指定
- count 引数stringとlengthで配列を指定してる場合、配列の要素数を指定
- **string シェーダーのソースコード配列を指定
- *length 引数string配列の各種文字列の長さを指定
引数length
にNULLが指定されていた場合、配列の各文字列はNULL終端とみなされる
引数length
にNULL以外が指定されていた場合、引数string配列
の各要素に対応する文字列の長さを指定する
-
引数shader
で指定したシェーダーオブジェクトは引数string配列
で指定したソースコードと関連付けられる -
シェーダーオブジェクトに元々関連付けされていた場合、それらのシェーダーは上書きされる
-
この関数を使用した時点ではコードの解析やスキャンをおこなうわけではなく、単純にコードをシェーダーオブジェクトにコピーしているだけ
ここの翻訳ちょっと大変だった
glCompileShader
- 戻り値 なし
- 引数 (GLuint shader) シェーダーオブジェクトのハンドル
指定したシェーダーオブジェクトに保存されているソースコードをコンパイルする
コンパイルステータスは、シェーダーオブジェクトの状態の一部として保存される
ステータスは glGetShaderiv
関数の引数にGL_COMPILE_STATUS
を渡すことで取得することができる
さらに、エラーが存在する場合glGetProgramiv
にGL_INFO_LOG_LENGTHを指定することで、ログの文字列の長さを取得することができる
glGetShaderInfoLog
関数を使用することによってコンパイルに関する情報を取得することが可能となっている
glAttachShader
- 戻り値 なし
- 引数 (GLuint program, GLuint shader)
- program シェーダーオブジェクトがアタッチされているプログラムオブジェクトのハンドル
- shader アタッチするシェーダーオブジェクトのハンドル
プログラムオブジェクトとシェーダーオブジェクトとを関連付ける
複数アタッチ可
glDetachShader
を使って指定したシェーダーオブジェクトをデタッチする
glLinkProgram
- 戻り地 なし
- 引数 (GLuint program)
- program リンクしたいプログラムオブジェクトのハンドル
シェーダーをリンクする
ステータスは glGetProgramiv
関数の引数にGL_LINK_STATUS
を渡すことで取得することができる
さらに、エラーが存在する場合glGetProgramiv
にGL_INFO_LOG_LENGTHを指定することで、ログの文字列の長さを取得することができる
そして、glGetProgramInfoLog
関数を使用することによってリンクに関する情報を取得することが可能となっている
ここでエラーが返ってきたら、その都度調査という感じで
正直翻訳してて心が折れそうだったので途中でやめた
バッファの作成
glGenVertexArrays
- 戻り値 なし
- 引数 (GLsizei n, GLuint* arrays)
- n 生成する頂点オブジェクトの数を指定する
- arrays ↑で指定した数だけ頂点オブジェクトのID格納する配列を指定する
arraysに返ってくるIDは連続したものである保証はない
glDeleteVertexArraysで削除しない限り、その後glGenVertexArraysを使用しても同じIDが重複することはない
glGenBuffers
- 戻り値 なし
- 引数(GLsizei n, GLuint* buffers)
- n 生成するバッファオブジェクトの数を指定する
- buffers ↑で指定した数だけバッファオブジェクトのID格納する配列を指定する
arraysに返ってくるIDは連続したものである保証はない
glDeleteVertexArraysで削除しない限り、その後glDeleteBuffersを使用しても同じIDが重複することはない
glBindVertexArray
- 戻り値 なし
- 引数(GLuint array)
- array 紐付けしたい頂点配列の名前(glGenVertexArraysで生成したIDを指定する)
生成したIDを指定することによってその後の処理と関連付けをする(glBufferData等)
0を指定すると以前のバインディングを切り離す
glBindBuffer
- 戻り値 なし
- 引数(GLenum target, GLuint buffer)
- target バッファオブジェクトがバインドされるターゲットを指定する
ターゲットについては、色々あるのでリファレンスを要参照 - buffer バッファのIDを指定する
- target バッファオブジェクトがバインドされるターゲットを指定する
生成したIDを指定することによってその後の処理と関連付けをする(glBufferData等)
0を指定すると以前のバインディングを切り離す
glBufferData
- 戻り値 なし
- 引数(GLenum target, GLsizeiptr size, const void* data, GLenum usage)
- target バッファオブジェクトがバインドされるターゲットを指定する
ターゲットについては、glBindBuffer同様色々あるのでリファレンスを要参照 - size データのサイズをバイト単位で指定する
- data セットしたいデータのポインタを指定。NULL指定も可
- usage データの使用方法
- target バッファオブジェクトがバインドされるターゲットを指定する
実際のデータをGPUへ送信する関数
引数data
にNULLを指定した場合、データはコピーされない
glEnableVertexAttribArray
- 戻り値 なし
- 引数(GLuint index)
- index 有効にする頂点属性のインデックスを指定する
glBufferDataで送ったデータの内訳を明確にするために使う
後々GLSLのコード内でlocation
という形でindex
の値が使われる
glVertexAttribPointer
- 戻り値 なし
- 引数(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer)
- index 変更する頂点属性のインデックスを指定する
- size 頂点属性の数を指定する 1~4の値、もしくは
GL_BGRA
でなければならない - type データ型を指定する (初期値
GL_FLOAT
) - normalized 正規化をする場合は
GL_TRUE
そうでない場合はGL_FALSE
- stride 連続した頂点属性のバイトオフセットを指定する
- pointer データ配列の先頭アドレスから数えたバイトオフセットを指定する
データ配列の頂点属性の内容を指定する関数
normalized
については、型が符号付きの場合は-1~1, 符号なしの場合は0~1の値に正規化される
stride
で値を指定することによって、座標3byte, 法線3byte, uv2byte が連続してる配列データ等1配列に複数の情報が格納されている場合を考慮できるようになる
頂点オブジェクトとバッファオブジェクト
頂点オブジェクトがバッファオブジェクトを管理しているイメージ
各頂点の座標や法線等のデータをバッファオブジェクトとして管理し、それらをまとめて管理しているのが頂点オブジェクト的な
描画関係
glGetUniformLocation
- 戻り値 (GLint) uniformのlocationID
- 引数(GLuint program, const GLchar* name)
- program プログラムオブジェクトのIDを指定する
- name シェーダー側で使用されているuniform変数の名前
uniform変数の位置を取得する
後々、glUniform関数で値を更新するのに使用したりする
uniformが配列の場合はname
に添え字を加えることで、配列の値を個別に取得することもできる(?)
↑ためしてないので不確定な情報
glUniform○○
- 戻り値 なし
- 引数 (GLint location, GLsizei count, GLboolean transpose <= あったりなかったりする, const GLfloat* value)
- location uniform変数のlocationIDを指定する
- count 設定する値の数 配列の場合は1より大きい値を指定する必要がある
- transpose 行列のuniformを設定するばあいに指定できる引数。 転地するかどうかをtrue falseで指定する
- v0,v1,v2,v3 それぞれ対応する値を引数に設定する
- value ベクターか行列の場合、配列の先頭アドレスを指定する
uniform変数の値を更新するのに使用する関数
公式ドキュメントには色々書いてあるけど、関数の命名規則とそれぞれの関数が何をしているかとかが書いてある気がする
glDrawArrays
- 戻り値 なし
- 引数 (GLenum mode, GLint first, GLsizei count)
- mode 描画するポリゴンの形状を指定する 三角形・四角形・ライン・点などが指定できる
- first 配列の先頭アドレスを指定する
- count 配列の要素数を指定する
ポリゴンを描画する関数
引数first
については、バッファをGPU側に送っている場合は0を指定する
glDrawElements
glDrawArraysとの違い
端的に言ってしまうと、共通インデックスの概念を利用できる
インデックスに対して、座標や法線の情報をテーブルとして紐付けできるので、無駄のないデータ構造を構築することができるのだと思う
↓画像付きで解説されていてとてもわかりやすかった
とても参考になったサイト: 床井研究室 - 第8回 指標を用いた図形の描画
ソースコード
// 初期化処理
GLuint programObject, vao, vbo;
void Init(){
// プログラムオブジェクトを作成
programObject = glCreateProgram();
// 頂点シェーダーコンパイルまで
const GLuint vsShaderObject = glCreateShader();
const GLchar* vsCode = "頂点しぇーだーのコード";
glShaderSource(vsShaderObject, 1, &vsCode, NULL);
glCompileShader(vsShaderObject);
glAttachShader(programObject, vsShaderObject);
// フラグメントシェーダーコンパイルまで
const GLuint fsShaderObject = glCreateShader();
const GLchar* fsCode = "フラグメントしぇーだーのコード";
glShaderSource(fsShaderObject, 1, &fsCode, NULL);
glCompileShader(fsShaderObject);
glAttachShader(programObject, fsShaderObject);
// リンク
glLinkProgram(programObject);
/************************************************************/
//頂点データの作成
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindVertexArray(GL_ARRAY_BUFFER, vbo);
static const float positionArray[] = {
0.0f, 1.0f, 0.0f,
-1.0f,-1.0f, 0.0f,
1.0f,-1.0f, 0.0f,
};
// 頂点データ作成
glBufferData(GL_ARRAY_BUFFER, sizeof(positionArray), positionArray, GL_STATIC_DRAW);
// location = 0 の属性設定
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindArray(0);
}
// ------------------------------------------------
// ループ
void Loop(){
// 使用するプログラムを指定
glUserProgram(programObject);
glBindVertexArray(vao);
// モデル行列の値を指定
const GLint modelLocation = glGetUniformLocation(programObject, "aModel");
glUniformMatrix4fv(modelLocation, 1, GL_FALSE, modelMat/*モデル行列のポインタ*/);
// ビュー行列の値を指定
const GLint viewLocation = glGetUniformLocation(programObject, "aView");
glUniformMatrix4fv(viewLocation, 1, GL_FALSE, viewMat/*ビュー行列のポインタ*/);
// パースペクティブ行列の値を指定
const GLint perspectiveLocation = glGetUniformLocation(programObject, "aProjection");
glUniformMatrix4fv(perspectiveLocation, 1, GL_FALSE, perspectiveMatrix/*射影行列のポインタ*/);
glDrawArray(GL_TRIANGLES, 0, 9);
glBindVertexArray(0);
glUserProgram(0);
}
// ------------------------------------------------
int main(){
Init();
// ~なんかいい感じにループする処理 start~
Loop();
// ~なんかいい感じにループする処理 end~
return 0;
}
#version 430 core
layout (location = 0) in vec3 aPosition;
uniform mat4 aModel;
uniform mat4 aView;
uniform mat4 aProjection;
out vec3 FragPosition;
void main(){
FragPosition = vec3(aModel * vec4(aPosition, 1.0));
gl_Position = aProjection * aView * vec4(FragPosition, 1.0);
}";
#version 430 core;
out vec4 FragColor;
void main(){
FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
結果
参考ページ
OpenGL4.5 Reference Pages
https://www.khronos.org/registry/OpenGL-Refpages/gl4/
床井研究室 - 第8回 指標を用いた図形の描画
http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20090909