読者です 読者をやめる 読者になる 読者になる

Lynx-EyEDの電音鍵盤 新館

広帯域制御屋の駄文とか

GLFW3 + VS2013を使った立方体の描画と回転

OpenGL GLFW

OpenGL + GLFW3 + VS2013で立方体を回転させる

ちょっと計測関連でOpenGLを触らないといけなくなったのでメモがわりに。
学生時代、GLUT+GLSLで水蒸気爆発シミュとかやった記憶がありましたが、今回もGLUTに頼ろうとしたものの、Mac OS X(Marvericks)/Linux/Windows 7 or 8.1/iOS*1 で同じような動作をしてほしかったこともあり、となると…OpenGL 3以上が必要な感じになり、どうしたものかと。

ライブラリ導入

  • GLFW3

GLFW - An OpenGL library
GLFW3では、先ほどの条件を満たし、かつ複数のウィンドウをハンドルしたりスレッドを扱う事が出来るので今回の用途に最適と思われました。そのかわりGLUTで便利なあのtorusとかteapotをひょこっと出す、みたいな芸当はできませんけれども。
というわけでさっそく、Windows 8.1 32bitのタブレット(Dell Venue 8 Pro)に導入してみました。

Visual Studio Express
GLFW3.02を導入したのですが、コンパイル済みdllを使うとなるとVS2012以降が必要になるようなので、VS Express 2013をインストール(要Windows liveアカウント)

  • GLFW3

GLFW - Download
Source Packageと32-bit Windows binariesの両方をダウンロードします。
● 32-bit Windows binaries
[lib-msvc120]フォルダの中の
glfw3.dll -> C:¥Windows¥System32¥
glfw3.lib, glfw3dll.lib -> C:¥Program Files¥Windows Kits¥8.1¥Lib¥winv6.3¥um¥x86
にコピー
● Source Package
[include]フォルダの
[GLFW] -> C:¥Program Files¥Windows Kits¥8.1¥Include¥um¥
にフォルダごとコピー

立方体を作って回転させる

GLUTでの作例はたくさんあるのでそれをGLFWのドキュメントを参考に、GLFWで作り直す方法でやってみます。
GLUTによる「手抜き」OpenGL入門
GLUTとOpenGLで立方体を回転させて表示するプログラム | GLUTでOpenGL 3Dプログラミング


VS2013 VC++WIn32プロジェクトを新規作成
上記ソースコードをGLFW3向けに書き換え

#define GLFW_INCLUDE_GLU
#include <stdio.h>
#include <GLFW/glfw3.h>
#include <Windows.h>

#pragma comment(lib, "GLFW3.lib")
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")


void reshape(int width, int height)
{

	static GLfloat lightPosition[4] = { 0.25f, 1.0f, 0.25f, 0.0f };
	static GLfloat lightDiffuse[3] = { 1.0f, 1.0f, 1.0f };
	static GLfloat lightAmbient[3] = { 0.25f, 0.25f, 0.25f };
	static GLfloat lightSpecular[3] = { 1.0f, 1.0f, 1.0f };



	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

	glShadeModel(GL_SMOOTH);
	glViewport(0, 0, width, height);



	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, (double)width / (double)height, 0.1, 100.0);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	gluLookAt(0.5, 1.5, 2.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
	glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
	glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular);

}





static GLfloat vertices[][3] =
{
	{ -0.5f, -0.5f, 0.5f },
	{ 0.5f, -0.5f, 0.5f },
	{ 0.5f, 0.5f, 0.5f },
	{ -0.5f, 0.5f, 0.5f },
	{ 0.5f, -0.5f, -0.5f },
	{ -0.5f, -0.5f, -0.5f },
	{ -0.5f, 0.5f, -0.5f },
	{ 0.5f, 0.5f, -0.5f }
};

