第 6 章 マウスとキーボード
6.1 ウィンドウとビューポート
6.1.4 表示図形の縦横比を維持する
glUseProgram(program);
// 図形を描画する
glBindVertexArray(object.vao);
glDrawArrays(GL_LINE_LOOP, 0, object.count);
// カラーバッファを入れ替えてイベントを取り出す window.swapBuffers();
} }
そのために、コンストラクタで glfwSetWindowUserPointer() 関数により this ポインタ、すなわ ち生成されたインスタンス自体を指すポインタを、GLFW 側で記録しておきます。そして、コー ルバック関数として起動された静的メンバ関数において、その引数に渡されるウィンドウのハン ドルをもとに、glfwGetWindowUserPointer() 関数を使って記録した this ポインタを取り出します。
インスタンスのメンバ変数は、このポインタを使ってアクセスすることができます。
このほか、この変数の値をクラス外から参照できるように、getAspect() のようなメンバ関数 (アクセサ) を用意しておきます。
// ウィンドウ関連の処理 class Window
{
// ウィンドウのハンドル GLFWwindow *const window;
// 縦横比
GLfloat aspect;
public:
// コンストラクタ
Window(int width = 640, int height = 480, const char *title = "Hello!") : window(glfwCreateWindow(width, height, title, NULL, NULL))
{
《省略》
// 垂直同期のタイミングを待つ glfwSwapInterval(1);
// このインスタンスの this ポインタを記録しておく glfwSetWindowUserPointer(window, this);
// ウィンドウのサイズ変更時に呼び出す処理の登録 glfwSetWindowSizeCallback(window, resize);
// 開いたウィンドウの初期設定 resize(window, width, height);
}
《省略》
// 縦横比を取り出す
GLfloat getAspect() const { return aspect; }
// ウィンドウのサイズ変更時の処理
static void resize(GLFWwindow *const window, int width, int height) {
// ウィンドウ全体をビューポートに設定する glViewport(0, 0, width, height);
// このインスタンスの this ポインタを得る Window *const
instance(static_cast<Window *>(glfwGetWindowUserPointer(window)));
if (instance != NULL) {
// このインスタンスが保持する縦横比を更新する instance->aspect =
static_cast<GLfloat>(width) / static_cast<GLfloat>(height);
} } };
void glfwSetWindowUserPointer(GLFWwindow *const window, void *pointer)
window に指定したウィンドウに対して pointer に指定したユーザ定義の任意のポインタを記
録します。ウィンドウが破棄されるまで、この値が保持されます。初期値はNULLです。
window
ポインタを記録する対象のウィンドウのハンドル。
pointer
記録するポインタ。
void glfwGetWindowUserPointer(GLFWwindow *const window)
window に指定したウィンドウに対して記録されているユーザ定義のポインタを取り出します。
初期値はNULLです。
window
記録されたポインタを取り出す対象のウィンドウのハンドル。
l バーテックスシェーダのソースプログラム point.vert の変更点
このメンバ変数 aspect の値をシェーダプログラムに渡して、バーテックスシェーダで処理さ れる頂点の位置を変更します。aspect の値は一つの図形の描画中に変更されることはないので、
これにはシェーダの uniform 変数を用います。attribute 変数 (4.2.2) が一つの頂点ごとに異なる 情報を保持しているのに対して、uniform 変数は一回の描画命令 (描画単位) で使用される全ての 頂点で共通して参照される値を保持します。
このプログラムでは、描画する図形の頂点位置がバーテックスシェーダの in 変数 (attribute 変
数) pv に格納されています。vec4 は四つの float 型の要素を持つベクトルのデータ型で、pv は
pv.x、pv.y、pv.z、および pv.w の四つの要素を持っています。ただし、このプログラムは図 40 の 二次元図形を描画するものであり、CPU 側のプログラムでは頂点の x 座標値と y 座標値だけ を設定しています。これらはそれぞれ pv.x と pv.y に格納されます。残りの pv.z には 0、p.w に は 1 がデフォルト値として格納されています。
この頂点位置 pv に vec4 などのベクトル型同士のかけ算は、対応する要素同士の積を要素と する同じ型のベクトルになります。たとえば、a と b が vec4 型の変数のとき、a * b は vec4(a.x
* b.x, a.y * b.y, a.z * b.z, a.w * b.w) になります。したがって、このX 座標値だけを 1 / aspect 倍す るには、vec4(1.0 / aspect, 1.0, 1.0, 1.0) という vec4 型の値を乗じます。あるいは pv との乗算を
省略して、gl_Position = vec4(pv.x / aspect, pv.yzw); という書き方をしても結果は同じです。
#version 150 core uniform float aspect;
in vec4 pv;
void main() {
gl_Position = pv * vec4(1.0 / aspect, 1.0, 1.0, 1.0);
}
l uniform 変数 aspect の設定
uniform 変数には、描画を行う前に CPU 側のプログラムで値を設定します。そのためには、プ
ログラムオブジェクトにおける uniform 変数の場所 (index) を、CPU 側のプログラムで調べて おく必要があります。これは glGetUniformLocation() 関数で行います。
uniform 変数に実際に値を設定するには、glUseProgram() でシェーダプログラムを有効にした
後で、その index に対して glUniform*() 関数を使って値を設定します。float 型の単一の変数を 設定するなら glUniform1f() 関数を用います。
《省略》
int main() {
《省略》
// 背景色を指定する
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
// プログラムオブジェクトを作成する
const GLuint program(loadProgram("point.vert", "pv", "point.frag", "fc"));
// uniform 変数の場所を取得する
cosnt GLint aspectLoc(glGetUniformLocation(program, "aspect"));
// 形状データを作成する
const Object object(createRectangle());
// ウィンドウが開いている間繰り返す
while (window.shouldClose() == GL_FALSE) {
// ウィンドウを消去する
glClear(GL_COLOR_BUFFER_BIT);
// シェーダプログラムの使用開始 glUseProgram(program);
// uniform 変数に値を設定する
glUniform1f(aspectLoc, window.getAspect());
// 図形を描画する
glBindVertexArray(object.vao);
glDrawArrays(GL_LINE_LOOP, 0, object.count);
// カラーバッファを入れ替えてイベントを取り出す window.swapBuffers();
} }
GLint glGetUniformLocation(GLuint program, const GLchar *name)
program に指定したプログラムオブジェクトの中で使われている name に指定した uniform
変数の場所を探します。戻り値は uniform 変数の index で、見つからなければ -1 を返します。
program
uniform 変数を探すプログラムオブジェクト名。
name
探す uniform 変数名の文字列。
void glUniform1f(GLint location, GLfloat v0)
現在使用中のシェーダプログラムの location に指定した index の float 型の uniform 変数に GLfloat 型の値 v0 を設定します。ほかに vec2 型に設定する glUniform2f()、vec3 型に設定す る glUniform3f()、vec4 型に設定する glUniform4f() があります。
location
値を設定する float 型の uniform 変数の index。 v0
設定する GLfloat 型の値。