今天回家本想在我的 Ubuntu 上玩玩 OpenGL,结果花了一个下午,终于研究出些东西了……
在 NeHe 的源代码中似乎有 Linux 的,不过一个是用 glut、一个是用 SDL、一个是用 GLX,原本看到 glut 是 OpenGL 官方的一个夸平台的简单窗口系统,结果发现全屏不能……于是就找到了 GLFW 这个东西,据说比较简单,不过还是研究了一个下午。
下面说一下研究成果吧,首先,想要用 g++ 编译用 GLFW 写的程序,一定要加这些编译参数: -lglfw -lGL -lGLU -lXrandr,特别是最后一个,是其官方参考中没有的!这个是我查了许多资料,然后瞎猜猜到的……再说说头文件,这次不需要引用3个库了,只有一个 #include <GL/glfw.h> 就可以了,似乎把其他的库自动引用了。另外就是,画完要用 glfwSwapBuffers(); 刷新,不然不仅什么都不会显示,而且还会死机……除此之外,还要注意那个键盘的按键,不要想当然的和 Windows 下拿去类比,根据研究发现,键盘事件交出的 key 最大可以达到 318,而且特殊键都会以这些“大值”返回,所以一定要申请好内存……
这次主要参考了:
GLFW Reference
OpenGL Tutorials – Basics
以及 NeHe 的 OpenGL 教程。
这个例子是一个转动的彩色四棱锥,只有 ESC 和 F11 的键盘处理,附加帧数计算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | #include <cstdio> #include <cstdlib> #include <cstring> #include <unistd.h> #include <GL/glfw.h> bool fullscreen; bool active = true; bool keys[GLFW_KEY_LAST+1]; // 为键盘按键申请空间 GLfloat rtri; bool initGLFW(const char*, int, int); // 帧数统计用 double starttime; int flames = 0; // 绘制代码 void drawGLScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); glRotatef(rtri, 0.0f, 1.0f, 0.0f); glBegin(GL_TRIANGLES); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f( 0.0f, 1.0f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f( 0.0f, 1.0f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f( 0.0f, 1.0f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f( 0.0f, 1.0f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glEnd(); ++flames; double dt = glfwGetTime() - starttime; if (dt >= 5.0f) { printf("%d frames in %.1lf seconds = %.3lf FPSn", flames, dt, double(flames) / dt); flames = 0; st = glfwGetTime(); } rtri += 0.15f; } // 键盘处理 void keyPress(int key, int action) { keys[key] = action; if (keys[GLFW_KEY_ESC]) { active = false; return; } if (keys[GLFW_KEY_F11]) { keys[GLFW_KEY_F11] = GLFW_RELEASE; glfwTerminate(); fullscreen = ! fullscreen; initGLFW("Upsuper's OpenGL Test", 640, 480); } } inline void quit(int status) { glfwTerminate(); exit(status); } inline void quit() { quit(0); } inline void report_error(const char* info) { puts(info); quit(1); } void resizeGLScene(int width, int height) { if (height <= 0) height = 1; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, GLfloat(width)/GLfloat(height), 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } bool initGL(int width, int height) { glShadeModel(GL_SMOOTH); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); return true; } bool initGLFW(const char* title, int width, int height) { glfwInit(); if (! glfwOpenWindow(width, height, 8, 8, 8, 8, 24, 0, fullscreen ? GLFW_FULLSCREEN : GLFW_WINDOW)) report_error("ERROR: Cannot open a window."); glfwSetWindowTitle(title); glfwEnable(GLFW_AUTO_POLL_EVENTS); glfwSetKeyCallback(keyPress); glfwSetWindowSizeCallback(resizeGLScene); initGL(width, height); } int main(int argc, char** argv) { printf("Would you like to run in fullscreen mode? [Y/n]"); int c = getchar(); fullscreen = (c != 'n' && c != 'N'); memset(keys, false, sizeof(keys)); initGLFW("Upsuper's OpenGL Test", 640, 480); st = glfwGetTime(); do { drawGLScene(); glfwSwapBuffers(); } while (active); quit(); return 0; } |
代码比 VC++ 的那个短好多,再次证明 Linux 是多么适用于编程……
同时根据帧数对比,印证了我的猜想——全屏下比较流畅!我这里全屏下 fps 达到了窗口模式的接近3倍。
附 makefile 文件(这也是我第一次写 makefile):
1 2 | all: test1.cpp a.cpp g++ test1.cpp -o test1 -lglfw -lGL -lGLU -lXrandr |
最后,我还是十分高兴,那个绘制代码是我自己写出来的,不是抄的了!(虽然以前写过……)
写 OpenGL 就是爽……
Comments