• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天行健 君子當自強而不息

            幾何檢測(4)

            新建網頁 1

             

            球和平面的相交性檢測

            球和平面的靜態檢測相對容易一些,可以用公式12.14來計算球心到平面的距離。如果距離小于球半徑,那么它們相交。實際上還能作一種更靈活的檢測,這種檢測把相交分為球完全在平面正面,完全在背面,跨平面等三種情況。仔細分析程序清單13.2

                Listing 13.2: Determining which side of a plane a sphere is on
               
               
            // Given a sphere and plane, determine which side of the plane
                // the sphere is on.
                //
                // Return values:
                //
                // < 0 Sphere is completely on the back
                // > 0 Sphere is completely on the front
                // 0 Sphere straddles plane
               
            int classifySpherePlane(
                  
            const Vector3 &planeNormal, // must be normalized
               
              float planeD, // p * planeNormal = planeD
               
              const Vector3 &sphereCenter, // center of sphere
               
              float sphereRadius // radius of sphere
               

                {
                  
            // Compute distance from center of sphere to the plane
               
              float d = planeNormal * sphereCenter – planeD;
               
                  
            // Completely on the front side?
               
              if (d >= sphereRadius) 
                    
            return +1;
               
                  
            // Completely on the back side?
               
              if (d <= –sphereRadius) 
                    
            return –1;
               
                  
            // Sphere intersects the plane
               
              return 0;
                }

            動態檢測要稍微復雜一些。設平面為靜止的,球作所有的相對位移。

            平面的定義方式一如既往,用標準形式p . n = dn為單位向量。球由半徑r和初始球心位置c定義。球的位移,由單位向量d指明方向,L代表位移的距離。t從0變化到L,用直線方程c+td計算球心的運動軌跡。如圖13.13所示:

            不管在平面上的哪一點上發生相交,在球上的相交點總是固定的,認識到這一點能大大簡化問題。用c-rn來計算交點,如圖13.14所示:

            現在我們知道了球上的相交點,就可以利用射線與平面相交性檢測的方法,替換掉公式13.6中的p0,得到公式13.9

            射線和三角形的相交性檢測

            在圖形學和計算幾何中射線與三角形的相交性檢測是非常重要的。因為缺乏射線和復雜物體間相交性檢測的方法,我們通常用三角網格代表(或至少是近似代表)物體表面,再作射線和三角網格的相交性檢測。第一步是計算射線和包含該三角形的平面的交點,第二步是通過計算交點的重心坐標,來判斷它是否在三角形中。

            為了使測試效率盡可能高,要使用下列技巧:

            (1)在檢測中盡可能地返回負值(沒有相交),這稱作"提前結束(early out)"

            (2)盡可能地延遲昂貴的數學運算,如除法。有兩個原因:第一,如果并不需要昂貴運算的結果,比如說遇到了提前結束的情況,那么執行這些運算的時間就白白浪費了。第二,它給了編譯器更多的空間以利用現代處理器的指令管道的優點。在準備除法運算時,它產生執行其他測試的代碼(可能導致提前結束)。所以,在執行期間,如果確實需要除法運算的結果,該結果可能已經被計算出來,或至少已經部分被計算出來了。

            (3)只檢測與三角形正面的相交,這幾乎可以節省一半的檢測時間。

                // Ray-triangle intersection test.
                //
                // Algorithm from Didier Badouel, Graphics Gems I, pp 390-393
               
            float rayTriangleIntersect(
                    
            const Vector3 &rayOrg,        // origin of the ray
               
                const Vector3 &rayDelta,    // ray length and direction
               
                const Vector3 &p0,            // triangle vertices
               
                const Vector3 &p1,            // .
               
                const Vector3 &p2,            // .
               
                float minT)                    // closest intersection found so far. (Start with 1.0)
               
            {
                    
            // We'll return this huge number if no intersection is detected
               
                const float kNoIntersection = 1e30f;
               
                    
            // Compute clockwise edge vectors.
               
                Vector3 e1 = p1 – p0;
                    Vector3 e2 = p2 – p1;
               
                    
            // Compute surface normal. (Unnormalized)
               
                    Vector3 n = crossProduct(e1, e2);
               
                    
            // Compute gradient, which tells us how steep of an angle
                    // we are approaching the *front* side of the triangle
               
                float dot = n * rayDelta;
               
                    
            // Check for a ray that is parallel to the triangle or not pointing toward the front face 
                    // of the triangle.
                    //
                    // Note that this also will reject degenerate triangles and rays as well. We code this in a 
                    // very particular way so that NANs will bail here. (This does not behave the same as 
                    // "dot >= 0.0f" when NANs are involved.)
               
                if (!(dot < 0.0f)) 
                        
            return kNoIntersection;
                    
                    
            // Compute d value for the plane equation. We will use the plane equation with d on the right side:
                    //
                    // Ax + By + Cz = d
               
                float d = n * p0;
               
                    
            // Compute parametric point of intersection with the plane containing the triangle, checking at the 
                    // earliest possible stages for trivial rejection.
               
                float t = d – n * rayOrg;
               
                    
            // Is ray origin on the backside of the polygon? Again, we phrase the check so that NANs will bail.
               
                if (!(t <= 0.0f)) 
                        
            return kNoIntersection;
                    
                    
            // Closer intersection already found? (Or does ray not reach the plane?)
                    //
                    // since dot < 0:
                    //
                    // t/dot > minT
                    //
                    // is the same as
                    //
                    // t < dot * minT
                    //
                    // (And then we invert it for NAN checking)
               
                if (!(t >= dot * minT)) 
                        
            return kNoIntersection;
                    
                    
            // OK, ray intersects the plane. Compute actual parametric point of intersection.
               
                t /= dot;
               
                    assert(t >= 0.0f);
                    assert(t <= minT);
               
                    
            // Compute 3D point of intersection
               
                Vector3 p = rayOrg + rayDelta * t;
               
                    
            // Find dominant axis to select which plane
                    // to project onto, and compute u's and v's
               
                float u0, u1, u2;
                    
            float v0, v1, v2;
               
                    
            if (fabs(n.x) > fabs(n.y)) 
                    {
                        
            if (fabs(n.x) > fabs(n.z)) 
                        {
                            u0 = p.y – p0.y;
                            u1 = p1.y – p0.y;
                            u2 = p2.y – p0.y;
                            v0 = p.z – p0.z;
                            v1 = p1.z – p0.z;
                            v2 = p2.z – p0.z;
                        } 
                        
            else 
                        {
                            u0 = p.x – p0.x;
                            u1 = p1.x – p0.x;
                            u2 = p2.x – p0.x;
                            v0 = p.y – p0.y;
                            v1 = p1.y – p0.y;
                            v2 = p2.y – p0.y;
                        }
                    } 
                    
            else 
                    {
                        
            if (fabs(n.y) > fabs(n.z)) 
                        {
                            u0 = p.x – p0.x;
                            u1 = p1.x – p0.x;
                            u2 = p2.x – p0.x;
                            v0 = p.z – p0.z;
                            v1 = p1.z – p0.z;
                            v2 = p2.z – p0.z;
                        } 
                        
            else 
                        {
                            u0 = p.x – p0.x;
                            u1 = p1.x – p0.x;
                            u2 = p2.x – p0.x;
                            v0 = p.y – p0.y;
                            v1 = p1.y – p0.y;
                            v2 = p2.y – p0.y;
                        }
                    }
               
                    
            // Compute denominator, check for invalid.
               
                float temp = u1 * v2 – v1 * u2;
               
                    
            if (!(temp != 0.0f)) 
                        
            return kNoIntersection;
                    
                    temp = 1.0f / temp;
               
                    
            // Compute barycentric coords, checking for out-of-range at each step
               
                float alpha = (u0 * v2 – v0 * u2) * temp;
               
                    
            if (!(alpha >= 0.0f)) 
                        
            return kNoIntersection;
                    
                    
            float beta = (u1 * v0 – v1 * u0) * temp;
               
                    
            if (!(beta >= 0.0f)) 
                        
            return kNoIntersection;
                    
                    
            float gamma = 1.0f - alpha - beta;
               
                    
            if (!(gamma >= 0.0f)) 
                        
            return kNoIntersection;
                    
                    
            // Return parametric point of intersection
               
                return t;
                }

            還有一個能優化昂貴計算的策略沒體現在上述代碼中:即預先計算結果。如果像多邊形向量這樣的值預先被計算出來的話,就可以采用更加優化的策略。

             

            射線和AABB的相交性檢測

            檢測AABB和射線的相交性非常重要,因為根據檢測的結果可以避免對更復雜物體的測試。(例如,我們要檢測射線與多個由三角網格組成的物體的相交性,可以先計算射線和三角網格的AABB的相交性。有時候可以一次就排除整個物體,而不必去檢測這個物體的所有三角形。)

            Woo提出一種方法,先判斷矩形邊界框的哪個面會相交,再檢測射線與包含這個面的平面的相交性。如果交點在盒子中,那么射線與矩形邊界框相交,否則不存在相交。

            cAABB3中rayIntersect()就是用Woo的技術來實現的。

                //---------------------------------------------------------------------------
                // Parametric intersection with a ray.  Returns parametric point
                // of intsersection in range 01 or a really big number (>1) if no
                // intersection.
                //
                // From "Fast Ray-Box Intersection," by Woo in Graphics Gems I, page 395.
                //
                // See 12.9.11
                //---------------------------------------------------------------------------
               
            float AABB3::rayIntersect(const Vector3& rayOrg,        // origin of the ray
               
                                      const Vector3& rayDelta,        // length and direction of the ray
               
                                          Vector3* returnNormal) const    // optionally, the normal is returned
               
            {
                    
            // We'll return this huge number if no intersection
               
                const float kNoIntersection = 1e30f;
               
                    
            // Check for point inside box, trivial reject, and determine parametric distance to each front face.
               
                bool inside = true;
               
                    
            float xt, xn;
               
                    
            if (rayOrg.x < min.x) 
                    {
                        xt = min.x - rayOrg.x;
                        
            if (xt > rayDelta.x) 
                            
            return kNoIntersection;
               
                        xt /= rayDelta.x;
                        inside = 
            false;
                        xn = -1.0f;
                    } 
                    
            else if (rayOrg.x > max.x) 
                    {
                        xt = max.x - rayOrg.x;
                        
            if (xt < rayDelta.x) 
                            
            return kNoIntersection;
               
                        xt /= rayDelta.x;
                        inside = 
            false;
                        xn = 1.0f;
                    } 
                    
            else
                        xt = -1.0f;    
               
                    
            float yt, yn;
               
                    
            if (rayOrg.y < min.y) 
                    {
                        yt = min.y - rayOrg.y;
                        
            if (yt > rayDelta.y) 
                            
            return kNoIntersection;
               
                        yt /= rayDelta.y;
                        inside = 
            false;
                        yn = -1.0f;
                    } 
                    
            else if (rayOrg.y > max.y) 
                    {
                        yt = max.y - rayOrg.y;
                        
            if (yt < rayDelta.y) 
                            
            return kNoIntersection;
               
                        yt /= rayDelta.y;
                        inside = 
            false;
                        yn = 1.0f;
                    } 
                    
            else 
                        yt = -1.0f;    
               
                    
            float zt, zn;
               
                    
            if (rayOrg.z < min.z) 
                    {
                        zt = min.z - rayOrg.z;
                        
            if (zt > rayDelta.z) 
                            
            return kNoIntersection;
               
                        zt /= rayDelta.z;
                        inside = 
            false;
                        zn = -1.0f;
                    } 
                    
            else if (rayOrg.z > max.z) 
                    {
                        zt = max.z - rayOrg.z;
                        
            if (zt < rayDelta.z) 
                            
            return kNoIntersection;
               
                        zt /= rayDelta.z;
                        inside = 
            false;
                        zn = 1.0f;
                    } 
                    
            else 
                        zt = -1.0f;    
               
                    
            // Inside box?
               

                    
            if (inside) 
                    {
                        
            if (returnNormal != NULL) 
                        {
                            *returnNormal = -rayDelta;
                            returnNormal->normalize();
                        }
               
                        
            return 0.0f;
                    }
               
                    
            // Select farthest plane - this is
                    // the plane of intersection.
               

                    
            int which = 0;
                    
            float t = xt;
               
                    
            if (yt > t) 
                    {
                        which = 1;
                        t = yt;
                    }
               
                    
            if (zt > t) 
                    {
                        which = 2;
                        t = zt;
                    }
               
                    
            switch (which) 
                    {
                    
            case 0: // intersect with yz plane
               
                  {
                        
            float y = rayOrg.y + rayDelta.y * t;
               
                        
            if (y < min.y || y > max.y) 
                            
            return kNoIntersection;
               
                        
            float z = rayOrg.z + rayDelta.z * t;
                        
            if (z < min.z || z > max.z) 
                            
            return kNoIntersection;
               
                        
            if (returnNormal != NULL) 
                        {
                            returnNormal->x = xn;
                            returnNormal->y = 0.0f;
                            returnNormal->z = 0.0f;
                        }
                      } 
                      
            break;
               
                    
            case 1: // intersect with xz plane
               
                  {
                        
            float x = rayOrg.x + rayDelta.x * t;
                        
            if (x < min.x || x > max.x) 
                            
            return kNoIntersection;
               
                        
            float z = rayOrg.z + rayDelta.z * t;
                        
            if (z < min.z || z > max.z) 
                            
            return kNoIntersection;
               
                        
            if (returnNormal != NULL) 
                        {
                            returnNormal->x = 0.0f;
                            returnNormal->y = yn;
                            returnNormal->z = 0.0f;
                        }
               
                      } 
                      
            break;
               
                    
            case 2: // intersect with xy plane
               
                  {
                        
            float x = rayOrg.x + rayDelta.x * t;
                        
            if (x < min.x || x > max.x) 
                            
            return kNoIntersection;
               
                        
            float y = rayOrg.y + rayDelta.y * t;
                        
            if (y < min.y || y > max.y) 
                            
            return kNoIntersection;
               
                        
            if (returnNormal != NULL) 
                        {
                            returnNormal->x = 0.0f;                                
                            returnNormal->y = 0.0f;
                            returnNormal->z = zn;
                        }
                      } 
                      
            break;
                    }
               
                    
            // Return parametric point of intersection
               
                return t;
                }

            posted on 2008-02-27 14:23 lovedday 閱讀(1229) 評論(0)  編輯 收藏 引用

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            青青草原综合久久大伊人| 久久这里都是精品| 99久久无色码中文字幕| 9191精品国产免费久久| 久久影院午夜理论片无码| 久久人人爽人人爽人人片av麻烦| 久久精品国产亚洲av水果派| 久久国产视频99电影| 久久久国产乱子伦精品作者| 日本精品久久久中文字幕| 久久精品国产亚洲AV无码娇色| 一本大道加勒比久久综合| 精品一二三区久久aaa片| 国产精品成人99久久久久| 一本色道久久综合狠狠躁| 日韩中文久久| 久久人人爽人人精品视频| 久久久久青草线蕉综合超碰| 91久久精品无码一区二区毛片| 欧美亚洲国产精品久久| 久久久精品波多野结衣| 99久久免费国产精品热| 久久亚洲中文字幕精品有坂深雪| 91麻豆国产精品91久久久| 91久久九九无码成人网站| 久久久久亚洲AV片无码下载蜜桃| 人人狠狠综合久久亚洲| 久久天天躁狠狠躁夜夜2020| 久久久91精品国产一区二区三区| 亚洲成色WWW久久网站| 成人久久久观看免费毛片| 97久久婷婷五月综合色d啪蜜芽| 亚洲欧美另类日本久久国产真实乱对白| 久久亚洲国产成人精品无码区| 久久久久人妻一区精品性色av| 无码AV中文字幕久久专区| 亚洲国产精品无码久久久秋霞2| 国产精品久久久久久久人人看| 久久精品国产色蜜蜜麻豆| 伊人久久大香线蕉av一区| 色欲综合久久中文字幕网|