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 2013 for Windows Desktopの導入
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); }
実行すると、こんな感じに立方体が回る。
◆参考
OpenGLで物質の質感を定義するメモ(glMaterialfv)/ 日々、思ウコト(遠藤理平)