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

            麒麟子

            ~~

            導航

            <2009年10月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統計

            常用鏈接

            留言簿(12)

            隨筆分類

            隨筆檔案

            Friends

            WebSites

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            #

            per-pixel lighting 紋理空間坐標基的計算方法

             

             

            文章來源:http://www.freegames.com.cn/school/383/2007/27685.html
            Nemesis2k
            per-pixel lighting 紋理空間坐標基的計算方法

            我知道的幾種方法:

            1. 對于參數化的表面,設其方程為 P = P (u, v),其中 P 為向量,
            三個分量分別為 x, y z。也可以表示為:
            Px = Px (u ,v)
            Py = Py (u ,v)
            Pz = Pz (u ,v)
            那在任意一個頂點
            T = {dPx/du, dPy/du, dPz/du}
            B = {dPx/dv, dPy/dv, dPz/dv}
            N = T X B
            然后把 T, B, N 歸一化就行了。
            這里的偏導數可以用差分計算。
            這樣計算出來的切空間是在每一個頂點的切空間。

            2。對于由三角形面片組成的網格,在 MSDN 上的 Per-pixel lighting
            文章里介紹了一種方法。
            設三角形的三個頂點是 P0, P1, P2,其中每個頂點都有位置,法向量
            和 2-D 紋理坐標。
            Pi : {x, y, z}, {nx, ny, nz}, {s, t}
            現在我們要計算在 P0 點的切空間。
            這里要分辨兩個切空間:
            1)頂點上的切空間
            2)三角形面片上的切空間
            兩個切空間是相同的嗎?我覺得是不同的。方法 2 和方法 3 計算出來的
            實際上都是三角形面片的切空間,頂點的切空間還要通過平均頂點所在
            各個三角形面片的切空間基向量來計算。(是這樣的嗎?高手指教一下!)

            設三角形面片所在的切空間的基向量為 T, B, N,坐標原點在 P0。
            那么三角形面片中的任意向量應該可以表示為:
            Vec = x*T + y*B
            因此,如果我們找到了兩個向量 Vec1, Vec2 以及它們在 T, B 上的
            分量,那么自然就可以解出 T, B 了。
            令:
            Vec1 = P1 - P0
            Vec2 = P2 - P0
            dS1 = P1.s - P0.s
            dS2 = P2.s - P0.s
            dT1 = P1.t - P0.t
            dT2 = P2.t - p0.t
            那么我們有
            Vec1 = dS1*T + dT1*B (1)
            Vec2 = dS2*T + dT2*B (2)
            聯立 (1), (2) 就可以解出
            B*(dS2*dT1 - dS1*dT2) = (dS2*Vec1 - dS1*Vec2)
            所以:
            (dS2*dT1 - dS1*dT2) 是一個常數,反正我們之后要對 B 歸一化,
            可以不用管它。于是:
            B = normalize(dS2*Vec1 - dS1*Vec2) 這就是 MSDN 里那篇文章里的方法。
            B 可以通過解方程獲得,但是 T 就不行了,因為這樣解出來的 T 和
            B 不一定垂直。怎么處理呢?
            MSDN 中的方法是,利用頂點的 N 來求 T:
            T = B X N
            然后再求 N
            N = T X B
            但是這樣可以嗎?這里的 N 是頂點 P0 的 N,而不是三角形面片的 N。
            是不是這樣求出來的 T, N, B 恰好是頂點 P0 的切空間的坐標基,不需要
            再平均了?(高手指教!)
            我想的處理方法是這樣的:
            同樣解出 T 來:
            T = normalize(dT2*Vec1 - dT1*Vec2)
            然后 N = T X B。這個 N 是三角形面片的 N。
            然后 T = B X N。這樣 T, N, B 構成正交基,而且是三角形面片的。
            要計算 P0 頂點的切空間基,還需要平均多個面片。
            這種方法到是比較復雜。

            一個問題是,為什么有
            Vec1 = dS1*T + dT1*B (1)
            Vec2 = dS2*T + dT2*B (2)
            這兩個公式!
            我想是因為在計算頂點的紋理坐標時,因為是從平面映射到平面,所以我們使用了
            仿射變換:
            s = as*x + bs*y + cs
            t = as*x + bs*y + cs
            反過來我們有
            x = ax*s + bx*t + cx (3)
            y = ay*s + by*t + cy (4)
            z = az*s + bz*t + cz (5)
            于是
            Vec1.x = P1.x - P0.x = ax*(P1.s - P0.s) + bx*(P1.t - P0.t)
            Vec1.y = P1.y - P0.y = ay*(P1.s - P0.s) + by*(P1.t - P0.t)
            Vec1.z = P1.z - P0.z = az*(P1.s - P0.s) + bz*(P1.t - P0.t)
            于是
            Vec1 = {ax, ay, az}*dS1 + {bx, by, bz}*dT1
            這和 (1) 已經很象了,那么 {ax, ay, az} 就是 T 嗎?
            答案是是的!事實上 (3), (4), (5) 就是三角形面片的參數表示,那么
            T = {dx/ds, dy/ds, dz/ds} = {ax, ay, az}
            B = {dx/dt, dy/dt, dz/dt} = {bx, by, bz}
            也就是說,如果我們能直接把 ax, ay, az, bx, by, bz 求出來,T 和 B 就求出來了

            (當然要把他們正交歸一化)

            3 nVidia 網站上的方法。
            我們可以假設
            x = ax*s + bx*t + cx
            y = ay*s + by*t + cy
            z = az*s + bz*t + cz
            如何求解 (3) ?這里有 3 個未知數,那我們需要 3 個方程。
            將 3 個頂點的屬性 {x, y ,z}, {s, t} 帶入,剛好有三個方程:
            P0.x = ax*P0.s + bx*P0.t + cx (1)
            P1.x = ax*P1.s + bx*P1.t + cx (2)
            P2.x = ax*P2.s + bx*P2.t + cx (3)
            解出來就得到 ax, bx, cx 了。
            同理可得: ay, by, cy, az, bz, cz。
            T = {ax, ay, az}
            B = {bx, by, bz}
            N = T X B
            T = B X N
            然后都歸一化即可。

            nVidia 網站上的方法呢,是建立三個平面方程
            Ax*x + Bx*s + Cx*t + Dx = 0 (4)
            Ay*y + By*s + Cy*t + Dy = 0 (5)
            Az*z + Bz*s + Cz*t + Dz = 0 (6)

            并且指出,三角形面片上的所有點的 (x, s, t) 都在
            方程 (4) 定義的平面中。那么
            dx/ds = -Bx/Ax
            dx/dt = -Cx/Ax

            同理
            dy/ds = -By/Ay
            dy/dt = -Cy/Ay

            dz/ds = -Bz/Az
            dz/dt = -Cz/Az

            那么這些 Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz 怎么求呢?
            容易知道,{Ax, Bx, Cx} 其實是平面的法向量,那么可以
            選平面中的三個點,計算出兩個向量,然后叉乘。

            {Ax, Bx, Cx} = {P1.x - P0.x, P1.s - P0.s, P1.t - P0.t} X
            {P2.x - P0.x, P2.s - P0.s, P2.t - P0.t}

            這兩種方法是等價的。

            posted @ 2009-04-17 21:45 麒麟子 閱讀(556) | 評論 (0)編輯 收藏

            D3D API調用消耗表

            API Call Average number of Cycles
            SetVertexDeclaration 6500 - 11250
            SetFVF 6400 - 11200
            SetVertexShader 3000 - 12100
            SetPixelShader 6300 - 7000
            SPECULARENABLE 1900 - 11200
            SetRenderTarget 6000 - 6250
            SetPixelShaderConstant (1 Constant) 1500 - 9000
            NORMALIZENORMALS 2200 - 8100
            LightEnable 1300 - 9000
            SetStreamSource 3700 - 5800
            LIGHTING 1700 - 7500
            DIFFUSEMATERIALSOURCE 900 - 8300
            AMBIENTMATERIALSOURCE 900 - 8200
            COLORVERTEX 800 - 7800
            SetLight 2200 - 5100
            SetTransform 3200 - 3750
            SetIndices 900 - 5600
            AMBIENT 1150 - 4800
             SetTexture 2500 - 3100
            SPECULARMATERIALSOURCE 900 - 4600
            EMISSIVEMATERIALSOURCE 900 - 4500
            SetMaterial 1000 - 3700
            ZENABLE 700 - 3900
            WRAP0 1600 - 2700
            MINFILTER 1700 - 2500
            MAGFILTER 1700 - 2400
            SetVertexShaderConstant (1 Constant) 1000 - 2700
            COLOROP 1500 - 2100
            COLORARG2 1300 - 2000
            COLORARG1 1300 - 1980
            CULLMODE 500 - 2570
            CLIPPING 500 - 2550
            DrawIndexedPrimitive 1200 - 1400
            ADDRESSV 1090 - 1500
            ADDRESSU 1070 - 1500
            DrawPrimitive 1050 - 1150
            SRGBTEXTURE 150 - 1500
            STENCILMASK 570 - 700
            STENCILZFAIL 500 - 800
            STENCILREF 550 - 700
            ALPHABLENDENABLE 550 - 700
            STENCILFUNC 560 - 680
            STENCILWRITEMASK 520 - 700
            STENCILFAIL 500 - 750
            ZFUNC 510 - 700
            ZWRITEENABLE 520 - 680
            STENCILENABLE 540 - 650
            STENCILPASS 560 - 630
            SRCBLEND 500 - 685
            Two_Sided_StencilMODE 450 - 590
            ALPHATESTENABLE 470 - 525
            ALPHAREF 460 - 530
            ALPHAFUNC 450 - 540
            DESTBLEND 475 - 510
            COLORWRITEENABLE 465 - 515
            CCW_STENCILFAIL 340 - 560
            CCW_STENCILPASS 340 - 545
            CCW_STENCILZFAIL 330 - 495
            SCISSORTESTENABLE 375 - 440
            CCW_STENCILFUNC 250 - 480
            SetScissorRect 150 - 340
            使用D3D,我們就得知道常用的API的消耗,才能夠方便我們優化自己的渲染器。這里給出了常用API的消耗表,可以有一個直觀的比較。
            這個表也可以在D3D SDK文檔的 Accurately Profiling Direct3D API Calls (Direct3D 9) 一文中找到

             

            posted @ 2009-04-17 13:21 麒麟子 閱讀(517) | 評論 (3)編輯 收藏

            [導入]List methods



            Table 6.12. Constructors and Destructor of Lists Operation Effect
            list<Elem> c Creates an empty list without any elements
            list<Elem> c1(c2) Creates a copy of another list of the same type (all elements are copied)
            list<Elem> c(n) Creates a list with n elements that are created by the default constructor
            list<Elem> c(n,elem) Creates a list initialized with n copies of element elem
            list<Elem> c (beg,end) Creates a list initialized with the elements of the range [beg,end)
            c.~list<Elem>() Destroys all elements and frees the
            memory

            Table 6.13. Nonmodifying Operations of Lists Operation Effect
            c.size() Returns the actual number of elements
            c. empty () Returns whether the container is empty (equivalent to size()==0, but might be faster)
            c.max_size() Returns the maximum number of elements possible
            c1 == c2 Returns whether c1 is equal to c2
            c1 != c2 Returns whether c1 is not equal to c2 (equivalent to ! (c1==c2))
            c1 < c2 Returns whether c1 is less than c2
            c1 > c2 Returns whether c1 is greater than c2 (equivalent to c2<c1)
            c1 <= c2 Returns whether c1 is less than or equal to c2 (equivalent to ! (c2<c1) )
            c1 >= c2 Returns whether c1 is greater than or equal to c2 (equivalent to ! (c1<c2))

            Table 6.14. Assignment Operations of Lists Operation Effect
            c1 = c2 Assigns all elements of c2 to c1
            c.assign(n,elem) Assigns n copies of element elem
            c.assign(beg,end) Assigns the elements of the range [beg,end)
            c1.swap(c2) Swaps the data of c1 and c2
            swap(c1,c2) Same (as global function)

            Table 6.15. Direct Element Access of Lists Operation Effect
            c.front() Returns the first element (no check whether a first element exists)
            c.back() Returns the last element (no check whether a last element exists)

            Table 6.16. Iterator Operations of Lists Operation Effect
            c.begin() Returns a bidirectional iterator for the first element
            c.end() Returns a bidirectional iterator for the position after the last element
            c.rbegin() Returns a reverse iterator for the first element of a reverse iteration
            c.rend() Returns a reverse iterator for the position after the last element of a reverse iteration

            Table 6.17. Insert and Remove Operations of Lists Operation Effect
            c.insert (pos, elem) Inserts at iterator position pos a copy of elem and returns the position of the new element
            c.insert (pos,n, elem) Inserts at iterator position pos n copies of elem (returns nothing)
            c. insert (pos, beg,end) Inserts at iterator position pos a copy of all elements of the range [beg,end) (returns nothing)
            c.push_back(elem) Appends a copy of elem at the end
            c.pop_back() Removes the last element (does not return it)
            c.push_front(elem) Inserts a copy of elem at the beginning
            c.pop_front () Removes the first element (does not return it)
            c. remove (val) Removes all elements with value val
            c.remove_if (op) Removes all elements for which op(elem) yields true
            c. erase (pos) Removes the element at iterator position pos and returns the position of the next element
            c.erase (beg,end) Removes all elements of the range [beg,end) and returns the position of the next element
            c. resize (num) Changes the number of elements to num (if size() grows, new elements are created by their default constructor)
            c.resize (num, elem) Changes the number of elements to num (if size ( ) grows, new elements are copies of elem)
            c. clear () Removes all elements (makes the container empty)

            Table 6.18. Special Modifying Operations for Lists Operation Effect
            c.unique() Removes duplicates of consecutive elements with the same value
            c.unique(op) Removes duplicates of consecutive elements, for which op() yields true
            c1.splice(pos,c2) Moves all elements of c2 to c1 in front of the iterator position pos
            c1.splice(pos,c2,c2pos) Moves the element at c2pos in c2 in front of pos of list c1 (c1 and c2 may be identical)
            c1.splice(pos,c2,c2beg,c2end) Moves all elements of the range [c2beg,c2end) in c2 in front of pos of list c1 (c1 and c2 may be identical)
            c.sort() Sorts all elements with operator <
            c.sort(op) Sorts all elements with op()
            c1.merge(c2) Assuming both containers contain the elements sorted, moves all elements of c2 into c1 so that all elements are merged and still sorted
            c1.merge(c2,op) Assuming both containers contain the elements sorted due to the sorting criterion op(), moves all elements of c2 into c1 so that all elements are merged and still sorted according to op()
            c.reverse() Reverses the order of all elements

            Examples of Using Lists
            The following example in particular shows the use of the special member functions for lists:


            // cont/list1.cpp

            #include <iostream>
            #include <list>
            #include <algorithm>
            using namespace std;

            void printLists (const list<int>& 11, const list<int>& 12)
            {

            cout << "list1: ";
            copy (l1.begin(), l1.end(), ostream_iterator<int>(cout," "));
            cout << endl << "list2: ";
            copy (12.begin(), 12.end(), ostream_iterator<int>(cout," "));
            cout << endl << endl;

            }

            int main()
            {

            //create two empty lists
            list<int> list1, list2;

            //fill both lists with elements
            for (int i=0; i<6; ++i) {
            list1.push_back(i);
            list2.push_front(i);
            }
            printLists(list1, list2);

            //insert all elements of list1 before the first element with value 3 of list2
            //-find() returns an iterator to the first element with value 3
            list2.splice(find(list2.begin(),list2.end(), // destination position
            3),
            list1); // source list
            printLists(list1, list2);

            //move first element to the end
            list2.splice(list2.end(), // destination position
            list2, // source list
            list2.begin()); // source position
            printLists(list1, list2);

            //sort second list, assign to list1 and remove duplicates
            list2.sort();
            list1 = list2;
            list2.unique();
            printLists(list1, list2);

            //merge both sorted lists into the first list
            list1.merge(list2);
            printLists(list1, list2);
            }


            The program has the following output:


            list1: 0 1 2 3 4 5
            list2: 5 4 3 2 1 0

            list1:
            list2: 5 4 0 1 2 3 4 5 3 2 1 0

            list1:
            list2: 4 0 1 2 3 4 5 3 2 1 0 5

            list1: 0 0 1 1 2 2 3 3 4 4 5 5
            list2: 0 1 2 3 4 5

            list1: 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5
            list2:


            Vector的
            //建立一個向量并為之分配內存
            std::vector<int> v; // create an empty vector
            v.reserve (80); // reserve memory for 80 elements
            //建立一個向量,并用默認的構造函數初始化,因此速度較慢
            std::vector<T> v(5); // creates a vector and initializes it with five values
            // (calls five times the default constructor of type T)


            Table 6.2. Constructors and Destructors of Vectors Operation Effect
            vector<Elem> c Creates an empty vector without any elements
            vector<Elem> c1(c2) Creates a copy of another vector of the same type (all elements are copied)
            vector<Elem> c(n) Creates a vector with n elements that are created by the default constructor
            vector<Elem> c(n,elem) Creates a vector initialized with n copies of element elem
            vector<Elem> c(beg,end) Creates a vector initialized with the elements of the range [beg,end)
            c.~vector<Elem>() Destroys all elements and frees the memory

            Table 6.3. Nonmodifying Operations of Vectors Operation Effect
            c.size() Returns the actual number of elements
            c.empty() Returns whether the container is empty (equivalent to size()==0, but might be faster)
            c.max_size() Returns the maximum number of elements possible
            capacity() Returns the maximum possible number of elements without reallocation
            reserve() Enlarges capacity, if not enough yet[7] //如果不夠的話就繼續分配內存
            c1 == c2 Returns whether c1 is equal to c2
            c1 != c2 Returns whether c1 is not equal to c2 (equivalent to ! (c1==c2))
            c1 < c2 Returns whether c1 is less than c2
            c1 > c2 Returns whether c1 is greater than c2 (equivalent to c2<c1)
            c1 <= c2 Returns whether c1 is less than or equal to c2 (equivalent to ! (c2<c1))
            c1 >= c2 Returns whether c1 is greater than or equal to c2 (equivalent to ! (c1<c2))

            Table 6.4. Assignment Operations of Vectors Operation Effect
            c1 = c2 Assigns all elements of c2 to c1
            c.assign(n,elem) Assigns n copies of element elem
            c.assign(beg,end) Assigns the elements of the range [beg,end)
            c1.swap(c2) Swaps the data of c1 and c2
            swap(c1,c2) Same (as global function)

            Table 6.5. Direct Element Access of Vectors Operation Effect
            c.at(idx) Returns the element with index idx (throws range error exception if idx is out of range)
            c[idx] Returns the element with index idx (no range checking)
            c.front() Returns the first element (no check whether a first element exists)
            c.back() Returns the last element (no check whether a last element exists)

            通過at來訪問元素的時候如果越界會有一個out_of_range異常
            用[]重載來訪問的時候只會報錯

            Table 6.6. Iterator Operations of Vectors Operation Effect
            c.begin() Returns a random access iterator for the first element
            c.end() Returns a random access iterator for the position after the last element
            c.rbegin() Returns a reverse iterator for the first element of a reverse iteration
            c.rend() Returns a reverse iterator for the position after the last element of a reverse iteration

            Table 6.7. Insert and Remove Operations of Vectors Operation Effect
            c.insert(pos,elem) Inserts at iterator position pos a copy of elem and returns the position of the new element
            c.insert(pos,n,elem) Inserts at iterator position pos n copies of elem (returns nothing)
            c.insert(pos,beg,end) Inserts at iterator position pos a copy of all elements of the range [beg,end) (returns nothing)
            c.push_back(elem) Appends a copy of elem at the end
            c.pop_back() Removes the last element (does not return it)
            c.erase(pos) Removes the element at iterator position pos and returns the position of the next element
            c.erase(beg,end) Removes all elements of the range [beg,end) and returns the position of the next element
            c.resize(num) Changes the number of elements to num (if size() grows, new elements are created by their default constructor)
            c.resize(num,elem) Changes the number of elements to num (if size() grows, new elements are copies of elem)
            c.clear() Removes all elements (makes the container empty)

            std::vector<Elem> coll;
            ...
            //remove all elements with value val
            coll.erase(remove(coll.begin(),coll.end(),
            val),
            coll.end());

            std::vector<Elem> coll;
            ...
            //remove first element with value val
            std::vector<Elem>::iterator pos;
            pos = find(coll.begin(),coll.end(),
            val);
            if (pos != coll.end()) {
            coll.erase(pos);
            }

            vector<bool>有特殊的函數
            Table 6.8. Special Operations of vector<bool> Operation Effect
            c.flip() Negates all Boolean elements (complement of all bits)
            m[idx].flip() Negates the Boolean element with index idx (complement of a single bit)
            m[idx] = val Assigns val to the Boolean element with index idx (assignment to a single bit)
            m[idx1] = m[idx2] Assigns the value of the element with index idx2 to the element with index idx1

            Examples of Using Vectors
            The following example shows a simple usage of vectors:


            // cont/vector1.cpp

            #include <iostream>
            #include <vector>
            #include <string>
            #include <algorithm>
            using namespace std;

            int main()
            {

            //create empty vector for strings
            vector<string> sentence;

            //reserve memory for five elements to avoid reallocation
            sentence.reserve(5);

            //append some elements
            sentence.push_back("Hello,");
            sentence.push_back("how");
            sentence.push_back("are");
            sentence.push_back("you");
            sentence.push_back("?");

            //print elements separated with spaces
            copy (sentence.begin(), sentence.end(),
            ostream_iterator<string>(cout," "));
            cout << endl;

            //print ''technical data''
            cout << " max_size(): " << sentence.max_size() << endl;
            cout << " size(): " << sentence.size() << endl;
            cout << " capacity(): " << sentence.capacity() << endl;

            //swap second and fourth element
            swap (sentence[1], sentence [3]);

            //insert element "always" before element "?"
            sentence.insert (find(sentence.begin(),sentence.end(),"?"),
            "always");

            //assign "!" to the last element
            sentence.back() = "!";

            //print elements separated with spaces
            copy (sentence.begin(), sentence.end(),
            ostream_iterator<string>(cout," "));
            cout << endl;

            //print "technical data" again
            cout << " max_size(): " << sentence.max_size() << endl;
            cout << " size(): " << sentence.size() << endl;
            cout << " capacity(): " << sentence.capacity() << endl;

            }


            The output of the program might look like this:


            Hello, how are you ?
            max_size(): 268435455
            size(): 5
            capacity(): 5
            Hello, you are how always !
            max_size(): 268435455
            size(): 6
            capacity(): 10

            文章來源:http://ly-weiwei.blog.163.com/blog/static/7297528320092311263852

            posted @ 2009-03-31 13:26 麒麟子 閱讀(71) | 評論 (0)編輯 收藏

            [導入]DX 骨骼動畫

            第一,了解骨骼結構(Skeletal Structures)和骨層級(Bone Hierarchies):

            骨骼結構就是連續很多的骨頭(Bone)相結合,形成的骨層級。第一個骨頭叫做根骨(root bone),是形成骨骼結構的關鍵點。其它所有的骨骼作為孩子骨(child bone)或者兄弟骨(sibling bone)附加在根骨之上。所謂的“骨”用一個幀(frame)對象表示。在Directx中,用一個D3DXFRAME結構或者X文件中的Frame template來表示幀對象。下面看一下Frame template和D3DXFRAME結構的定義:

            template Frame
            {
                    < 3D82AB46-62DA-11cf-AB39-0020AF71E433 >
                    FrameTransformMatrix frameTransformMatrix;      // 骨骼相對于父節點的坐標變換矩陣,就是一個matrix
                    Mesh mesh;                                      // 骨骼的Mesh
            }

            typedef struct _D3DXFRAME
            {
            LPSTR                   Name;                   // 骨骼名稱
            D3DXMATRIX         TransformationMatrix;        // 相對與父節點的坐標變換矩陣
            LPD3DXMESHCONTAINER     pMeshContainer; // LPD3DXMESHCONTAINER對象,
            //用來加載MESH,還有一些附加屬性,見SDK
            struct _D3DXFRAME       *pFrameSibling;         // 兄弟節點指針,和下面的子節點指針
            // 一塊作用構成骨骼的層次結構。   
                struct _D3DXFRAME       *pFrameFirstChild;   // 子節點指針
            } D3DXFRAME, *LPD3DXFRAME;


            注意D3DXFRAME * pFrameSibling和D3DXFRAME * pFrameFirstChild,主要是利用這兩個指針形成骨層級。pFrameSibling把一個骨頭連接到兄弟層級,相對的,pFrameFirstChild把一個骨頭連接到子層級。通常,你需要用建模軟件為你的程序創建那些骨骼結構,輸出骨層級到X文件以便使用。Microsoft有3D Studio Max和Maya的輸出插件(exporter),可以輸出骨骼和動畫數據到X文件。很多建模程序也都有這樣的功能。


            利用D3DXFRAME pointers指針形成了一個兄弟幀和孩子幀的鏈表。

            在前面template Frame中已經提及過每個Frame數據對象中存放著一個變換矩陣,這個矩陣描述了該骨骼相對于父骨骼的位置。另外在根Frame數據對象中內嵌了一個標準的Mesh數據對象。Frame定義了骨骼的層級,而Mesh中的SkinWeights數據對象定義了Frame代表的骨頭。我們用D3DXFRAME結構容納從X文件加載進來的Frame數據對象。為了更好的容納Frame數據對象,我們需要擴展下D3DXFRAME結構:

            struct D3DXFRAME_EX : D3DXFRAME
            {
            D3DXMATRIX matCombined;   // 組合變換矩陣,用于儲存變換的骨骼矩陣
            D3DXMATRIX matOriginal;   // 從X文件加載的原始變換矩陣
            D3DXFRAME_EX()
            {
                Name = NULL;
                pMeshContainer = NULL;
                pFrameSibling = pFrameFirstChild = NULL;
                D3DXMatrixIdentity(&matCombined);
                D3DXMatrixIdentity(&matOriginal);
                D3DXMatrixIdentity(&TransformationMatrix);
            }

            ~D3DXFRAME_EX()
            {
                delete [] Name;          Name = NULL;
                delete pFrameSibling;    pFrameSibling = NULL;
                delete pFrameFirstChild; pFrameFirstChild = NULL;
            }
            }

            利用我們以前介紹的cXParse類可以遍歷X文件的數據對象,從而加載出Frame數據對象。下面的代碼都是寫在方法ParseObject中,如下:

            // 判斷當前分析的是不是Frame節點
            if( objGUID == TID_D3DRMFrame )
            {
            // 引用對象直接返回,不需要做分析。一個數據段實際定義一次后可以被其他模板引用,例
            //如后面的Animation動畫模板就會引用這里的Frame
            // 節點,標識動畫關聯的骨骼。
            if( pDataObj->IsReference() )
            return true;
                    // D3DXFRAME_EX為D3DXFRAME的擴展結構,增加些數據成員
                    D3DXFRAME_EX *pFrame = new D3DXFRAME_EX();

            // 得到名稱
                    pFrame->Name = GetObjectName( pDataObj );

            // 注意觀察文件就可以發現一個Frame要么是根Frame,父節點不存在, 要么作為某

            //個Frame的孩子Frame而存在。
                    if( NULL == pData )
                    {
                            // 作為根節點的兄弟節點加入鏈表。
                            pFrame->pFrameSibling = m_pRootFrame;
                            m_pRootFrame = pFrame;
                            pFrame = NULL;
                        // 將自定義數據指針指向自己,供子節點引用。
                            pData = ( void** )&m_pRootFrame;
                     }
                     else
                     {
                            // 作為傳入節點的子節點
                            D3DXFRAME_EX *pDataFrame = ( D3DXFRAME_EX* )( *pData );
                            pFrame->pFrameSibling = pDataFrame->pFrameFirstChild;
                            pDataFrame->pFrameFirstChild = pFrame;
                            pFrame = NULL;
                            pData = ( void** )&pDataFrame->pFrameFirstChild;
                      }
            }

            記住我們只需要做一件事情,判斷類型,分配匹配的對象然后拷貝數據,下面來分析Frame中的matrix,

            // frame的坐標變換矩陣, 因為matrix必然屬于某個Frame所以pData必須有效
            else if( objGUID == TID_D3DRMFrameTransformMatrix && pData )
            {
                      // 我們可以肯定pData指向某個Frame
                      D3DXFRAME_EX *pDataFrame = ( D3DXFRAME_EX* )( *pData );
                      // 先取得緩沖區大小,應該是個標準的4x4矩陣
                      DWORD size = 0;
                      LPCVOID buffer = NULL;

                      hr = pDataObj->Lock( &size, &buffer );
                      if( FAILED( hr ) )
            return false;

                      // 拷貝數據
                      if( size == sizeof( D3DXMATRIX ) )
                      {
                           memcpy( &pDataFrame->TransformationMatrix, buffer, size );
                           pDataObj->Unlock();
                           pDataFrame->matOriginal = pDataFrame->TransformationMatrix;
                      }
            }

            第二,修改和更新骨骼層級:

            加載完骨骼層級之后,你可以操作它,更改骨骼的方位。你需要創建一個遞歸函數,按照名字找到相應的Frame數據對象。這個函數如下:

            D3DXFRAME_EX *FindFrame(D3DXFRAME_EX *Frame, char *Name)
            {
            if(Frame && Frame->Name && Name) {
            // 如果名字找到,返回一個Frame指針
            if(!strcmp(Frame->Name, Name)) // strcmp函數比較兩個字符串,如果兩個字符串相等,返回0
            return Frame;
            }
            // 在sibling frames找匹配的名字
            if(Frame && Frame->pFrameSibling) {
            D3DXFRAME_EX *FramePtr = FindFrame((D3DXFRAME_EX*)Frame->pFrameSibling, Name);
            if(FramePtr)
            return FramePtr;

            }
            // 在child frames找匹配的名字
            if(Frame && Frame->pFrameFirstChild) {
            D3DXFRAME_EX *FramePtr = FindFrame((D3DXFRAME_EX*)Frame->pFrameFirstChild,Name);
            if(FramePtr)
            return FramePtr;
            }
            // 如果沒有找到,返回 NULL
            return NULL;
            }

            如果你想找到一個叫“Leg”的Frame,可以把“Leg”傳入FindFrame函數,并且提供指向RootFrame的指針:
            // pRootframe 為D3DXFRAME_EX root frame 指針
            D3DXFRAME_EX *Frame = FindFrame(pRootFrame, "Leg");
            if(Frame) {
            // 可以在這里做一些處理,比如旋轉操作
            // 你在這里可以稍微的旋轉這個骨頭
            D3DXMatrixRotationY(&Frame->TransformationMatrix, 1.57f);
            }

            一旦你修改變換骨頭,你需要更新整個骨骼層級,也就是把變換的組合矩陣存入D3DXFRAME_EX結構的matCombined成員中,用于后面的渲染。下面的函數應該增加到D3DXFRAME_EX結構中,如下:

            void UpdateHierarchy(D3DXMATRIX *matTransformation = NULL)
            {
                D3DXFRAME_EX *pFramePtr;
                D3DXMATRIX matIdentity;
                // 如果為空,用一個全同矩陣
                if(!matTransformation) {
                  D3DXMatrixIdentity(&matIdentity);
                  matTransformation = &matIdentity;
                }
                // 把變換矩陣組合到matCombined中
                matCombined = TransformationMatrix * (*matTransformation);
                // 更新兄弟層級
                if((pFramePtr = (D3DXFRAME_EX*)pFrameSibling))
                  pFramePtr->UpdateHierarchy(matTransformation);
                // 更新孩子層級
                if((pFramePtr = (D3DXFRAME_EX*)pFrameFirstChild))
                  pFramePtr->UpdateHierarchy(&matCombined);
            }
            現在matCombined儲存著每個骨骼相對于原點的變換矩陣,然后只要把各個頂點附在相應的骨骼上,就能渲染了。

            第三,使用蒙皮網格:

            蒙皮網格和普通網格的唯一不同點就是看XskinMeshHeader和SkinWeights模版是否存在。如果把這兩個模版從任何一個蒙皮網格里面移走的話,就可以得到一個普通網格。在X文件中,我們將會發現一個GUID為TID_D3DRMMesh的模版,這表示模版里面存有一個網格。利用D3D的幫助函數D3DXLoadSkinMeshFromXof將會加載蒙皮網格和其它補充性數據。只需要向它傳遞一個IDirectXFileData指針,然后它將為你做剩下的事情。現在介紹下D3DXLoadSkinMeshFromXof函數:

            HRESULT D3DXLoadSkinMeshFromXof(
            LPD3DXFILEDATA pxofMesh,        //X文件數據接口
            DWORD Options,                   //加載參數
            LPDIRECT3DDEVICE9 pD3DDevice, //使用的三維設備
            LPD3DXBUFFER * ppAdjacency,      //鄰接信息緩沖接口
            LPD3DXBUFFER * ppMaterials,       //材質緩沖接口
            LPD3DXBUFFER * ppEffectInstances, //效果實例接口
            DWORD * pMatOut,                 //材質數
            LPD3DXSKININFO * ppSkinInfo,      //蒙皮信息接口
            LPD3DXMESH * ppMesh             //加載的網格模型接口
            );


            文章來源:http://ly-weiwei.blog.163.com/blog/static/72975283200922394958876

            posted @ 2009-03-23 21:50 麒麟子 閱讀(237) | 評論 (0)編輯 收藏

            [導入]引用 開始→運行:運行什么

            引用

            紫色思念開始→運行:運行什么


            1.Control
            Control 控制面板
            Control userpasswords2 用戶賬戶
            Control access.cpl 輔助功能選項
            Control appwiz.cpl 添加刪除程序
            Control bthprops.cpl 藍牙支持服務
            Control desk.cpl 顯示屬性
            Control firewall.cpl Windows防火墻
            Control hdwwiz.cpl 添加硬件
            Control inetcpl.cpl Internet選項
            Control intl.cpl 區域和語言選項
            Control irprops.cpl 無線連接
            Control joy.cpl 游戲控制器
            Control main.cpl 鼠標
            Control mmsys.cpl 聲音和音頻設備
            Control ncpa.cpl 網絡連接
            Control netsetup.cpl 網絡安裝向導
            Control nusrmgr.cpl 用戶賬戶
            Control nvtuicpl.cpl Nvidia顯示屬性
            Control odbccp32.cpl ODBC數據源管理器
            Control powercfg.cpl 電源選項
            Control sysdm.cpl 系統屬性
            Control telephon.cpl 電話和調制解調器
            Control timedate.cpl 日期和時間
            Control wscui.cpl Windows安全中心
            Control wuaucpl.cpl 自動更新
            2.Shell
            shell:Common Administrative Tools 管理工具
            shell:Administrative Tools
            shell:SystemX86 System32
            shell:My Pictures
            shellrofile %userprofile%
            shell:CommonProgramFiles
            shellrogramFiles %programfiles%
            shell:System
            shell:Windows %windir%
            shell:History
            shell:Cookies
            shellocal AppData
            shell:AppData
            shell:Common Documents
            shell:Common Templates
            shell:Common AppData
            shell:Common Favorites
            shell:Common Desktop
            shell:Common Menu
            shell:Common Programs
            shell:Common Startup
            shell:Templates
            shellrintHood
            shell:NetHood
            shell:Favorites
            shellersonal
            shell:SendTo
            shell:Recent
            shell:Menu
            shellrograms
            shell:Startup
            shellesktop
            shell:Fonts
            shell:ConnectionsFolder
            shell:RecycleBinFolder
            shellrintersFolder
            shell:ControlPanelFolder Control
            shell:InternetFolder
            shellriveFolder
            shell:NetworkFolder
            shellesktopFolder


            開始→運行→命令 集錦(絕對值得收藏)


            開始→運行→命令 集錦

            winver---------檢查Windows版本
            wmimgmt.msc----打開windows管理體系結構(WMI)
            wupdmgr--------windows更新程序
            wscript--------windows腳本宿主設置
            write----------寫字板
            winmsd---------系統信息
            wiaacmgr-------掃描儀和照相機向導
            winchat--------XP自帶局域網聊天

            mem.exe--------顯示內存使用情況
            Msconfig.exe---系統配置實用程序
            mplayer2-------簡易widnows media player
            mspaint--------畫圖板
            mstsc----------遠程桌面連接
            mplayer2-------媒體播放機
            magnify--------放大鏡實用程序
            mmc------------打開控制臺
            mobsync--------同步命令

            dxdiag---------檢查DirectX信息
            drwtsn32------ 系統醫生
            devmgmt.msc--- 設備管理器
            dfrg.msc-------磁盤碎片整理程序
            diskmgmt.msc---磁盤管理實用程序
            dcomcnfg-------打開系統組件服務
            ddeshare-------打開DDE共享設置
            dvdplay--------DVD播放器

            net stop messenger-----停止信使服務
            net start messenger----開始信使服務
            notepad--------打開記事本
            nslookup-------網絡管理的工具向導
            ntbackup-------系統備份和還原
            narrator-------屏幕“講述人”
            ntmsmgr.msc----移動存儲管理器
            ntmsoprq.msc---移動存儲管理員操作請求
            netstat -an----(TC)命令檢查接口

            syncapp--------創建一個公文包
            sysedit--------系統配置編輯器
            sigverif-------文件簽名驗證程序
            sndrec32-------錄音機
            shrpubw--------創建共享文件夾
            secpol.msc-----本地安全策略
            syskey---------系統加密,一旦加密就不能解開,保護windows xp系統的雙重密碼
            services.msc---本地服務設置
            Sndvol32-------音量控制程序
            sfc.exe--------系統文件檢查器
            sfc /scannow---windows文件保護

            tsshutdn-------60秒倒計時關機命令
            tourstart------xp簡介(安裝完成后出現的漫游xp程序)
            taskmgr--------任務管理器

            eventvwr-------事件查看器
            eudcedit-------造字程序
            explorer-------打開資源管理器


            packager-------對象包裝程序
            perfmon.msc----計算機性能監測程序
            progman--------程序管理器

            regedit.exe----注冊表
            rsop.msc-------組策略結果集
            regedt32-------注冊表編輯器
            rononce -p ----15秒關機
            regsvr32 /u *.dll----停止dll文件運行
            regsvr32 /u zipfldr.dll------取消ZIP支持

            cmd.exe--------CMD命令提示符
            chkdsk.exe-----Chkdsk磁盤檢查
            certmgr.msc----證書管理實用程序
            calc-----------啟動計算器
            charmap--------啟動字符映射表
            cliconfg-------SQL SERVER 客戶端網絡實用程序
            Clipbrd--------剪貼板查看器
            conf-----------啟動netmeeting
            compmgmt.msc---計算機管理
            cleanmgr-------垃圾整理
            ciadv.msc------索引服務程序

            osk------------打開屏幕鍵盤
            odbcad32-------ODBC數據源管理器
            oobe/msoobe /a----檢查XP是否激活
            lusrmgr.msc----本機用戶和組
            logoff---------注銷命令


            iexpress-------木馬捆綁工具,系統自帶

            Nslookup-------IP地址偵測器

            fsmgmt.msc-----共享文件夾管理器

            utilman--------輔助工具管理器

            gpedit.msc-----組策略


            文章來源:http://ly-weiwei.blog.163.com/blog/static/729752832009181554598

            posted @ 2009-02-08 13:55 麒麟子 閱讀(178) | 評論 (0)編輯 收藏

            僅列出標題
            共38頁: First 26 27 28 29 30 31 32 33 34 Last 
            人妻精品久久久久中文字幕69 | 久久免费香蕉视频| 久久精品国产99国产电影网| 中文字幕成人精品久久不卡| 亚洲欧洲精品成人久久奇米网| 久久婷婷五月综合国产尤物app| 久久人人爽人人爽人人AV| 丁香狠狠色婷婷久久综合| 久久久久婷婷| 精品亚洲综合久久中文字幕| 亚洲午夜无码久久久久小说| 久久久久亚洲精品无码蜜桃| 国产精品青草久久久久福利99| 色偷偷88888欧美精品久久久| 成人a毛片久久免费播放| 久久久SS麻豆欧美国产日韩| 久久综合久久综合九色| 久久久SS麻豆欧美国产日韩| 久久国产午夜精品一区二区三区| 久久狠狠高潮亚洲精品 | 精品久久久一二三区| 国产午夜福利精品久久| 久久青青草原亚洲av无码app| 2020久久精品亚洲热综合一本| 国产亚洲成人久久| 久久这里只有精品久久| 97r久久精品国产99国产精| 漂亮人妻被中出中文字幕久久| 久久一区二区三区99| 午夜不卡888久久| 久久综合九色综合久99| 国产精品久久久亚洲| 久久精品亚洲精品国产色婷 | 欧美精品丝袜久久久中文字幕 | 久久99国产精品久久99小说| 久久久久亚洲精品无码网址 | 亚洲一本综合久久| 2021久久国自产拍精品| 狠狠色丁香久久婷婷综合五月 | 亚洲一区精品伊人久久伊人| 欧美午夜A∨大片久久 |