这两天一直在思考如何在OpenGL底下对二维的屏幕坐标进行定位。很可惜OpenGL里并没有直接定位的函数,似乎所有的函数都是把输入一个三维的坐标,然后返回这个三维坐标在当前变换矩阵下对应屏幕上的点。不可否认这个东西很有用,比如在敌人身上冒出个伤害值什么的就非此不可。但我现在需要的只是在屏幕上某个固定的位置显示事先设计好的点阵字,那就不是那么好办了……
开始的时候用glLoadIdentity初始化矩阵之后用glRasterPos2i(0,0)定位到屏幕中心,再用glBitmap的第五、六个参数来偏移到目的地。但一直觉得心虚……要知道分辨率都是偶数的,也就是说“中心”对应的二维坐标很可能是因系统而异的。在一个系统下正常的画面到另一个系统可能就歪了。虽然能够在特定条件下满足要求,但这样不健壮的代码总是一个麻烦……
后来看到一个网站上说可以用gluOrtho2D把投影设定成正投影的方法来定位二维坐标:
gluOrtho2D(0, 639, 0, 479);
这样一来,屏幕的左下角就是坐标(0,0),右上角就是(639,479)。然后再用glRasterPos2i来定位就可以了。
然而我尝试的时候总是失败,总是定位到无效的位置导致接下来的点阵字根本就不显示。这个问题大约困扰了我一天的时间。我想方法应该没有错,应该只是有一些基础的代码,该文的作者认为每个OpenGL程序员都应该了解的代码被省略了。于是我去查一本很厚的书,把关于视图的部分好好看了看,终于发现了问题的关键。
OpenGL的变换矩阵分为投影矩阵(GL_PROJECTION)和视图/模型矩阵(GL_MODELVIEW)。(暂不涉及纹理矩阵GL_TEXTURE)使用gluOrtho2D或者gluPerspective等改变投影矩阵的函数之前应该先用glMatrixMode(GL_PROJECTION)将当前矩阵模式设置为投影矩阵,然后glOrtho等函数才能正常地去改变投影矩阵。
换句话说OpenGL里无论是gluPerspective这样的(理解上)改变投影矩阵的函数,还是glTranslatef这样的(理解上)改变视图/模型矩阵的函数,其本质都是根据函数的参数算出一个矩阵,然后与当前矩阵相乘。至于当前矩阵是哪个矩阵,则由glMatrixMode来指定。
了解了问题所在,就很容易写出正确的代码:
//在此之前已经处理完全部三维画面 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, 639, 0, 479); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRasterPos2i(x, y); //x与y是坐标,左下角为(0,0) //从这里开始处理二维画面
以上是窗口大小为640x480的情况。可以将代码写得更加健壮一些。设cx为窗口宽度,cy为窗口高度,则代码相应为:
//在此之前已经处理完全部三维画面 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, cx-1, 0, cy-1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRasterPos2i(x, y); //x与y是坐标,左下角为(0,0) //从这里开始处理二维画面