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

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

视图概念的理解

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

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

完成代码

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

#include 
#include 
#include 
#include 
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视图概念,固定管线渲染下的实例演示——物体坐标到屏幕坐标,屏幕坐标到物体坐标_第2张图片
窗口显示图如下所示:
opengl视图概念,固定管线渲染下的实例演示——物体坐标到屏幕坐标,屏幕坐标到物体坐标_第3张图片

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

你可能感兴趣的:(opengl)