麒麟子

~~

导航

<2024年8月>
28293031123
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 麒麟子 阅读(528) | 评论 (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 麒麟子 阅读(501) | 评论 (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 麒麟子 阅读(67) | 评论 (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 麒麟子 阅读(225) | 评论 (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 麒麟子 阅读(167) | 评论 (0)编辑 收藏

仅列出标题
共38页: First 26 27 28 29 30 31 32 33 34 Last