• <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>

            牽著老婆滿街逛

            嚴(yán)以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            一種3D游戲碰撞檢測(cè)解決方案

            轉(zhuǎn)載自:http://www.cnblogs.com/cproom/archive/2007/12/15/608732.html




                    碰撞檢測(cè)在3D游戲中至關(guān)重要,好的碰撞檢測(cè)要求人物在場(chǎng)景中可以平滑移動(dòng),遇到一定高度內(nèi)的臺(tái)階可以自動(dòng)上去,而過(guò)高的臺(tái)階則把人擋住,遇到斜率較小的斜坡可以上去,斜率過(guò)大則把人擋住,在各種前進(jìn)方向被擋住的情況下都要盡可能地讓人物沿合理的方向滑動(dòng)而不是被迫停下。在滿足這些要求的同時(shí)還要做到足夠精確和穩(wěn)定,防止人物在特殊情況下穿墻而掉出場(chǎng)景。

                    碰撞檢測(cè)做得好了是應(yīng)該的,不易被人注意到,因?yàn)檫@符合我們?nèi)粘I钪械某WR(shí)。做得差了卻很容易讓人發(fā)現(xiàn),人物經(jīng)常被卡住不能前進(jìn)或者人物穿越了障礙。所以大部分人都覺(jué)得寫(xiě)碰撞檢測(cè)代碼是件吃力不討好的事情,算法復(fù)雜、容易出bug、不容易出彩。下面還是回到正題,看看我們?cè)撊绾谓鉀Q這個(gè)難題。

                    早期3D游戲的碰撞檢測(cè)多數(shù)基于格子或者BSP樹(shù),基于格子的系統(tǒng)實(shí)現(xiàn)簡(jiǎn)單但精度不夠,不屬于嚴(yán)格意義的3D碰撞檢測(cè)。基于BSP樹(shù)的碰撞檢測(cè)一度十分流行,算法基本已經(jīng)成熟定型,但它的固有缺點(diǎn)卻使它不太適合現(xiàn)在的游戲。BSP樹(shù)需要很長(zhǎng)的預(yù)處理時(shí)間不適合加載時(shí)計(jì)算,BSP劃分經(jīng)常會(huì)產(chǎn)生原多邊形數(shù)三到四倍的多邊形,考慮到不用保存法線、顏色、uv等信息也要增加將近一倍的資源容量,在一個(gè)大的游戲中將模型資源的容量從200M增加到400M相信是大部分人都不愿接受的。目前對(duì)于任意復(fù)雜三角形集合(mesh)的碰撞檢測(cè)多數(shù)基于BVTreebounding volume tree,具體可以是aabb treeobb tree或者K-dop tree,這也是當(dāng)今各種物理引擎和碰撞檢測(cè)引擎流行的做法。

                    上面是碰撞檢測(cè)按數(shù)據(jù)結(jié)構(gòu)不同的分類,按檢測(cè)方式又可以分為離散點(diǎn)的碰撞檢測(cè)和連續(xù)碰撞檢測(cè)(CCD continuous collision detection)。離散點(diǎn)的碰撞檢測(cè)是指定某一時(shí)刻T的兩個(gè)靜態(tài)碰撞體,看它們之間是否交迭,如果沒(méi)有交迭則返回它們最近點(diǎn)的距離,如果交迭則返回交迭深度,交迭方向等。連續(xù)碰撞檢測(cè)則是分別指定在T1T2兩個(gè)時(shí)刻兩個(gè)碰撞體的位置,看它們?cè)谟?span>T1運(yùn)動(dòng)到T2時(shí)刻的過(guò)程中是否發(fā)生碰撞,如果碰撞則返回第一碰撞點(diǎn)的位置和法線。連續(xù)碰撞檢測(cè)是最為自然的碰撞檢測(cè),可以大大方便碰撞響應(yīng)邏輯的編寫(xiě),可以很容易避免物體發(fā)生交迭或者穿越。離散點(diǎn)的碰撞檢測(cè)則沒(méi)有那么友好,當(dāng)檢測(cè)到碰撞時(shí)兩個(gè)物體已經(jīng)發(fā)生了交迭,如果其中有三角形網(wǎng)格對(duì)象那么已經(jīng)有許多三角形發(fā)生了交迭,如何將兩個(gè)交迭的對(duì)象分開(kāi)并按合理的方式運(yùn)動(dòng)是一個(gè)挑戰(zhàn)。雖然連續(xù)碰撞檢測(cè)是最自然的方式,但它的實(shí)現(xiàn)非常復(fù)雜,運(yùn)算開(kāi)銷(xiāo)也很大,所以目前大部分成熟的物理引擎和碰撞檢測(cè)引擎還是采用了基于離散點(diǎn)的碰撞檢測(cè),為了避免物體交迭過(guò)深或者彼此穿越,它們都要采用比較小的模擬步長(zhǎng)。

                    由于碰撞檢測(cè)引擎的復(fù)雜性和對(duì)效率的高要求,我們應(yīng)該盡量使用目前成熟的完整引擎,而不是自己去開(kāi)發(fā)。經(jīng)過(guò)評(píng)估,我決定采用Opcode碰撞檢測(cè)引擎來(lái)做游戲中人物和場(chǎng)景的碰撞檢測(cè)。Opcode的主要功能是用aabb tree管理復(fù)雜三角形集合來(lái)和射線、球體,立方體,另一個(gè)三角形集合等進(jìn)行離散點(diǎn)上的碰撞檢測(cè),如果檢測(cè)到交迭則返回所有發(fā)生交迭的三角形。Opcode的特點(diǎn)是高度的內(nèi)存使用優(yōu)化和極好的效率,ODE物理引擎底層就采用它來(lái)做復(fù)雜三角形mesh的碰撞檢測(cè),Opcode的作者也是NovodeXPhysX前身)物理引擎的核心開(kāi)發(fā)人員,據(jù)說(shuō)NovodeX采用了Opcode的一個(gè)更優(yōu)化版本。由此可見(jiàn)Opcode的成熟與效率。

                    確定了要使用的引擎,下面要討論的算法就和具體引擎無(wú)關(guān)了,適合于任何離散點(diǎn)的碰撞檢測(cè)引擎。我們用AABB包圍盒來(lái)代表場(chǎng)景中的人物,看看如何實(shí)現(xiàn)文章開(kāi)頭所提出的效果。

                     首先解釋一下檢測(cè)地面的方式,沿人物包圍盒的四條豎邊向下投四條射線,射線的終點(diǎn)略低于人物的腳底(也就是說(shuō)射線的長(zhǎng)度是有限的),如果與場(chǎng)景發(fā)生碰撞并且碰撞平面的斜率小于某一值則取得碰撞點(diǎn)的高度,否則視為這條射線沒(méi)有檢測(cè)到地面。將所有射線檢測(cè)到的地面高度最大值作為最后的地面高度,如果四條射線都沒(méi)有檢測(cè)到地面則認(rèn)為人物懸空。

             

            vD = 當(dāng)前幀人物位移

            p0 
            = 人物包圍盒中心當(dāng)前位置

            bOnGroundP1; 
            // 人物是否站在地面

            bOnGroundP3; 
            // 人物是否站在地面

            bOnGround; 
            // 人物是否站在地面

             

            p1 
            = p0 + vD

            在p1位置檢測(cè)地面

            if( 檢測(cè)到地面 )

            {

                 將包圍盒下放到地面得到位置p2

                 bOnGroundP1 
            = true;

            }


            else

            {

                 p2 
            = p1;

                 bOnGroundP1 
            = false;

            }





            測(cè)試p2點(diǎn)的包圍盒是否與場(chǎng)景交迭

            if( 交迭 )

            {

                 取得所有交迭三角形的法線,將它們相加后取平均值,得到法線normal

                 將法線與向上的向量叉乘得到切線方向tangent

                 
            // 計(jì)算人物沿切線滑動(dòng)后的位置,注意這里用p0做計(jì)算。

                 
            // 如果要使滑動(dòng)更平滑可以把p0向法線方向推出一些

                 
            // p3 = p0 + normal * 0.1f + vD.Dot(tangent);

                 p3 
            = p0 + vD.Dot(tangent); 

             

                 在p3位置檢測(cè)地面

                 
            if( 檢測(cè)到地面 )

                 
            {

                     將包圍盒下放到地面得到位置p4

                      bOnGroundP3 
            = true;

                 }


                 Else

                 
            {

                     p4 
            = p3;

                      bOnGroundP3 
            = false;

                 }


             

                 測(cè)試p4點(diǎn)的包圍盒是否與場(chǎng)景交迭

                 
            if( 交迭 )

                 
            {

                     測(cè)試p1點(diǎn)的包圍盒是否與場(chǎng)景交迭

                     
            if( 交迭 )

                     
            {

                          
            // 無(wú)法得到合理的移動(dòng)位置,人物位置保持不變

                          
            // 等待下一幀玩家調(diào)整前進(jìn)方向再做測(cè)試

                          將p0作為人物的新位置

                          bOnGround 
            = true;

                          
            return;

                     }


                     
            else

                     
            {

                          將p1作為人物的新位置

                          bOnGround 
            = bOnGroundP1;

                          
            return;

                     }


                 }


                 Else

                 
            {

                     將p4作為人物的新位置

                     bOnGround 
            = bOnGroundP3;

                      
            return;

                 }


            }


            else

            {

                 將p2作為人物的新位置

                 bOnGround 
            = bOnGroundP1;

                 
            return;

            }

             

             

            上面的算法基本達(dá)到了文章開(kāi)頭所提到的效果,在某些復(fù)雜情況下人物移動(dòng)還有些不流暢,但沒(méi)有發(fā)現(xiàn)人物有穿越障礙物的現(xiàn)象。在大部分情況下人物的新坐標(biāo)都會(huì)由p2點(diǎn)返回,最壞情況是人物被卡住返回p0點(diǎn)。在P4 3.0G的機(jī)器上可以支持120個(gè)人物在最壞情況下保持30幀的游戲幀數(shù)。

            posted on 2007-12-29 12:08 楊粼波 閱讀(922) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久精品成人影院| 久久精品成人免费国产片小草 | AV无码久久久久不卡网站下载| 无码AV波多野结衣久久| 青青国产成人久久91网| 狠狠色丁香久久婷婷综合图片| 久久精品无码专区免费东京热| 久久99精品国产99久久6| 日韩精品久久久久久久电影蜜臀| 国内精品免费久久影院| 久久综合给合久久狠狠狠97色 | 久久久久亚洲精品日久生情| 久久伊人精品青青草原高清| 久久精品无码一区二区WWW| 国产激情久久久久影院老熟女免费| 久久人人爽人人爽人人av东京热 | 亚洲综合伊人久久大杳蕉| 国产成人精品久久亚洲高清不卡| 久久久久亚洲精品天堂| 久久婷婷国产剧情内射白浆| 久久九九免费高清视频| 日本精品久久久中文字幕| 99久久99久久精品免费看蜜桃| 99久久香蕉国产线看观香| 色偷偷91久久综合噜噜噜噜| 国内精品久久久久久久涩爱| 久久久久久久99精品免费观看| 久久久噜噜噜久久熟女AA片| 狠狠色婷婷久久综合频道日韩| 亚洲欧美另类日本久久国产真实乱对白| 999久久久国产精品| 亚洲国产精品久久久久久| 久久99精品国产99久久| 久久99国产精品二区不卡| 国内精品久久久久久99| 国产欧美一区二区久久| 亚洲国产精品久久久久婷婷老年 | 久久夜色tv网站| 欧美午夜精品久久久久久浪潮| 婷婷久久综合九色综合九七| 久久人人爽人人爽人人片AV麻烦 |