拾取是图形学里一个很常用的应用,在3D世界里选中我们想要的东西,枪战游戏中判断子弹是否射中敌人。
这里我们讲下如何实现一个精确的拾取碰撞,不仅检测是否射中了这个物体,更进一步的返回射中了这个物体的上哪个三角形。在《COD》等比较优秀的枪战游戏中,我们都可以看到子弹是射中敌人身体的不同部位,敌人的身体会做出不同的反应。
然后我们看看如何实现一个基于GPU的拾取,把拾取的所有计算都映射到GPU上去。这里我们分别用GeometryShader和ComputeShader来做一个实现。这一篇先用GeometryShader来实现。
程序主要是如果点击鼠标,选中了哪个三角形,就绘制它,其它三角形就以线框的方式绘制。程序截图如下:
文章下面先讲下拾取的算法,然后再来讲如何在GeometryShader上实现这个算法。
精确拾取算法说白了就判断一个射线是否与一个三角形相交。我们设T(u,v,w)=uA+vB+wC定义了三角形ABC平面上的点,其中(u,v,w)为该点的质心坐标且有u+v+w=1,当且仅当该点的质心坐标满足0<=u,v,w<=1时,点T位于三角形ACB里面。设u=1-v-w,则T(v,w)=A+v(B-A)+u(C-A)。
令两端点P,Q构成的有向线段定位为R(t)=P+t(Q-P),0<=t<=1.
如果拾取到了,或者说我们射出去的射线PQ选中了三角形,那么有
T(v,w)=R(t)
则
(P-Q)t+(B-A)v+(C-A)w=P-A变成矩阵形式:
[(P-Q) (B-A) (C-A)] [t v w]'=[P-A] (住 ' 表示转置)
用克莱姆法则对t,v,w进行求解:
t=det[(P-A) (B-A ) (C-A)]/det[(P-Q) (B-A) (C-A)] (注det表示行列式)
v=det[(P-Q) (P-A ) (C-A)]/det[(P-Q) (B-A) (C-A)] (注det表示行列式
w=det[(P-Q) (B-A ) (P-A)]/det[(P-Q) (B-A) (C-A)] (注det表示行列式)
具体的负责判断拾取的