﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-life02-随笔分类-游戏开发</title><link>http://www.cppblog.com/life02/category/11643.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 26 Sep 2009 06:17:31 GMT</lastBuildDate><pubDate>Sat, 26 Sep 2009 06:17:31 GMT</pubDate><ttl>60</ttl><item><title>如何判断一点在三角形内（转）</title><link>http://www.cppblog.com/life02/archive/2009/09/25/97213.html</link><dc:creator>life02</dc:creator><author>life02</author><pubDate>Fri, 25 Sep 2009 02:22:00 GMT</pubDate><guid>http://www.cppblog.com/life02/archive/2009/09/25/97213.html</guid><wfw:comment>http://www.cppblog.com/life02/comments/97213.html</wfw:comment><comments>http://www.cppblog.com/life02/archive/2009/09/25/97213.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/life02/comments/commentRss/97213.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/life02/services/trackbacks/97213.html</trackback:ping><description><![CDATA[<p><a href="http://www.cnblogs.com/cgwolver/archive/2009/03/26/1257611.html">http://www.cnblogs.com/cgwolver/archive/2009/03/26/1257611.html</a><br>假定在右手坐标系中的三角形3点坐标为A，B，C，判断P是否在ABC之内</p>
<p>( 主要来自 3D引擎研发QQ群（38224573 ）的各位朋友的讨论 ，我仅仅算做个总结吧，特别感谢各位朋友的热情支持。 ）</p>
<p>方法1：三个Perplane的方法</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 设AB，BC，AC边上的垂直平面为Perplane[3]，垂直朝向内侧的法向为n[3]</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1）先根据任意两边叉出法向N</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N = AB.CrossProduct(AC); </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N.Normalize();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D = A.DotProduct( N );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2）如果P在三角形所在平面之外，可直接判定不在平面之内（ 假定方程为 ax+by+cz+d = 0 )</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( P.DotProduct( N ) + D &gt; 0 ) return false; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3）然后法向和各边叉出垂直平面的法向</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n[0] = N.CrossProduct(AB); //朝向内侧</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n[0].Normalize();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Perplane[0].dist = A.DotProduct(n[0]); </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Perplane[0].normal = n[0];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同样方法求得Perplane[1],Perlane[2];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3）因为三个Perplane都朝向三角形内侧，P在三角形内的条件是同时在三个Perplane前面；如果给定点P在任意一个垂直平面之后，那么可判定P在三角形外部</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for( int i = 0;i&lt;3;j++ )</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( P.DotProduct( Perplane[i].normal ) + Perplane[i].dist &lt; 0 )</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;//如果P没有在任意一条边的外面，可判断定在三角形之内，当然包括在边上的情况</p>
<p>方法2：三个部分面积与总面积相等的方法</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; S(PAB) + S(PAC) + S( PBC) = S(ABC) 则判定在三角形之内</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用矢量代数方法计算三角形的面积为 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; S = 1/2*|a|*|b|*sin(theta) </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 1/2*|a|*|b|*sqrt(1-cos^2(theta)) </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 1/2*|a|*|b|*sqrt(1- (a.DotProduct(b)/(|a|*|b|))^2);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另一种计算面积的方法是 S = 1/2*|a.CrossProduct(b)|</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比较一下，发现后者的精确度和效率都高于前者，因为前者需要开方和求矢量长度，矢量长度相当于一次点乘，三个点乘加一个开方，显然不如</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后者一次叉乘加一次矢量长度（注，一次叉乘计算相当于2次点乘，一次矢量长度计算相当于一次点乘），后者又对又快。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; S(ABC)&nbsp; = AB.CrossProduct(AC)；//*0.5;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; S(PAB)&nbsp; = PA.CrossProduct(PB)；//*0.5;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; S(PBC)&nbsp; = PB.CrossProduct(PC)；//*0.5;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; S(PAC)&nbsp; = PC.CrossProduct(PA)；//*0.5;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( S(PAB) + S(PBC) + S(PAC) == S(ABC)&nbsp; )</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另一种计算三角形面积的矢量方法是 1/2*a.CrossProdcuct(b) ，CrossProduct = ( y1*z2 - y2*z1 , x1*z2 - x2*z1, x1*y2 - x2*z1 )</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以看到CrossProduct 的计算要比DotProduct多3个乘法计算，效率没有上面的方法高</p>
<p><br>方法3：三个向量归一化后相加为0</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个方法很怪异，发现自<a href="http://flipcode.spaces.live.com/blog/cns!8e578e7901a88369!903.entry">http://flipcode.spaces.live.com/blog/cns!8e578e7901a88369!903.entry</a> 下面的一个回帖</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img height=196 alt="" src="http://www.cppblog.com/images/cppblog_com/life02/1.jpg" width=198 border=0><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如上图三角形ABC，P为AB外侧一点，N1，N2，N3 分别为BP，AP，CP的归一化矢量；NM为N1，N2夹角的角平分线</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以看出角A-P-B是三角形内角，必然小于180度，那么角N1-P-N2等于A-P-B；NM是N1-P-N2的角平分线，那么角B-P-N等于角N-P-A，而CPN必然小于其中一个，</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 即小于180/2 = 90度。结论是角N1，N2的合矢量方向与N3的夹角为锐角。所以N1，N2，N3的合向量模大于1.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里注意，N3不一定在N1，N2之间，不能假定N2-P-N3 和N3-P-N1这两个角一定是锐角</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同样可以推导出如果P在三角形内，N1+N2+N3必然小于0；若N1+N2+N3 = 0则P在三角形的边上。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有没有更简单的推导方法？</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个方法看起来很精巧，但是善于优化的朋友会立刻发现，三个矢量归一化，需要三个开方。迭代式开方太慢了，而快速开方有的时候又不满足精度要求。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;方法4：重心坐标之和为1</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BaryCenter = ( S(PAB)/S(PABC),S(PBC)/S(PABC),S(PAC)/S(PABC)) // 点P在三角形内的重心坐标</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( BaryCenter.x + BaryCenter.y + BaryCenter.z &gt;0.f )</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中S(PAB)，S(ABC)，S(PBC)，S(PBC) 用上述的方法二种提到的计算三角形面积方法计算。 </p>
<p>综合比较</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 方法1必须求叉乘，虽然可以通过首先排除不在平面内的点，但是后面仍要求三个叉乘和3个点乘（当然还可排除法优化）</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 方法2看起来之需要求4个点乘，如果用叉乘方法计算面积，可能会导致效率低下</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 方法3是看起来是最精巧的方法，但是效率也不能保证...3个开方</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 方法4和方法2的效率差不多</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/boyzk2008/archive/2009/08/07/4421106.aspx">http://blog.csdn.net/boyzk2008/archive/2009/08/07/4421106.aspx</a></p>
<img src ="http://www.cppblog.com/life02/aggbug/97213.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/life02/" target="_blank">life02</a> 2009-09-25 10:22 <a href="http://www.cppblog.com/life02/archive/2009/09/25/97213.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>game c++ （转）</title><link>http://www.cppblog.com/life02/archive/2009/08/31/94893.html</link><dc:creator>life02</dc:creator><author>life02</author><pubDate>Mon, 31 Aug 2009 08:27:00 GMT</pubDate><guid>http://www.cppblog.com/life02/archive/2009/08/31/94893.html</guid><wfw:comment>http://www.cppblog.com/life02/comments/94893.html</wfw:comment><comments>http://www.cppblog.com/life02/archive/2009/08/31/94893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/life02/comments/commentRss/94893.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/life02/services/trackbacks/94893.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/life02/archive/2009/08/31/94893.html'>阅读全文</a><img src ="http://www.cppblog.com/life02/aggbug/94893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/life02/" target="_blank">life02</a> 2009-08-31 16:27 <a href="http://www.cppblog.com/life02/archive/2009/08/31/94893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>