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

            我參與的團隊

            最新隨筆

            搜索

            •  

            積分與排名

            • 積分 - 370257
            • 排名 - 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
            請問此貼中提到的代碼是??
            從哪本書上來的?  回復  更多評論
              

            国内精品伊人久久久久AV影院| 久久婷婷五月综合成人D啪| 狠狠色综合网站久久久久久久高清| 久久本道伊人久久| 久久99久久99小草精品免视看| 久久亚洲AV成人无码电影| 狠狠综合久久综合88亚洲| 性欧美大战久久久久久久 | 亚洲国产成人久久精品99| 91亚洲国产成人久久精品| 久久精品国产91久久综合麻豆自制| 久久中文骚妇内射| 日本久久久久亚洲中字幕| 久久亚洲春色中文字幕久久久| 蜜臀av性久久久久蜜臀aⅴ| 国产精品美女久久久久| 精品综合久久久久久97超人| 久久99国产精品二区不卡| 亚洲国产精品久久久久| 狠狠综合久久综合中文88| 精品久久久久久国产牛牛app | 青青草原综合久久大伊人导航| 久久国产影院| 亚洲午夜久久久| 亚洲中文字幕久久精品无码APP | 久久夜色撩人精品国产| 无码精品久久一区二区三区| 亚洲婷婷国产精品电影人久久| 久久久久99这里有精品10| 国内精品人妻无码久久久影院导航 | 伊人久久大香线蕉亚洲| 久久丫精品国产亚洲av不卡| 国产精品久久99| 久久性生大片免费观看性| 久久综合亚洲鲁鲁五月天| 精品久久久噜噜噜久久久| 99国内精品久久久久久久| 久久久久久久波多野结衣高潮| 久久99精品久久只有精品| 国产午夜福利精品久久| 国产精品乱码久久久久久软件 |