OpenGL面片拣选

OpenGL中,对象本身经过世界变换、观察变换、投影变换、剪切变换,显示到屏幕。通过鼠标点击,获取的是屏幕坐标系的二维坐标(x,y)。需要将屏幕坐标反变换,计算世界坐标系中拣选射线方程。

(1)建立屏幕ndc坐标,即将整个屏幕进行映射,x方向范围-1到1,中心为0,y方向范围-1到1,中心为0。注意:x方向右正左负,y方向上正下负。

ndcx = (2.0f * x) / fWidth - 1.0f;
ndcy = 1.0f - (2.0f * y) / fHeight;

ndcz = 1.0f;

(2)将投影变换的逆变换作用在该坐标系上。若mxPorj为投影矩阵,则:

        mxInvProj=mxProj.inversed();

        v4World=mxInvProj*QVector4D(ndcx,ndcy,ndcz,1.0);

这里,我们将变换后的向量写为v4World,是指该向量含义在世界坐标系中意义非常清晰:可理解为将摄像机置于世界坐标系原点,鼠标在远平面上的拣选点。so,拣选向量即为:v4World前三维坐标单位化,记为n。

(3)假设模型在绘图前使用了mxTrans=mxView*mxModel进行了变换,将其放在我们能看到的地方,而实际上,模型真正的位置在其本身节点坐标描述的位置。因此,我们需要将拣选射线进行变换,逆着mxTrans变换后,作用于拣选射线上。如,我们让模型右上角对着摄像机,可以理解为将摄像机转动到模型右上角。

视点:vCam,原点,重组为4维向量,w=1,变换为v4Eye=mxTrans(-1)*vCam;

拣选方向:n,重组为4维向量,w=0(不参与平移变换),变换为v4To=mxTrans(-1)*n

(4)计算射线与面片交点。变换后,用v4Eye中的w值除前三个坐标,重组为三维向量P,该项量为坐标系中眼睛的位置;v4To区前三维坐标整理为m,并单位化,该项量为眼睛观察的方向。

(5)拣选面片。使用模型本身节点数据,无需任何变换。若有面,过空间一点Q,法线方向为k。则首先将直线方程写为:

x=p1+m1*r

y=p2+m2*r

z=p3+m3*r

平面方程为:

k1*(q1-p1)+k2*(q2-p2)+k3*(q3-p3)=0

联立上述方程得到 r=(Q-P)*k/(m*k),均为向量运算,*为点乘。

理解r的几何意义为:从P点想m方向行走的距离,因此,r应当为正值才和面片有真正的交点(r为负时,表示射线反向与面片相交,显然不是我们想要的结果)

(5)判断交点是否在面片内。

如上图,H1和H2有什么不同?我们用向量与向量的叉乘解决问题。

内部点H1,向量H1P1×P1P2、H1P2×P2P3、H1P3×P3P1 方向均指向 外面,而外部点H2,向量H2P1×P1P2、H2P2×P2P3、H2P3×P3P1,总有一个方向指向 里面。注意叉乘顺序,按照规则始终沿着同样的方向叉乘,叉乘后单位化,判断三个向量是否均相同,如果有一个和另外两个不一样,则是外点。