static GLfloat normals[][3] =
{
	{ 0.0f, 0.0f, 1.0f },
	{ 0.0f, 0.0f, -1.0f },
	{ 1.0f, 0.0f, 0.0f },
	{ -1.0f, 0.0f, 0.0f },
	{ 0.0f, 1.0f, 0.0f },
	{ 0.0f, -1.0f, 0.0f }
};


void display(void)
{

	static GLfloat diffuse[3] = { 1.0f, 0.0f, 0.0f };
	static GLfloat ambient[3] = { 0.25f, 0.25f, 0.25f };
	static GLfloat specular[3] = { 1.0f, 1.0f, 1.0f };
	static GLfloat shininess[1] = { 32.0f };

	static float angle = 0.0f;

	glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
	glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
	glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, shininess);

	glEnable(GL_DEPTH_TEST);

	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	angle += 2.5f;
	if (angle > 360.0f) {
		angle -= 360.0f;
	}

	glPushMatrix();
	glRotatef(angle, 0.0f, 1.0f, 0.0f);

	// 前
	glBegin(GL_QUADS);
		glNormal3fv(normals[0]);
		glVertex3fv(vertices[0]);
		glVertex3fv(vertices[1]);
		glVertex3fv(vertices[2]);
		glVertex3fv(vertices[3]);
	glEnd();

	// 後
	glBegin(GL_QUADS);
		glNormal3fv(normals[1]);
		glVertex3fv(vertices[4]);
		glVertex3fv(vertices[5]);
		glVertex3fv(vertices[6]);
		glVertex3fv(vertices[7]);
	glEnd();

	// 右
	glBegin(GL_QUADS);
		glNormal3fv(normals[2]);
		glVertex3fv(vertices[1]);
		glVertex3fv(vertices[4]);
		glVertex3fv(vertices[7]);
		glVertex3fv(vertices[2]);
	glEnd();

	// 左
	glBegin(GL_QUADS);
		glNormal3fv(normals[3]);
		glVertex3fv(vertices[5]);
		glVertex3fv(vertices[0]);
		glVertex3fv(vertices[3]);
		glVertex3fv(vertices[6]);
	glEnd();

	// 上
	glBegin(GL_QUADS);
		glNormal3fv(normals[4]);
		glVertex3fv(vertices[3]);
		glVertex3fv(vertices[2]);
		glVertex3fv(vertices[7]);
		glVertex3fv(vertices[6]);
	glEnd();

	// 下
	glBegin(GL_QUADS);
		glNormal3fv(normals[5]);
		glVertex3fv(vertices[1]);
		glVertex3fv(vertices[0]);
		glVertex3fv(vertices[5]);
		glVertex3fv(vertices[4]);
	glEnd();

	glPopMatrix();
	Sleep(10);

}
void idle()
{

	Sleep(10);
}

void error_callback(int eror, const char* description)
{
	fputs(description, stderr);
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nShowCmd)
{
	int width, height;
	// コールバックの設定
	glfwSetErrorCallback(error_callback);

	// GLFWを初期化
	if (!glfwInit())
		exit(EXIT_FAILURE);
	

	GLFWwindow* window = glfwCreateWindow(400, 400, "GL Sample", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	glfwMakeContextCurrent(window);
	glfwSetKeyCallback(window, key_callback);


	// メインループ 
	while (!glfwWindowShouldClose(window))
	{
		glfwGetFramebufferSize(window, &width, &height);
		reshape(width, height);
		idle();
		
		display();
		glfwSwapBuffers(window);

		// イベントのポーリング
		glfwPollEvents();
	}

	// Windowの削除
	glfwDestroyWindow(window);
	// GLFWの終了処理
	glfwTerminate();
	exit(EXIT_SUCCESS);
}

実行すると、こんな感じに立方体が回る。
f:id:Lynx-EyED:20140611224226p:plain
◆参考
OpenGLで物質の質感を定義するメモ(glMaterialfv)/ 日々、思ウコト(遠藤理平)


*1:iOSOpenGL ES