openGL通过glRasterPos设置当前光栅坐标实现分屏效果

最近做一个分屏效果,即左右两个viewport同时显示一个bmp图像
openGL通过glRasterPos设置当前光栅坐标实现分屏效果
文章图片
最终效果
我的bmp图像是从摄像头获得的,摄像头的画面是先保存成bmp文件,再使用glDrawPixel绘制出来的,绘制一个还行,但是绘制第二个(即右边的)的时候就遇到了问题,怎样改变glDrawPixel绘制图像的位置?
glDrawPixel不像glBitmap可以直接指定绘制起点,注意windows下的bmp文件算是图片,并不算是位图,要绘制bmp文件并不能用glBitmap函数
openGL通过glRasterPos设置当前光栅坐标实现分屏效果
文章图片
openGL通过glRasterPos设置当前光栅坐标实现分屏效果
文章图片

来自
https://docs.microsoft.com/zh-cn/windows/desktop/OpenGL/gldrawpixels
https://docs.microsoft.com/zh-cn/windows/desktop/OpenGL/glbitmap

glDrawPixels function reads pixel data from memory and writes it into the framebuffer relative to the current raster position
glDrawPixel从内存中读取像素数据并写入帧缓存,受到当前光栅坐标的影响。当前光栅坐标包括四部分(x,y,z,w),其中w与裁剪相关,可以通过glGet的GL_CURRENT_RASTER_POSITION参数来获得当前光栅坐标,默认为(0,0,0,1)
float pos[4]; glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); printf("x:%f\n", pos[0]); printf("y:%f\n", pos[1]); printf("z:%f\n", pos[2]); printf("w:%f\n", pos[3]);

默认的绘制起点是屏幕的左下角,通过glRasterPos方法可以改变当前光栅坐标从而改变glDrawPixel的绘制起始位置。
glRasterPos有许多分支,它们都用来指定当前光栅坐标
openGL通过glRasterPos设置当前光栅坐标实现分屏效果
文章图片

glRasterPos2f与glRasterPos3f的区别在于
glRasterPos2f只改变x,y,将z,w设置为0和1
glRasterPosz,w,3f改变x,y,z,将w设置为1
同理,4f是改变xyzw

glRasterPos的参数 我在改变光栅坐标时遇到了一个问题,无论如何通过glRasterPos设置坐标,glGet返回的结果只有w的值发生了改变,xyz始终为0,而且也没有图像被绘制出来。
出现这个问题的原因在于:
glRasterPos设置的坐标是世界坐标,受到投影变换和视景体裁剪的影响,也就是说我设置的世界坐标在经过ModelView,Projection,和ViewPort的变换之后,如果没有在视景体之内(你可以理解为camera看不见),那么这个坐标是无效的,无法改变glRasterPos的xyz,glDrawPixel也不会进行绘制
你可以通过glGet的GL_CURRENT_RASTER_POSITION_VALID参数来检查当前光栅坐标是否有效
GLboolean if_valid; glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &if_valid);

如果返回的是false,那么恭喜你设置的坐标确实有问题。

我的投影矩阵和模型视图矩阵变换非常复杂,怎么样才能找到正确的参数?
两种解决办法:
1、glWindowPos函数允许你通过设置屏幕坐标来改变光栅坐标,但需要引入glew库
2、通过glUnProject计算出屏幕坐标对应的世界坐标
我使用的是第二种方法,第一种方法没有试验过,两种方法的本质其实都是一样的
GLdouble world_x, world_y, world_z; //最终结果//计算屏幕坐标对应的世界坐标 void GetPos() { GLdouble screen_x, screen_y, screen_z; GLdouble m_projection[16], m_modelview[16]; GLint m_viewport[4]; glGetDoublev(GL_PROJECTION_MATRIX, m_projection); //获得投影矩阵 glGetDoublev(GL_MODELVIEW_MATRIX, m_modelview); //获得模型视图矩阵 glGetIntegerv(GL_VIEWPORT, m_viewport); //获得viewport//设置屏幕坐标的x,y screen_x = imagewidth; //imagewidth是一张bmp图片的宽度 screen_y= 0; screen_z = 0; //获得对应的世界坐标 gluUnProject((GLdouble)screen_x, (GLdouble)screen_y, (GLdouble)screen_z, m_modelview, m_projection, m_viewport, &world_x, &world_y, &world_z); cout << "得到的world坐标:" << endl; cout << "(" << world_x << "," << world_y << "," << world_z << ")" << endl; }

在gluUnProject中进行(GLdouble)的强制类型转换是出于精度的考虑,因为看到一些博客说如果不是GLdouble类型使用float的话会导致出现误差。
注意在绘制完右边的图像后再想绘制坐标的图像需要将当前光栅坐标改回去,再使用上面的函数计算一次,屏幕坐标x和y要改为0,0(屏幕坐标系原点在左下角),如果是想在鼠标函数中实现某些效果,要记得对y坐标进行处理转为屏幕坐标


【openGL通过glRasterPos设置当前光栅坐标实现分屏效果】

    推荐阅读