traP Member's Blog

D言語でOpenGL†入門†

sobaya007
このエントリーをはてなブックマークに追加

タイトルの通りOpenGLの入門記事をぼちぼち書いていきます。準備に関しては前の記事を参照。

GLFWでとにかくウインドウを表示

D言語ですので引数のない関数の()は取れますし、型名をいちいち書くのが面倒ならautoでいいんですが、説明にならないのでここでは省略をなるべくしない形で書いていきます。

import derelict.opengl3.gl;
import derelict.glfw3.glfw3;
 
void main() {
	//======Derelict側の初期化=====
	DerelictGL.load();
	DerelictGLFW3.load();
 
	//=====GLFWの初期化=====
	glfwInit();
 
	//=====ウインドウの初期化=====
	const int window_width  = 800;
	const int window_height = 600;
	//末尾のnullはそれぞれフルスクリーン、ウインドウの共有をするときに使う(らしい?)
	GLFWwindow *window = glfwCreateWindow(window_width, window_height, "Hello, D World!", null, null);
 
	//=====メインループ=====
	while (!glfwWindowShouldClose(window)) {
	}
 
	//=====おわり=====
	glfwTerminate();
}

 

これで一応GLFWからウインドウを表示することはできます。しかしやってみるとわかりますが、この状態ではウインドウにマウスを乗せただけでグルグルしてしまいます。

これは、GLFWでマウスイベントを処理していないために起きています。これを直すにはglfwPollEvents()という関数を使います。

import derelict.opengl3.gl;
import derelict.glfw3.glfw3;

void main() {
	//======Derelict側の初期化=====
	DerelictGL.load();
	DerelictGLFW3.load();

	//=====GLFWの初期化=====
	glfwInit();

	//=====ウインドウの初期化=====
	const int window_width  = 800;
	const int window_height = 600;
	//末尾のnullはそれぞれフルスクリーン、ウインドウの共有をするときに使う(らしい?)
	GLFWwindow *window = glfwCreateWindow(window_width, window_height, "Hello, D World!", null, null);
	
	glfwMakeContextCurrent(window);

	//=====メインループ=====
	while (!glfwWindowShouldClose(window)) {
		glfwPollEvents();
	}

	//=====おわり=====
	glfwTerminate();
}

 

これでとりあえずウインドウがまともに出せました。続いては何か書いてみましょう。

三角形の表示

すべては三角形に始まり三角形に終わります。三角形は三次元上で使え、凸性を保証された優れた図形です。まずはこれを画面に描いてみましょう。

import derelict.opengl3.gl;
import derelict.glfw3.glfw3;

void main() {
	//======Derelict側の初期化=====
	DerelictGL.load();
	DerelictGLFW3.load();

	//=====GLFWの初期化=====
	glfwInit();

	//=====ウインドウの初期化=====
	const int window_width  = 800;
	const int window_height = 600;
	//末尾のnullはそれぞれフルスクリーン、ウインドウの共有をするときに使う(らしい?)
	GLFWwindow *window = glfwCreateWindow(window_width, window_height, "Hello, D World!", null, null);

	//OpenGLでの描画対象をwindowに設定
	glfwMakeContextCurrent(window);

	//=====メインループ=====
	while (!glfwWindowShouldClose(window)) {
		
		//三角形を描画
		glClear(GL_COLOR_BUFFER_BIT);
		glBegin(GL_TRIANGLES);
		glVertex3d(-0.5, -0.5, 0.0);
		glVertex3d( 0.5, -0.5, 0.0);
		glVertex3d( 0.0,  0.5, 0.0);
		glEnd();
		
		//画面を更新
		glfwSwapBuffers(window);

		glfwPollEvents();
	}

	//=====おわり=====
	glfwTerminate();
}

 

Triangle

