opengl视图概念,固定管线渲染下的实例演示——物体坐标到屏幕坐标,屏幕坐标到物体坐标

时间:2022-03-12 10:30:24

参考了一下两篇博客:
http://blog.csdn.net/zhongjling/article/details/8488844
http://blog.csdn.net/lyx2007825/article/details/8792475

视图概念的理解

opengl视图概念,固定管线渲染下的实例演示——物体坐标到屏幕坐标,屏幕坐标到物体坐标

整个过程说的非学术点的话,就是一个向量与几个矩阵相乘后,得到另一个向量,那么这个向量就是你想要的结果。

完成代码

说明:用的是freeglut glew库,由于最近正用opencv,为了偷懒所以矩阵的运算用的是opencv2里的mat。当然,自己改用数组的运算也是可以的。

#include <vgl.h>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;

GLfloat g_x = 7, g_y = 6, g_z = 4;
GLint viewport[4] = { 0 };
GLdouble modelview[16] = { 0.0f };
GLdouble projection[16] = { 0.0f };

Mat arr2mat(double *arr, int n){
vector<float> mvec;
for (int i = 0; i < n; i++)
mvec.push_back(arr[i]);
Mat mat = Mat(mvec).reshape(1, 4).t();
return mat;
}

void init() {
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
}

void display(void){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//打印白色原点
glColor3f(1.0, 1.0, 1.0);
glPointSize(2);
glBegin(GL_POINTS);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
//相机设置, 视图变换(view)
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
//投影变换
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-10, 10, -10, 10, -10, 10);
glMatrixMode(GL_MODELVIEW);
//模型变换(modeling)
glTranslatef(0, 0, -3);
//打印红色点(7, 6, 4)
glColor3f(1.0, 0.0, 0.0);
glPointSize(2);
glBegin(GL_POINTS);
glVertex3f(g_x, g_y, g_z);
glEnd();

glFlush();
}

Mat screen2world(int x, int y){
GLfloat winX = 0.0, winY = 0.0, winZ = 0.0;
GLdouble world_x = 0.0, world_y = 0.0, world_z = 0.0;
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);

winX = (float)x;
winY = (float)viewport[3] - (float)y;
glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); //获取屏幕坐标的深度信息
gluUnProject(winX, winY, winZ, modelview, projection, viewport, &world_x, &world_y, &world_z); //获取屏幕坐标对应的世界坐标
Mat_<double> v(3, 1);
v(0, 0) = world_x; v(1, 0) = world_y; v(2, 0) = world_z;
return v;
}

Mat world2screen(float x, float y, float z){
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);

GLfloat winx = 0.0f, winy = 0.0f;
Mat_<double> vec(4, 1);
vec(0, 0) = x; vec(1, 0) = y; vec(2, 0) = z; vec(3, 0) = 1.0;
Mat_<double> mv = arr2mat(modelview, 16); //模型视图矩阵
Mat_<double> pj = arr2mat(projection, 16); //投影矩阵
Mat_<double> res(4, 1);
res = mv * vec;
res = pj * res;
res = res / res(3, 0); //标准化到-1~1范围
res(0, 0) = (viewport[2] * 0.5f) * res(0, 0) + (viewport[0] + viewport[2] * 0.5f);
res(1, 0) = (viewport[3] * 0.5f) * res(1, 0) + (viewport[1] + viewport[3] * 0.5f); //计算窗口像素坐标值
return res;
}

void reshape(int w, int h){
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1.0, 1.0, 100);
}

void onmouse(int button, int state, int x, int y) {
cout.setf(ostream::fixed);
cout.precision(7);

if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
cout << "鼠标单击位置像素坐标:" << endl;
cout << "mouse_x = " << x << ", mouse_y = " << y << endl;

Mat_<double> v = screen2world(x, y);
Point3d world;
world.x = v(0, 0);
world.y = v(1, 0);
world.z = v(2, 0);
cout << "显示鼠标单击位置像素对应的世界坐标:" << endl;
cout << "world_x = " << world.x
<< ", world_y = " << world.y
<< ", world_z = " << world.z << endl;
v = Mat::zeros(Size(v.size()), v.type());
v = world2screen(world.x, world.y, world.z);
cout << "刚才生成的世界坐标对应的屏幕坐标为:" << endl;
cout << "window_x = " << v(0, 0) << ", window_y = " << v(1, 0) << endl;
}
}

int main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(200, 200);
glutCreateWindow("trans");

init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(onmouse);

glutMainLoop();
return 0;
}

运行结果图如下所示:
opengl视图概念,固定管线渲染下的实例演示——物体坐标到屏幕坐标,屏幕坐标到物体坐标
窗口显示图如下所示:
opengl视图概念,固定管线渲染下的实例演示——物体坐标到屏幕坐标,屏幕坐标到物体坐标

初学openGL,难免有错误, 一起交流讨论!