OpenGL三维坐标与二维坐标:gluProject 和 gluUnproject 的详解

简介

三维空间中,经常需要将3D空间中的点转换到2D(屏幕坐标),或者将2D点转换到3D空间中。当你使用OpenGL的时候,简单使用gluProject()和gluUnproject()函数就可以实现这个功能了。但这两个神奇的函数是怎样实现的,一直困扰着我,经过一番仔细研究,将自己的思路写在这里:


gluPorject()

先通过看代码,来一步一步分析它的数学原理吧!(其实代码是次要的,数学原理在这里才是关键所在!)这里的代码据说是赖在mesa OpenGL中的!

PS:这里为了更好理解,我修改了一下里面的代码,但没有兼顾效率的!

[cpp]   view plain copy
  1.   
[cpp]   view plain copy
  1.   
  2. static void transform_point(GLdouble out[4] const GLdouble m[16], const GLdouble in[4])  
  3.  
  4. #define M(row,col) m[col*4+row]  
  5.     out[0] M(0, 0) in[0] M(0, 1) in[1] M(0, 2) in[2] M(0, 3) in[3];  
  6.     out[1] M(1, 0) in[0] M(1, 1) in[1] M(1, 2) in[2] M(1, 3) in[3];  
  7.     out[2] M(2, 0) in[0] M(2, 1) in[1] M(2, 2) in[2] M(2, 3) in[3];  
  8.     out[3] M(3, 0) in[0] M(3, 1) in[1] M(3, 2) in[2] M(3, 3) in[3];  
  9. #undef M  
  10.  
  11.   
  12. GLint gluProject(GLdouble objx, GLdouble objy, GLdouble objz  
  13.                 const GLdouble model[16], const GLdouble proj[16], const GLint viewport[4]  
  14.                 GLdouble winx, GLdouble winy, GLdouble winz)  
  15.  
  16.       
  17.     GLdouble objCoor[4];  
  18.     GLdouble objProj[4], objModel[4];  
  19.   
  20.       
  21.     // 4x4 matrix must be multi to dimension vector( it matrix)  
  22.     // so we need to put the original vertex to 4D vector  
  23.     objCoor[0] objx;  
  24.     objCoor[1] objy;  
  25.     objCoor[2] objz;  
  26.     objCoor[3] 1.0;  
  27.   
  28.     // 由于原来的向量位于标准基向量(1, 0, 0), (0, 1, 0), (0, 0, 1)中,所以需要先转换到当前的模型矩阵中  
  29.     transform_point(objModel, model, objCoor);  
  30.   
  31.     // 然后将模型矩阵中的顶点转换到投影矩阵所在坐标系的矩阵中  
  32.     transform_point(objProj, proj, objModel);  
  33.   
  34.     // scale matrix  
  35.       
  36.   
  37.       
  38.     if (objProj[3] == 0.0)  
  39.         return GL_FALSE;  
  40.   
  41.     objProj[0] /= objProj[3];  
  42.     objProj[1] /= objProj[3];  
  43.     objProj[2] /= objProj[3];  
  44.   
  45.       
  46.     // 由于投影矩阵投影在[-1, 1]之间,所以需要将转换后的投影坐标放置到[0, 1]之间  
  47.     // 最后再在一个offset 矩形中转换为屏幕坐标就可以了(viewport[4]可以简单的认为一个offset矩形)  
  48.   
  49. #define SCALE_FROM_0_TO_1(_pt)  (((_pt) 1)/2)  
  50.     objProj[0] SCALE_FROM_0_TO_1(objProj[0]);  
  51.     objProj[1] SCALE_FROM_0_TO_1(objProj[1]);  
  52.     objProj[2] SCALE_FROM_0_TO_1(objProj[2]);  
  53. #undef SCALE_FROM_0_TO_1  
  54.   
  55.     *winx viewport[0] objProj[0] viewport[2];  
  56.     *winy viewport[1] objProj[1] viewport[3];  
  57.   
  58.       
  59.     *winz objProj[2];  
  60.     return GL_TRUE;  
  61.  
[cpp]   view plain copy
  1.   


基本的思路就是:

1、将输入的顶点,通过模型视图矩阵,变换到模型视图矩阵的坐标系中;

2、将模型视图矩阵中的顶点,再变换到投影矩阵中;

3、将顶点缩放到[0, 1]的映射区间中;

4、通过视口的位置和大小,计算出当前3D顶点中的屏幕坐标(2D坐标)


gluUnproject

其实gluUnproject和gluProject是非常类似的,代码我暂时没有去找,但我认为应该是这样的(其实就是gluPorject反过来的过程,只是有一些数学运算要注意一下):
1、首先,需要将输入的顶点,通过视口变换到[0, 1]之间;
2、然后将顶点缩放到[-1, 1]之间,就是上面代码中的scaleMat矩阵的逆矩阵
3、然后乘上投影矩阵的逆矩阵;
4、最后就是乘上模型视图矩阵的逆矩阵;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值