Direct3D拾取(Pick)全攻略

今天上午打算完成的,没想到出了个问题,搞了一天没有搞定,到现在才发现这个错误,直接晕倒。
概念就不介绍了,直接先上数学。

重心坐标:设三角形所在平面一点P的重心坐标为(a,b,c)则 a+b+c = 1;
(三角形所在平面的所有点都可以用重心坐标表示,如果在三角形外面,则:
a,b,c三个数当中必有一个为负数!!!!)
这一点P的3D坐标为(Px, Py, Pz);

三角形的三个点为(顺时针)v0, v1, v2 则 v0*a + v1*b + v2*c = (Px, Py, Pz); (前面v0,v1,v2是点注意了。)
因为:a+b+c = 1;
所以: v0*a + v1*b + v2*c = v0 * (1-b-c) + v1*b + v2*c ;
                                      = b * (v1 - v0) + c * (v2 - v0) + v0; ----------------- 1

假设射线方程式F(x,y,z) = Orgin + rayVec * t; --------------------------------------2

则射线和P点的交点方程(由1和2): Orgin + rayVec * t = b * (v1 - v0) + c * (v2 - v0) + v0;
列成矩阵形式: 设v1 - v0 = edge1;       v2 - v0 = edge2;
                    Orgin + rayVec * t = b * edge1+ c * edge2 + v0
        变一下型:b * edge1 - rayVec * t + c * edge2 = Orgin - v0;
        我们设fDist = -t;       去掉负号;
                    b * edge1 - rayVec * fDist + c * dege2 = Orgin - v0;

矩阵 b * edge1.x - rayVec.x * fDist + c * edge2.x = (Orgin - v0).x;
   b * edge1.y - rayVec.y * fDist + c * edge2.y = (Orgin - v0).y;
   b * edge1.z - rayVec.z * fDist + c * edge2.z = (Orgin - v0).z;
使用克莱姆法则求b , fDist, c ;
                  |edge1.x rayVec.x edge2.x|
分母det =   |edge1.y rayVec.y edge2.y|  = Dot(edge1, Cross(rayVec, edge2))(是个公式,记住了)
                  |edge1.z rayVec.z edge2.z|
分子
                                   |(Orgin - v0).x rayVec.x edge2.x|
未知数b的克莱姆分子     = |(Orgin - v0).y rayVec.y edge2.y|  = Dot((Orgin - v0), Cross(rayVec, edge2))
                                   |(Orgin - v0).z rayVec.z edge2.z|

                                   |edge1.x (Orgin - v0).x edge2.x|
未知数c的克莱姆分子     = |edge1.y (Orgin - v0).y edge2.y|  = Dot(edge1, Cross((Orgin - v0), edge2));
                                   |edge1.z (Orgin - v0).z edge2.z|

                                    |edge1.x rayVec.x (Orgin - v0).x|
未知数t的克莱姆分子     =  |edge1.y rayVec.y (Orgin - v0).y|  = Dot(edge1, Cross(rayVec, (Orgin - v0));
                                    |edge1.z rayVec.z (Orgin - v0).z|

3个分子分别和det相除就行了.
现在看看Ms的代码:(貌似交换了列的顺序,和上面的稍微有些出入)
Code
下面这个代码直接按公式写。
Code


求交就完了,剩下的, Orgin 和 rayVec

屏幕上的点

齐次裁剪空间:projPt.x = (screenPt.x-screenWidth/2)/screenWidth*2; (公式1

齐次裁剪空间projPt.y = (screenPt.y-screenHeight/2)/screenHeight*2; (公式2)

projPt.z = 1.0f(近裁减面的值);

投影矩阵 m_11 x缩放, m_22 y缩放

Orgin在视点空间的坐标为(0,0,0);

它们乘以投影的逆矩阵:Orgin * InverseMatProj; (视点空间)

                    projPtInverseMatProj; (视点空间)

转换到模型空间,乘以InverseMatWorldView;

如果你熟悉这几种矩阵变换的话,可以直接操作上面的计算。

最后将它们的值带入即可。



Code
分享知识,共同进步。如需转载注明http://www.cnblogs.com/ttthink
posted @ 2009-09-25 22:58  ttthinks  阅读(1554)  评论(0编辑  收藏  举报