こんなかんじになったでしょうか。ここらへんから真面目に解説しようと思います。OpenGLでの図形の描画は上のコードの通り、glClearで画面をクリアし、glBegin始め、途中でglVertex3dをいくつかはさんで頂点の座標を指定し、最後にglEndで締めくくるという流れで行います。

  • glClear(mode) : 画面をクリアします。modeの指定によって色々なものが指定できますが、ここでは画面の色を黒(デフォルト値です)で初期化します。
  • glBegin(mode)  : 図形の描画の開始を指定。modeには以下のものがある。
    • GL_POINTS:点を描く。大きさはglPointSize(size)で指定可能。
    • GL_LINES:頂点が2つ揃ったら直線を描く。
    • GL_LINE_STRIP:最後に出てきた2つの頂点で直線を描く。
    • GL_TRIANGLE_STRIP:最後に出てきた3つの頂点で三角形を描く。
    • GL_TRIANGLE_FAN:最初の頂点 + 最後に出てきた2つの頂点で三角形を描く。
    • GL_LINE_LOOP:GL_LINE_STRIPに加えて最初と最後の頂点でも直線を描く。
    • GL_TRIANGLES : 頂点が3つ揃ったら三角形を描く。
    • GL_QUADS:頂点が4つ揃ったら四角形を描く。
    • GL_QUAD_STRIP:最後に出てきた4つの頂点で四角形を描く。
    • GL_GeometricPrimitivesこんなかんじ。(画像はOpenGLの公式さんから)
  • glVertex3d(x,y,z) : 頂点の位置を(x,y,z)の3次元座標として指定する。似たようなやつとして、glVertex2iとかglVertex4fvとかある。数字は何次元ベクトルかのこと。dやiやfは座標の型(double,int,float)のこと。vがついていないものは、x,y,zのように3つの引数をとる。vがついているものは配列として1つ引数をとる。
  • glEnd():描画の終了を意味する。それ以上でも以下でもない。

OpenGLの座標系は、ウインドウの中心が原点、ウインドウの右上が(1,1),ウインドウの左下が(-1,-1)で、ウインドウの手前から奥へ行く向きにz軸正方向が取ってあります。遠近法はデフォルトでは働かないため、zを大きくしても図形が小さくなったりはしません。また、描画されるものは0 <= z <= 1のもののみです。適当に座標位置を変えながら色々と試してみてください。

色をつける

import derelict.opengl3.gl;
import derelict.glfw3.glfw3;

void main() {
	//======Derelict側の初期化=====
	DerelictGL.load();
	DerelictGLFW3.load();

	//=====GLFWの初期化=====
	glfwInit();

	//=====ウインドウの初期化=====
	const int window_width  = 800;
	const int window_height = 600;
	//末尾のnullはそれぞれフルスクリーン、ウインドウの共有をするときに使う(らしい?)
	GLFWwindow *window = glfwCreateWindow(window_width, window_height, "Hello, D World!", null, null);

	//OpenGLでの描画対象をwindowに設定
	glfwMakeContextCurrent(window);
	
	//=====メインループ=====
	while (!glfwWindowShouldClose(window)) {
		
		//三角形を描画
		glClear(GL_COLOR_BUFFER_BIT);
		glBegin(GL_TRIANGLES);
		glColor3b(byte.max, 0, 0);
		glVertex3d(-0.5, -0.5, 0.0);
		glColor3f(0, 1.0f, 0);
		glVertex3d( 0.5, -0.5, 0.0);
		glColor3i(0, 0, int.max);
		glVertex3d( 0.0,  0.5, 0.0);
		glEnd();
		
		//画面を更新
		glfwSwapBuffers(window);

		glfwPollEvents();
	}

	//=====おわり=====
	glfwTerminate();
}

キャプチャ

こんなかんじになります。各頂点の色をglColorで設定してやります。設定しない場合は最後に指定した色が使われ、デフォルト値は白です。頂点間の色は各頂点の色を線形補間したものになる(詳細は下の※参照)。

  • glColor : 頂点の色を指定する。引数は前から順にR, G, B, Aをとる。数字は引数の数を表しており、例えばRとGのみ設定したければglColor2を用いれば良い(とはいえそんなことは滅多にしない。普通は3か4を使う)。fibは引数の型名を表し、それぞれfloat, int, byte。引数に与える数の範囲は、型が整数型ならば0~(その型の最大値)、浮動小数型ならば0~1をとる。

 

(※ 各頂点の位置ベクトルを\vec{p_1}, \vec{p_2}, \vec{p_3}とすると、三角形上の任意の点\vec{p}は、実数t_1, t_2, t_3(0 \leq t_1, t_2, t_3 \leq 1, t_1 + t_2 + t_3 = 1)を用いて、

\vec{p} = t_1\vec{p_1} + t_2\vec{p_2} + t_3\vec{p_3}

と表される。このt_1, t_2, t_3は「\vec{p}\vec{p_1}, \vec{p_2}, \vec{p_3}にどれだけ近いか」を表すパラメータとみてよい。よって、各頂点の色のRGBを3次元ベクトルとみて、\vec{c_1}, \vec{c_2}, \vec{c_3}としたときの\vec{p}における色\vec{c}は、

\vec{c} = t_1\vec{c_1} + t_2\vec{c_2} + t_3\vec{c_3}

と表せる。こうして頂点間の色をいいかんじに表現している。)

このエントリーをはてなブックマークに追加

コメントを残す

メールアドレスが公開されることはありません。