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

            李錦俊(mybios)的blog

            游戲開發 C++ Cocos2d-x OpenGL DirectX 數學 計算機圖形學 SQL Server

              C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
              86 Posts :: 0 Stories :: 370 Comments :: 0 Trackbacks

            公告

            QQ:30743734
            EMain:mybios@qq.com

            常用鏈接

            留言簿(16)

            我參與的團隊

            最新隨筆

            搜索

            •  

            積分與排名

            • 積分 - 370305
            • 排名 - 67

            最新評論

            閱讀排行榜

            評論排行榜

            第九集 那是什么鬼東西

            ?

            想起第一次面對StarCraft的主界面, 看到旋轉的星球, 晃著腦袋的衛星, , 那是什么?

            ?

            想知道, 簡單, 把鼠標移上去, 它會告訴你的Who am I.

            ?

            9.1 逆轉換

            ?

            鼠標在屏幕的熱點是相對屏幕坐標系, Windows屏幕坐標以左上角為原點, X軸正方向朝右, Y軸正方向朝下. 問題是Windows屏幕坐標和虛擬3D世界坐標不是簡單映射的, 這個過程很復雜(在第2集的3D pipeline中有詳細的過程描述),? 我們只有將鼠標的熱點的坐標通過Windows坐標到3D pipeline的屏幕坐標及3D pipeline的逆轉換后, 才能得到在3D世界的對應點, 最后確定這個點是否有物體, 這就是Picking.

            ?

            部分知識參考DX9c SDK文檔中的Viewports and ClippingTransforms主題.

            ?

            9.1.1 Picking Ray

            ?

            如圖9.1, 我們根據3D pipeline的原理來轉換屏幕點S,

            9.1

            3D pipeline 中有一個重要的點 視點, 屏幕在DirectX Graphics中是Z = 1的視平面(攝影機坐標系). 屏幕顯示的是所有在視錐內的局部虛擬3D世界中的物體, 我們從視點通過屏幕上的點S的射線有可能和視錐內的局部虛擬3D世界中的物體有交點, 射線稱為Picking Ray, 我們依靠這條射線來確定選取的物體.

            ?

            Picking Ray 可以由它的端點R0(Rx, Ry, Rz)和方向向量U確定, R(t) = R0 + t * U.

            9.1.2 Windows 坐標到3D pipeline的屏幕坐標

            ?

            現在開始逆轉換, DirectX Graphics顯示的一幀數據以Surface表示的, 如圖9.2, surface中保存著以Windows坐標系統表示的數據. 3D pipeline的屏幕坐標系通過以下矩陣的轉換到Windows坐標系統,

            ?|? Width / 2???????? ????0??????????? ?????0???????????? ????0 |

            ?|????? 0?????? ????- Height / 2??? ????????0???????? ????????0 |

            M = |????? 0???????????? ????0?????? ?????MaxZ MinZ ???????????0 |

            ?| X + Width / 2 ???Y + Heught / 2???????? MinZ??????????? ???1 |

            9.2

            對于鼠標的Windows坐標P(Px, Py), 是由3D pipeline的屏幕坐標系中點S(Sx, Sy, Sz)轉換而來的, 滿足 [S] * M = [P], [s] = (Sx, Sy, Sz, 1), [P] = (Px, Py, 1, 1),坐標代入得到,

            Px = Sx * Width / 2 + X + Width / 2

            Py = - Sy * Height / 2 + Y + Height / 2

            Pz = Sz = 1

            ? 現在我們要計算的是S,

            Sx = (2 * Px 2 * X Width) / Width

            Sy = (-2 * Py + 2 * Y + Height) / Height

            Sz = 1

            當游戲是以全屏模式運行的時候, X = Y = 0,

            Sx = (2 * Px Width) / Width

            Sy = (-2 * Py + Height) / Height

            Sz = 1

            ?

            9.1.3 3D pipeline 的屏幕坐標系到攝影機坐標系的變換

            ?

            這個變換相對簡單, 因為投影矩陣是對角矩陣(參考 2.1.4.3 ), 我們只要除以這個對角矩陣的相應數值就可以了,

            Cx = (2 * Px Width) / (Width * P[0][0])

            Cy = (-2 * Py + Height) / (Height * P[1][1])

            ?

            9.1.4 攝影機坐標系到世界坐標系的變換

            ?

            ??? 這里的變換矩陣就比較復雜了(參考 2.1.4.2 ), 我們需要用到逆矩陣了,

            ????????????? E(Ex, Ey, Ez, Ew) = C(Cx, Cy, Cz, Cw) * M -1

            ?

            9.1.5 代碼實現

            ?

            //#define XLPARAM(lp)??? ((LONG)(SHORT)LOWORD(lp))

            //#define YLPARAM(lp)??? ((LONG)(SHORT)HIWORD(lp))

            LONG x = XLPARAM(dwPt);

            LONG y = YLPARAM(dwPt);

            ?

            FLOAT Rx = 0.0;

            FLOAT Ry = 0.0;

            FLOAT b ?= 0.0;

            FLOAT c ?= 0.0;

            ?

            D3DVIEWPORT9 mv;

            D3DXMATRIX?? mProj;

            D3DXMATRIX?? mView;

            m_pD3DDev->GetViewport(&mv);

            m_pD3DDev->GetTransform(D3DTS_PROJECTION, &mProj);

            m_pD3DDev->GetTransform(D3DTS_VIEW, &mView);

            D3DXMatrixInverse(&mView, NULL, &mView);

            ?

            b ?= mProj(0, 0);

            c ?= mProj(1, 1);

            Rx = ((x * 2.0) - mv.Width) / (mv.Width * b);

            Ry = (mv.Height - (y * 2.0)) / (mv.Height * c);

            ?

            D3DXVECTOR3 pos(0.0, 0.0, 0.0);

            D3DXVECTOR3 n(Rx, Ry, 1.0);

            D3DXVec3TransformCoord(&pos, &pos, &mView);

            D3DXVec3TransformNormal(&n, &n, &mView);

            D3DXVec3Normalize(&n, &n);

            ?

            9.2 它是誰

            ?

            終于轉換好了, 下面要確定在世界坐標系中誰在相應的坐標了. 其實我們發現射線Picking就是 光線跟蹤算法 ( 參考 5.2 ), 可以試著使用BSP來確定需要和射線做相交測試的物體, 想想和一個模型復雜的物體的測試, 可能要抓狂了 -- 天哪!

            ?

            ??? 當然, 實際不會真的和物體模型測試的(除非 ), 最實際的是和物體模型的最小外接正方體或球等做測試就可以了.

            ?

            9.2.1 Mesh Bounding

            ?

            ??? DirectX Graphics 中為Mesh提供了計算外接正方體或球的函數,

            HRESULT D3DXComputeBoundingBox(CONST D3DXVECTOR3 * pMeshVertex,

            ?????????????????????????????? DWORD NumVertices,

            ?????????????????????????????? DWORD dwStride,

            ?????????????????????????????? D3DXVECTOR3 * pMin,

            ?????????????????????????????? D3DXVECTOR3 * pMax);

            ?

            HRESULT D3DXComputeBoundingSphere(CONST D3DXVECTOR3 * pMeshVertex,

            ????????????????????????????????? DWORD NumVertices,

            ????????????????????????????????? DWORD dwStride,

            ????????????????????????????????? D3DXVECTOR3 * pCenter,

            ???????????????? ?????????????????FLOAT * pRadius);

            ?

            9.2.2 Ray & Sphere

            ?

            一般我們選用球做測試更簡單, 球原心向量O(Ox, Oy, Oz), 射線對應向量R0(Rx, Ry, Rz), 求出交點數|| R0 + t * U O || = r,

            A * t^2 + B * t + C = 0

            A = (U DOT U) = 1 ( 我們已經將U歸一化)

            B = 2 (U DOT (R0 - O))

            C = ((R0 - O) DOT (R0 - O)) r^2

            a = B^2 - 4 * C, 如果a < 0, 沒有交點; 如果a > 0, 那么只有當有一根不為負時, 有交點, 負根表示和當前射線方向相反的方向和球相交.

            ?

            // m_vCenter Mesh外界球的中心向量

            // m_fRad Mesh外界球的半徑

            D3DXVECTOR3 v = pos - m_vCenter;

            b = 2.0 * D3DXVec3Dot(&n, &v);

            c = D3DXVec3Dot(&v, &v) - m_fRad * m_fRad;

            ?

            FLOAT del = b * b - 4 * c;

            if (del > 0.0)

            {

            ??? del = sqrtf(del);

            ??? FLOAT x1 = ( del - b) / 2.0;

            ??? FLOAT x2 = (-del - b) / 2.0;

            ??? if ((x1 < 0.0) && (x2 < 0.0))

            ??? {

            ??????? return FALSE;

            ??? }

            ??? return TRUE;

            }

            return FALSE;

            ?

            9.3 Who am I

            ?

            如果物體在被Pick后自己能說: " 我是太陽", 那太好了, 但現在我們還未接觸DirectX Audio, 所以我們還是用文字表達吧.

            ?

            9.3.1 Bitmapped Font

            ?

            ??? Bitmapped Font 相對英語很簡單, 26個字母一16 * 16行成一隊列Bitmap, 大小寫各一行, 用到字母 "A"只需將(0, 16) -- (16, 32)Bitmap數據CopyRect就可以了, 這種方式早期的游戲很常見.

            ?

            9.3.2 ID3DXFont

            ?

            DirectX Graphics 中有專門的文字顯示接口ID3DXFont, GDI中的HFONT的創建類似, 顯示文字的函數也和GDI中相同. 使用以下兩個函數來創建字體,

            HRESULT D3DXCreateFont(LPDIRECT3DDEVICE9 pDevice,

            ?????????????????????? INT Height,

            ?????????????????????? UINT Width,

            ?????????????????????? UINT Weight,

            ?????????????????????? UINT MipLevels,

            ?????????????????????? BOOL Italic,

            ?????????????????????? DWORD CharSet,

            ?????????????????????? DWORD OutputPrecision,

            ?????????????????????? DWORD Quality,

            ?????????????????????? DWORD PitchAndFamily,

            ?????????????????????? LPCTSTR pFacename,

            ?????????????????????? LPD3DXFONT * ppFont);

            ?

            HRESULT D3DXCreateFontIndirect(LPDIRECT3DDEVICE9 pDevice,

            ?????????????????????????????? CONST D3DXFONT_DESC * pDesc,

            ?????????????????????????????? LPD3DXFONT * ppFont);

            實際上, ID3DXFont的創建和顯示字體還是依賴于GDIFONT的創建和顯示字體的函數的, 所以ID3DXFont顯示字體并非是由DirectX Graphics中的Direct3D來完成的, 如果想提高性能, 建議少量的字體顯示用9.3.1的方式, 大量的字體顯示可事先轉換成bitmap.

            ?

            ?

            9.4 Pick 的例子

            ?

            9.4.1 game9 project 代碼更新

            ?

            ??? game9 中只是演示了 Picking, ID3DXLINE 和文字顯示.

            ---------------------------------------------------------------

            // 全局變量, 用來保存4個測試球的半徑, 原始圓心位置, 變動圓心位置

            // 最后兩個向量是Picking Ray的端點和方向

            FLOAT?????? g_fRad[4];

            D3DXVECTOR3 g_vCenter[4];

            D3DXVECTOR3 g_vTest[4];

            D3DXVECTOR3 g_pos;

            D3DXVECTOR3 g_n;

            ?

            // game9.cpp, LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

            // 加入對WM_MOUSEHOVER的消息探測, 大概1秒鐘的鼠標停頓產生WM_MOUSEHOVER

            // 注意使用WM_MOUSEHOVER 必須定義 #define _WIN32_WINNT ?0x0500(0x400以上)

            ??? case WM_MOUSEMOVE:

            ??????? {

            ???????????? TRACKMOUSEEVENT tme = { 0 };

            ???????????? tme.cbSize = sizeof(TRACKMOUSEEVENT);

            ???????????? tme.dwFlags = TME_LEAVE | TME_HOVER;

            ???????????? tme.hwndTrack = hWnd;

            ???????????? tme.dwHoverTime = 0x0400;

            ???????????? TrackMouseEvent(&tme);

            ???????????? if (g_bHover)

            ???????????? {

            ????????????????? g_bHover = FALSE;

            ????????????????? g_pGame->EndPick();

            ???????????? }

            ??????? }

            ??????? break;

            ??? case WM_MOUSEHOVER :

            ??????? {???

            ???????????? if (g_bHover == FALSE)

            ???????????? {

            ????????????????? g_bHover = g_pGame->Picking((DWORD)lParam);

            ???????????? }

            ??????? }

            ??????? break;

            ?

            // direct9.cpp, 保存Picking Ray的端點和方向, 以為當4個模型自動旋轉時有自動Pick的功能

            BOOL CD9Game::Picking(DWORD dwPt)

            {

            ??? LONG x = XLPARAM(dwPt);

            ??? LONG y = YLPARAM(dwPt);

            ?

            ??? FLOAT Rx = 0.0;

            ??? FLOAT Ry = 0.0;

            ??? FLOAT mx = 0.0;

            ??? FLOAT my = 0.0;

            ?

            ??? D3DVIEWPORT9 mv;

            ??? D3DXMATRIX?? mProj;

            ??? D3DXMATRIX?? mView;

            ??? m_pD3DDev->GetViewport(&mv);

            ??? m_pD3DDev->GetTransform(D3DTS_PROJECTION, &mProj);

            ??? m_pD3DDev->GetTransform(D3DTS_VIEW, &mView);

            ??? D3DXMatrixInverse(&mView, NULL, &mView);

            ?

            ??? mx = mProj(0, 0);

            ??? my = mProj(1, 1);

            ??? Rx = (FLOAT)((x * 2.0) - mv.Width) / (mv.Width * mx);

            ??? Ry = (FLOAT)(mv.Height - (y * 2.0)) / (mv.Height * my);

            ?

            ??? g_pos.x = 0.0;

            ??? g_pos.y = 0.0;

            ??? g_pos.z = 0.0;

            ??? g_n.x?? = Rx;

            ??? g_n.y?? = Ry;

            ??? g_n.z?? = 1.0;

            ??? D3DXVec3TransformCoord(&g_pos, &g_pos, &mView);

            ??? D3DXVec3TransformNormal(&g_n, &g_n, &mView);

            ??? D3DXVec3Normalize(&g_n, &g_n);

            ?

            ??? return WhoAmI();

            }

            // direct9.cpp, 確定當前選中的物體

            BOOL CD9Game::WhoAmI()

            {

            ??? BOOL bPick = FALSE;

            ??? D3DXVECTOR3 v;

            ??? FLOAT b, c;

            ??? INT i = 0;

            ??? for (; i < 4; i++)

            ??? {

            ??????? v = g_pos - g_vTest[i];

            ??????? b = FLOAT(2.0 * D3DXVec3Dot(&g_n, &v));

            ??????? c = D3DXVec3Dot(&v, &v) - g_fRad[i] * g_fRad[i];

            ?

            ??????? FLOAT del = b * b - 4 * c;

            ??????? if (del > 0.0)

            ??????? {

            ???????????? del = sqrtf(del);

            ???????????? FLOAT x1 = (FLOAT)(( del - b) / 2.0);

            ???????????? FLOAT x2 = (FLOAT)((-del - b) / 2.0);

            ???????????? if ((x1 >= 0.0) || (x2 >= 0.0))

            ???????????? {

            ????????????????? bPick = TRUE;

            ????????????????? break;

            ???????????? }

            ??????? }

            ??? }

            ??? lstrcpyn(g_szPick, g_szObj[i], 512);

            ??? return bPick;

            }

            ?

            // direct9.cpp, 渲染物體, 如果自動旋轉時有自動Pick

            VOID CD9Game::Render()

            {

            ??? if (m_dwRot >= MAXROT)

            ??? {

            ??????? m_dwRot = 1L;

            ??? }

            ??? else if (m_bRot)

            ??? {

            ??????? m_dwRot++;

            ??? }

            ??? D3DXMATRIX mWorld, mWorldX, mWorldY, mWorldZ;

            ??? FLOAT rat = m_dwRot * ROT;

            ??? D3DXMatrixRotationX(&mWorldX, rat);

            ??? D3DXMatrixRotationY(&mWorldY, rat);

            ??? D3DXMatrixRotationZ(&mWorldZ, rat);

            ?

            ??? D3DXMatrixMultiply(&mWorld, &mWorldX, &mWorldY);

            ??? D3DXMatrixMultiply(&mWorld, &mWorld, &mWorldZ);

            ?

            ??? D3DXMATRIX m1, m2, m3, m4;

            ??? D3DXMatrixMultiply(&m1, &g_m1, &mWorld);

            ??? D3DXMatrixMultiply(&m2, &g_m2, &mWorld);

            ??? D3DXMatrixMultiply(&m3, &g_m3, &mWorld);

            ??? D3DXMatrixMultiply(&m4, &g_m4, &mWorld);

            ??? if (m_bRot)

            ??? {??? // 如果自動旋轉時有自動Pick

            ??????? D3DXVec3TransformCoord(&g_vTest[0], &g_vCenter[0], &m1);

            ??????? D3DXVec3TransformCoord(&g_vTest[1], &g_vCenter[1], &m2);

            ??????? D3DXVec3TransformCoord(&g_vTest[2], &g_vCenter[2], &m3);

            ??????? D3DXVec3TransformCoord(&g_vTest[3], &g_vCenter[3], &m4);

            ??????? WhoAmI();

            ??? }

            ?

            ??? m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,

            ???????????????????? D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

            ??? m_pD3DDev->BeginScene();

            ?

            ??? m_pD3DDev->SetTransform(D3DTS_WORLD, &m1);

            ??? m_pMeshShip->Render();

            ??? m_pD3DDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

            ??? m_pMeshSphere->DrawSubset(0);

            ??? m_pD3DDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

            ?

            ??? m_pD3DDev->SetTransform(D3DTS_WORLD, &m2);

            ??? m_pMesh1->DrawSubset(0);

            ??

            ??? m_pD3DDev->SetTransform(D3DTS_WORLD, &m3);

            ??? m_pMesh2->DrawSubset(0);

            ???

            ??? m_pD3DDev->SetTransform(D3DTS_WORLD, &m4);

            ??? m_pMesh3->DrawSubset(0);

            ?? // Y軸向上或向下的偏移, X軸向左或向右的偏移

            ??? D3DXVECTOR2* pLine = g_vy;

            ??? m_pLine->Begin();

            ??? m_pLine->Draw(pLine, 8, D3DCOLOR_XRGB(0, 128, 0));

            ??? pLine += 8;

            ??? m_pLine->Draw(pLine, 2, D3DCOLOR_XRGB(0, 255, 0));

            ??? pLine += 2;

            ??? m_pLine->Draw(pLine, 8, D3DCOLOR_XRGB(0, 128, 0));

            ??? pLine += 8;

            ??? m_pLine->Draw(pLine, 2, D3DCOLOR_XRGB(0, 255, 0));

            ??? m_pLine->End();

            ?? // 顯示每秒幀數和選擇物體的類型

            ??? RECT rect = { 16, 16, 512, 48 };

            ??? wsprintf(g_szFPS, _T("Current FPS : %ld"), g_dwFPS);

            ??? m_pFont->DrawText(NULL, g_szFPS, -1, &rect,

            ???????????????????? DT_NOCLIP | DT_VCENTER, D3DCOLOR_XRGB(0, 128, 0));

            ??? rect.top = 48;

            ??? rect.bottom += 32;

            ??? m_pFont->DrawText(NULL, g_szPick, -1, &rect, DT_NOCLIP, D3DCOLOR_XRGB(0, 128, 0));

            ???

            ??? m_pD3DDev->EndScene();

            ??? m_pD3DDev->Present(NULL, NULL, NULL, NULL);

            }

            ---------------------------------------------------------------

            ?

            9.4.2 game9 project 說明

            ?

            ??? 為代碼簡單, 在鼠標停留在某地一定時間產生 WM_MOUSEHOVER 消息時, 才會有Pick功能的調用, 物體類型在左上角顯示 . 自動旋轉/停止用Space切換, 自動旋轉時有自動Picking功能, 也就是鼠標不動, 當物體旋轉到鼠標位子將自動識別物體.

            ?

            ??? 識別物體有延遲現象, 作為例子就不改的太復雜了. 還有這種Picking技術是最普通的, 物體少的時候用還不錯, 實際的游戲可以使用BSP, 反饋法, 直接映射法等.

            ?

            ?

            第九集 小結?

            ?

            這一集我們學習了要進行DirectX Graphics 3D編程中的物體Pick和文字顯示.

            posted on 2006-11-16 19:57 李錦俊(mybios) 閱讀(1556) 評論(1)  編輯 收藏 引用 所屬分類: Direct3D

            Feedback

            # re: 【轉貼】那是什么鬼東西? Pick!!就是物件拾??! 2007-12-05 10:54 zhangyb
            請問此貼中提到的代碼是??
            從哪本書上來的?  回復  更多評論
              

            久久久精品人妻一区二区三区四| 久久伊人五月丁香狠狠色| 麻豆精品久久久久久久99蜜桃| 精品无码久久久久国产| 国产激情久久久久久熟女老人| 久久久久人妻一区精品| 青青草国产精品久久| 国产精品久久久福利| 人妻精品久久无码专区精东影业| 国产aⅴ激情无码久久| 久久亚洲精品成人无码网站| 欧美精品九九99久久在观看| 伊人精品久久久久7777| 色婷婷久久久SWAG精品| 亚洲国产精品综合久久网络| 亚洲国产高清精品线久久 | 久久午夜福利电影| 久久久久国产一区二区三区| 国产精自产拍久久久久久蜜| 精品国产婷婷久久久| 久久久亚洲精品蜜桃臀| 中文字幕无码久久久| 亚洲AV日韩精品久久久久久| 久久亚洲精精品中文字幕| 久久国产一区二区| 国产精品美女久久久网AV| 久久久人妻精品无码一区| 久久综合鬼色88久久精品综合自在自线噜噜 | 久久福利资源国产精品999| 伊人精品久久久久7777| 欧美午夜精品久久久久免费视| 国产精品免费福利久久| 欧美精品一本久久男人的天堂| 国产精品无码久久四虎| 偷偷做久久久久网站| 久久免费高清视频| 人妻少妇精品久久| 久久久久亚洲av无码专区导航| 色综合久久88色综合天天| 亚洲欧美久久久久9999| 国产综合久久久久|