青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Direct3D中實現圖元的鼠標拾取

Direct3D中實現圖元的鼠標拾取

 

BY 重劍,2004.5.28 重劍空間 

索引:

1、什么是拾取,拾取能做什么?

2、拾取操作的步驟和實現

    2.1.  變換并獲得通過視點和屏幕上點擊點的射線矢量(Dir)

 

2.1.1 確定鼠標選取點的屏幕坐標

 

2.1.2 得到Dir在觀察坐標空間內的表示

 

2.1.3 轉換Dir到世界坐標空間,并得到觀察點在世界坐標系中的坐標

 

    2.2   使用射線矢量對場景中的所有三角形圖元求交,獲得三角形索引值和重心坐標。

 

2.2.1 D3D擴展函數實現求交

2.2.2射線三角面相交的數學算法

2.2.3  拾取完成根據獲得的中心坐標計算我們關心的常見量

3、結束及聲明

4、參考文獻

 

補充:重心坐標的概念

 

 

 

3D交互圖形應用程序中,常常要用鼠標去選擇圖形,其實現的機制基于鼠標拾取算法。本文主要講述如何在D3D中實現圖元的鼠標拾取。為了討論簡單,本文假定讀者理解D3D 坐標變換流程和基本的圖形學知識,如果閱讀有困難請參考相關資料。

1、什么是拾取,拾取能做什么?

首先,拾取操作指當我們在屏幕上用鼠標點擊某個圖元應用程序能返回該圖元的一個標志和某些相關信息。有圖形程序設計經驗的人都知道,有這些信息就表示我們有了對該圖元的控制權,我們可以刪除,可以編輯,可以任意對待該圖元,至于你到底想干什么,就是閣下自己的事了^_^

2、拾取操作的步驟和實現

拾取算法的思想很簡單:得到鼠標點擊處的屏幕坐標,通過投影矩陣和觀察矩陣把該坐標轉換為通過視點和鼠標點擊點的一條射入場景的光線,該光線如果與場景模型的三角形相交(本文只處理三角形圖元),則獲取該相交三角形的信息。本文講述的方法除可以得到三角形的一個索引號以外還可以得到相交點的重心坐標。

    從數學角度來看,我們只要得到射線的方向矢量和射線的出射點,我們就具備了判斷射線與空間一個三角面是否相交的條件,本文主要討論如何獲得這些條件,并描述了射線三角面相交判斷算法和D3D的通常實現方法。   

根據拾取操作的處理順序,大概可以依次分為以下幾個步驟

2.1  變換并獲得通過視點和屏幕上點擊點的射線矢量(Dir

詳細介紹之前,為了大家方便理解,我們要先簡單說一下d3d坐標轉換的大概流程,如下圖:

 

 

所以我們要通過一系列的反變換,得到我們關心的值在世界坐標中的表示。

2.1.1 確定鼠標選取點的屏幕坐標

這一步是非常簡單的Windows給我們提供了API來完成屏幕坐標的獲取,使用GetCursorPos獲得鼠標指針位置,然后再利用ScreenToClient轉換坐標到客戶區坐標系(以窗口視區左上角為坐標原點,單位為像素),設該坐標為(POINT screenPt)。

2.1.2 得到Dir在觀察坐標空間內的表示

在觀察坐標系中,Dir是一條從觀察坐標原點出發的射線,所以我們只需要再確定一個該射線經過的點,就可以得到它在觀察坐標系中的表示。假設我們要求的射線上的另外一點為該射線與透視投影平截頭體近剪切面的交點,針對最普遍的透視投影而言,透視投影平截頭體經投影變換后,變成一個1/2立方體(請允許我這么叫^_^,因為它的大小為一個正方體的一半,x,y方向邊長為2z方向為1)如圖:

 

投影坐標系以近剪切面中心為坐標原點,該立方體從z軸負向看過去與圖形程序視區相對應,最終近剪切面(前剪切面)上一點與屏幕坐標之間的對應關系如下圖所示:

 

 

根據比例關系,screenPt與投影空間上的點projPt之間的關系為

假設圖形程序窗口的寬為screenWidth,高為screenHeight,

projPt.x = (screenPt.x-screenWidth/2)/screenWidth*2; (公式1)

projPt.y = (screenPt.y-screenHeight/2)/screenHeight*2; (公式2)

projPt.z =0;(實際該值可任意取,不影響最終結果。為了處理簡單,我們取改值為0,表示該點取在近剪切面上)

得到projPt后,我們需要做的是把該點坐標從投影空間轉換到觀察空間(view space),

根據透視投影的定義,可假設點(projPt.xprojPt.yprojPt.z)

對應的其次坐標為

(projPt.x*projPt.wprojPt.y*projPt.wprojPt.z*projPt.wprojPt.w)

 

我們可以通過 GetTransform(      D3DTS_PROJECTION,    &ProjMatrix)函數獲得投影矩陣ProjMatrix,則根據觀察空間到投影空間的變換關系則

(projPt.x*projPt.wprojPt.y*projPt.wprojPt.z*projPt.wprojPt.w)

 = (viewPt.xviewPt.yviewPt.z, 1)*pProjMatrx;

根據定義和圖形學原理

ProjMatrix = =

 

所以,

(projPt.x*projPt.wprojPt.y*projPt.wprojPt.z*projPt.wprojPt.w)

= ( viewPt.x*ProjMatrix._m11,

viewPt.y*ProjMatrix._m22,

viewPt.z*Q-QZn,

viewPt.z)

 

所以

projPt.x*projPt.w = viewPt.x*ProjMatrix._m11

projPt.y*projPt.w = viewPt.y*ProjMatrix._m22

projPt.z*projPt.w = viewPt.z*Q-QZn (注意projPt.z = 0

projPt.w = viewPt.z;

解得

viewPt.x = projPt.x*Zn/ ProjMatrix._m11;

viewPt.y = projPt.y*Zn/ ProjMatrix._m22;

viewPt.z = Zn;

好了,到這里為止我們終于求出了射線與近剪切面交點在觀察坐標系中的坐標,現在我們擁有了射線的出發點(0,0,0)和射線方向上另外一點(viewPt.x,viewPt.y,viewPt.z),則該射線的方向矢量在觀察空間中的表示可確定為(viewPt.x-0,viewPt.y-0,viewPt.z-0,化簡一下三個分量同除近剪切面z坐標Zn,該方向矢量可寫作

DIRview = (projPt.x/projMatrix._m11,projPt.y/projMatrix._m22,1)

代入公式1,公式2

DIRview.x = (2*screenPt.x/screenWidth-1)/projMatrix._m11;

DIRview.y = (2*screenPt.y/screenHeight-1)/projMatrix._m22;

DIRview.z = 1;

其中screenWidth和screenHeight可以通過圖像顯示的backBuffer的目標表面(D3DSURFACE_DESC)來獲得,該表面在程序初始化時由用戶創建。

2.1.3 轉換Dir到世界坐標空間,并得到觀察點在世界坐標系中的坐標

由于最終的運算要在世界坐標空間中進行,所以我們還需要把矢量DIRview從觀察空間轉換為世界坐標空間中的矢量DIRworld。

因為

DIRview = DIRworld*ViewMatrix;

其中ViewMatrix為觀察矩陣,在D3D中可以用函數GetTransform( D3DTS_VIEW, &ViewMatrix )得到。

所以DIRworld = DIRview * inverse_ViewMatrix,其中inverse_ViewMatrix為

ViewMatrix的逆矩陣。

     觀察點在觀察坐標系中坐標為OriginView(0,0,0,1),所以其在世界坐標系中的坐標同樣可以利用ViewMatrix矩陣,反變換至世界坐標系中,事實上我們可以很簡單的判斷出,其在世界坐標系中的表示為:

OriginWorld = (inverse_ViewMatrix._41,

inverse_ViewMatrix._42,

inverse_ViewMatrix._43,

1);

到這里為止,判斷射線與三角面是否相交的條件就完全具備了。

 

2.2   使用射線矢量對場景中的所有三角形圖元求交,獲得三角形索引值和重心坐標。

這一步驟地實現由兩種途徑:

第一種方法非常簡單,利用D3D提供的擴展函數D3DXIntersect可以輕松搞定一切。見2.1

第二種方法就是我們根據空間解析幾何的知識,自己來完成射線三角形的求交算法。一般來講,應用上用第一種方法就足夠了,但是我們如果要深入的話,必須理解相交檢測的數學算法,這樣才能自由的擴展,面對不同的需求,內容見2.2

下面分別講解兩種實現途徑:

2.2.1 D3D擴展函數實現求交

這種方法很簡單也很好用,對于應用來說應盡力是用這種方式來實現,畢竟效率比自己寫得要高得多。

實際上其實沒什么好講的,大概講一下函數D3DXIntersect

D3D SDK該函數聲明如下

HRESULT D3DXIntersect(      
    LPD3DXBASEMESH pMesh,
    CONST D3DXVECTOR3 *pRayPos,
    CONST D3DXVECTOR3 *pRayDir,
    BOOL *pHit,
    DWORD *pFaceIndex,
    FLOAT *pU,
    FLOAT *pV,
    FLOAT *pDist,
    LPD3DXBUFFER *ppAllHits,
    DWORD *pCountOfHits
);
l          pMesh指向一個ID3DXBaseMesh的對象,最簡單的方式是從.x文件獲得,描述了要進行相交檢測的三角面元集合的信息,具體規范參閱direct9 SDK
l          pRayPos 指向射線發出點
l          pRayDir 指向前面我們辛辛苦苦求出的射線方向的向量
l          pHit 當檢測到相交圖元時,指向一個true,不與任何圖元相交則為假
l          pU 用于返回重心坐標U分量
l          pV返回重心坐標V分量
l          pDist 返回射線發出點到相交點的長度
注意:以上紅色字體部分均指最近的一個返回結果(即*pDist最小)
l          ppAllHits用于如果存在多個相交三角面返回相交的所有結果
l          pCountOfHits 返回共有多少個三角形與該射線相交

 

補充:重心坐標的概念

其中pU和pV用到了重心坐標的概念,下面稍作描述

一個三角形有三個頂點,在迪卡爾坐標系中假設表示為V1(x1,y1,z1),V2(x2,y2,z2),V3(x3,y3,z3),則三角形內任意一點的坐標可以表示為 pV = V1 + U(V2-V1) + V(V3-V1),所以已知三個頂點坐標的情況下,任意一點可用坐標(U,V)來表示,其中 參數U控制V2在結果中占多大的權值,參數V控制V3占多大權值,最終1-U-V控制V1占多大權值,這種坐標定義方式就叫重心坐標。

 

2..2.2射線三角面相交的數學算法

     使用d3d擴展函數,畢竟有時不能滿足具體需求,掌握了該方法,我們才能夠獲得最大的控制自由度,任意修改算法。

    

已知條件: 射線源點orginPoint,三角形三個頂點 v1,v2,v3,射線方向 Dir

(均以三維坐標向量形式表示)

算法目的: 判斷射線與三角形是否相交,如果相交求出交點的重心坐標(U,V)和射線原點到交點的距離T

 

我們可先假設射線與三角形相交則交點(注以下均為向量運算,*數乘,dot(X,Y) XY 點乘,crossXYXY叉乘;UVT為標量)

則:

IntersectPoint = V1 + U*(V2-V1) + V*(V3-V1) ;

IntersectPoint = originPoint + T*Dir

 

所以

orginPoint + T*Dir = V1 + U*(V2-V1) + V*(V3-V1);

整理得:

 

這是一個簡單的線性方程組,若有解則行列式 不為0

根據T,U,V的含義當T>0, 0<U<1,0<V<1,0<U+V<1時該交點在三角形內部,

解此方程組即可獲得我們關心的值,具體解法不再贅述,克萊姆法則就夠了(詳細見線性代數):射線原點到相交點的距離T,和交點的中心坐標(U,V)

下面給出Direct 9 SDK示例程序中的實現代碼

IntersectTriangle( const D3DXVECTOR3& orig,

                   const D3DXVECTOR3& dir, D3DXVECTOR3& v0,

                   D3DXVECTOR3& v1, D3DXVECTOR3& v2,

                   FLOAT* t, FLOAT* u, FLOAT* v )

{

    // 算出兩個邊的向量

    D3DXVECTOR3 edge1 = v1 - v0;

    D3DXVECTOR3 edge2 = v2 - v0;

 

    D3DXVECTOR3 pvec;

    D3DXVec3Cross( &pvec, &dir, &edge2 );

 

    // 如果det為0,或接近于零則射線與三角面共面或平行,不相交

//此處det就相當于上面的

    FLOAT det = D3DXVec3Dot( &edge1, &pvec );

 

    D3DXVECTOR3 tvec;

    if( det > 0 )

    {

        tvec = orig - v0;

    }

    else

    {

        tvec = v0 - orig;

        det = -det;

    }

 

    if( det < 0.0001f )

        return FALSE;

 

    // 計算u并測試是否合法(在三角形內)

    *u = D3DXVec3Dot( &tvec, &pvec );

    if( *u < 0.0f || *u > det )

        return FALSE;

 

    // Prepare to test V parameter

    D3DXVECTOR3 qvec;

    D3DXVec3Cross( &qvec, &tvec, &edge1 );

 

    //計算u并測試是否合法(在三角形內)

    *v = D3DXVec3Dot( &dir, &qvec );

    if( *v < 0.0f || *u + *v > det )

        return FALSE;

 

    /*計算t,并把t,u,v放縮為合法值(注意前面的t,v,u不同于算法描述中的相應量,乘了一個系數det),注意:由于該步運算需要使用除法,所以放到最后來進行,避免不必要的運算,提高算法效率*/

    *t = D3DXVec3Dot( &edge2, &qvec );

    FLOAT fInvDet = 1.0f / det;

    *t *= fInvDet;

    *u *= fInvDet;

    *v *= fInvDet;

 

    return TRUE;

}

 

 

2.2.3  拾取完成根據獲得的中心坐標計算我們關心的常見量,。

根據重心坐標(U,V,我們可以很容易的算出各種相關量比如紋理坐標和交點的差值顏色,假設以紋理坐標為例設V1,V2,V3的紋理坐標分別為T1(tu1,tv1),T2(tu2,tv2),T3(tu3,tv3)則交點的坐標為

 

IntersectPointTexture = T1 + U(T2-T1) + V(T3-T1)

 

3、結束及聲明

Ok, 到這里為止關于拾取的相關知識就介紹完了,小弟第一次寫這種文章,不知道有沒有把問題說清楚,希望對大家有所幫助,有任何問題可以給我發email: jzhang1@mail.xidian.edu.cn

或者到我的網站留言: www.heavysword.com

 

聲明:

本文寫作的目的是為了廣大D3D學習者方便學習服務,文中算法為作者參考相關文獻總結,作者無意把這些據為自己的成果,所有權原算法提出者所有(參閱參考文獻),文中代碼為D3d SDK的示例內容,由筆者進行了必要的解釋,代碼版權歸microsoft所有。

4、參考文獻

【1】Microsoft DirectX 9.0 SDK,microsoft

【2】fast,Minimun Storage Ray/Triangle Intersection,Tomas Moler,Ben Trumbore

 

posted on 2008-04-16 09:44 RedLight 閱讀(544) 評論(0)  編輯 收藏 引用 所屬分類: 3D渲染技術

<2008年5月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

導航

統計

公告


Name: Galen
QQ: 88104725

常用鏈接

留言簿(3)

隨筆分類

隨筆檔案

相冊

My Friend

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            伊人成人在线| 蜜臀av国产精品久久久久| 久久精品一本久久99精品| 午夜精品福利视频| 欧美伊人精品成人久久综合97| 亚洲一区二区高清| 亚洲欧美精品伊人久久| 午夜在线精品| 麻豆成人91精品二区三区| 嫩草国产精品入口| 亚洲精品国产无天堂网2021| 一区二区高清视频在线观看| 亚洲欧美在线视频观看| 免费欧美日韩国产三级电影| 欧美日韩无遮挡| 国产午夜精品视频| 亚洲精品久久7777| 欧美一区网站| 亚洲电影免费| 性视频1819p久久| 欧美不卡视频一区发布| 国产精品久久久久久久第一福利| 一区在线免费| 亚洲一区二区综合| 欧美gay视频激情| 亚洲先锋成人| 欧美国产欧美亚州国产日韩mv天天看完整| 欧美日韩一区二区三区在线观看免| 国产精品一区二区女厕厕| 亚洲国产精品999| 欧美一区永久视频免费观看| 亚洲国产精彩中文乱码av在线播放| 日韩视频精品| 99天天综合性| 国产日韩一区| 一本色道久久综合亚洲精品不卡| 久久久久久久一区| 在线亚洲电影| 欧美精品七区| 亚洲国产高清高潮精品美女| 欧美在线播放一区二区| 99视频精品在线| 欧美激情精品久久久| 激情亚洲成人| 久久久久成人精品| 亚洲欧美另类中文字幕| 欧美色欧美亚洲另类二区| 亚洲精品免费在线| 欧美成人有码| 久久综合狠狠综合久久综合88| 国产色产综合产在线视频| 亚洲男人的天堂在线| 亚洲乱码国产乱码精品精可以看| 久久在线视频在线| 极品尤物av久久免费看 | 欧美国产日韩一区二区在线观看 | 国内外成人在线视频| 亚洲欧美激情四射在线日| 一区二区三区欧美日韩| 欧美日韩性视频在线| 99精品国产热久久91蜜凸| 91久久国产综合久久91精品网站| 开元免费观看欧美电视剧网站| 韩国欧美一区| 欧美大秀在线观看 | 狠狠色丁香婷婷综合| 久久精品国产亚洲一区二区| 欧美一级黄色录像| 激情丁香综合| 亚洲大片精品永久免费| 欧美经典一区二区三区| 亚洲手机成人高清视频| 一区二区三区精密机械公司 | 久久在线免费观看视频| 亚洲人成网站精品片在线观看| 欧美国产综合一区二区| 欧美精品免费视频| 新狼窝色av性久久久久久| 午夜精品国产更新| 亚洲国产精品成人va在线观看| 亚洲国产另类久久精品| 欧美午夜精品伦理| 久久国产精品久久久久久电车| 久久国产婷婷国产香蕉| 亚洲美女免费精品视频在线观看| av成人黄色| 国产一区二区精品在线观看| 国产精品婷婷| 99riav久久精品riav| 欧美国产91| 欧美三级电影精品| 久久女同互慰一区二区三区| 欧美成人a视频| 午夜一级在线看亚洲| 久久一综合视频| 亚洲综合国产| 麻豆精品传媒视频| 性xx色xx综合久久久xx| 欧美成va人片在线观看| 午夜亚洲一区| 欧美精品免费在线| 久久免费视频观看| 国产精品大全| 亚洲国产精品久久久久| 国产视频在线观看一区| 亚洲人成绝费网站色www| 国产伊人精品| 亚洲小少妇裸体bbw| 亚洲欧洲视频在线| 欧美在线黄色| 亚洲欧美日韩成人高清在线一区| 裸体女人亚洲精品一区| 欧美一区二区国产| 欧美视频网址| 亚洲精品字幕| 亚洲区免费影片| 久久精品导航| 久久精品盗摄| 国产精品日韩在线一区| 亚洲精品在线电影| 亚洲精品日产精品乱码不卡| 久久精品网址| 久久久久久亚洲精品中文字幕| 国产精品sss| 日韩视频精品| 一区二区三区成人精品| 欧美激情精品| 亚洲欧洲日产国产网站| 亚洲日本欧美天堂| 欧美成人免费全部| 亚洲国产成人在线播放| 亚洲黄色有码视频| 免费成人在线观看视频| 欧美好骚综合网| 亚洲国内高清视频| 欧美电影免费| 亚洲精品一区在线| 亚洲午夜小视频| 国产精品成人一区二区艾草| 99视频精品在线| 亚洲欧美激情四射在线日| 欧美午夜宅男影院在线观看| 亚洲伦理在线观看| 亚洲主播在线播放| 国产伦精品一区二区三区在线观看| 亚洲香蕉网站| 欧美制服丝袜第一页| 国产亚洲精久久久久久| 久久久久久久网站| 欧美不卡在线| 亚洲免费观看在线观看| 欧美午夜激情视频| 欧美一二区视频| 欧美r片在线| 亚洲午夜久久久久久久久电影网| 国产精品高清在线观看| 亚洲精品小视频在线观看| 欧美国产欧美亚洲国产日韩mv天天看完整 | 欧美国产精品人人做人人爱| 亚洲日本黄色| 欧美一级久久| 在线观看av不卡| 欧美日本国产在线| 亚洲欧美国产毛片在线| 久久久久久黄| 日韩亚洲在线| 国产人成精品一区二区三| 久久青青草综合| av成人动漫| 嫩草影视亚洲| 午夜久久影院| 亚洲日本一区二区三区| 国产精品视频99| 欧美成人精品高清在线播放| 亚洲一区免费| 最新国产の精品合集bt伙计| 欧美综合77777色婷婷| 亚洲精选成人| 红桃视频国产精品| 欧美视频导航| 欧美α欧美αv大片| 欧美亚洲一区二区在线| av成人动漫| 亚洲精品午夜| 亚洲二区在线视频| 久久综合狠狠| 欧美中文在线字幕| 亚洲影院免费| aa日韩免费精品视频一| 合欧美一区二区三区| 国产精品国产馆在线真实露脸| 美女国产一区| 久久精品夜夜夜夜久久| 欧美一区二区三区另类| 中文精品视频一区二区在线观看| 亚洲高清中文字幕| 欧美成人午夜激情视频| 久久人人爽人人爽| 久久超碰97中文字幕| 亚洲欧美日韩一区在线|