转的啊
人总是会为自己找捷径,而往往捷径是要付出不一般的代价。 呵呵—说说矩阵的事: 通过坐标变换将3D空间的图元转换成2D图元的过程:主要为世界变换->视图变换->投影变换->视口变换 3D场景中的任何物体,都是由一个一个三角形组成的。而三角形位置信息的就是其各个顶点的三维坐标。这是用来在模型中存储的,而要把物体显示在屏幕上,还需要将它们转换成显示器上的二维坐标。这就需要对每个点实施一套 3 to 2 的转换公式,在Direct3D中叫做“几何流水线”(Geometry Pipeline)。 一般创建的mesh处于自己的局部坐标系。基本是屏幕正中放置。
世界矩阵:而游戏需要先放入世界坐标系。世界坐标系主要3大功能:平移、旋转、缩放 平移: D3DXMatrixTranslation() 位于矩阵第四行
1 0 0 0
0 1 0 0
0 0 1 0
Tx Ty Tz 1
旋转: D3DXMatrixRotationX() 延 x 轴旋转
1 0 0 0
0 cos sin 0
0 -sin cos 0
0 0 0 1
D3DXMatrixRotationY() 延 y 轴旋转
cos 0 -sin 0
0 1 0 0
sin 0 cos 0
0 0 0 1
D3DXMatrixRotationZ() 延 z 轴旋转
cos sin 0 0
-sin cos 0 0
0 0 1 0
0 0 0 1
缩放: D3DXMatrixScaling
顺序如先旋转R在缩放S 则矩阵为 R*S 。对于行向量(dx默认为行向量)复合矩阵视觉效果为从左到右的顺序各单独矩阵效果的组合。对于列向量则相反: 复合矩阵应为 S * R.视觉效果从右到左(这是opengl 采用的)
观察矩阵:函数 D3DXMatrixLookAtLH()
不要被这个函数吓倒。其实观察矩阵作用和世界矩阵差不多,只是起到旋转、平移的作用。而且是把世界坐标系的物体映射到观察坐标系。只要用摄像机世界变换的逆就好了
V = T*Rz*Ry*Rz 。
实际上可以先获得摄像机的世界坐标 p,和摄像机坐标系轴在世界坐标中的矢量D(看向),U(上),R(右)。然后要把世界坐标的摄像机位置点换算到摄像机局部坐标系中。 (-D * p, - U * p, - R * p) 计算-p 在(D,U,R)矢量上的投影转换为p1.
Dx, Ux, Rx, 0
Dy, Uy, Ry, 0
Dz, Uz, Rz, 0
p1x,p1yp1z, 1
对于D,U,R 其实就是摄像机的世界坐标旋转变换的逆矩阵。如下:
Dx,Dy,Dz
Ux,Uy,Uz
Rx,Ry,Rz
旋转矩阵(还有镜像矩阵)为正交矩阵(参考3D数学基础中的矩阵正交化章节)。所以他的逆矩阵等于转置矩阵
这些不会影响mesh 的顶点和法线关系 使用shader时。如计算顶点和法线的点积,没必要映射到观察坐标系.在 direct3d 游戏编程基础的 shader 章节里。顶点法线和光线矢量都映射到了视图空间。其实是没有必要的
而世界变化和观察变换是可以和到一起组成世界-视图变换矩阵
投影变换:把3d 投影到2d平面。(似乎说映射[-1,-1,0(opengl 为-1)] 到[1,1,1]的立方体更好一些)分为透视投影和正交投影。正交投影不会随物体远近影响物体投影的大小。而透视则z值影响,物体越远成像越小。 投影变换涉及缩放和平移操作。对于正交投影矩阵缩放和z值无关。对于透视投影缩放和z值相关。 对于dx 左手坐标系函数如下: 正交投影函数: D3DXMatrixOrthoLH() 这个是以屏幕中心为坐标原点的。 如果设置2d坐标系。 可以考虑使用 D3DXMatrixOrthoOffCenterLH 函数 D3DXMatrixOrthoOffCenterLH(&m_matProj,0,(float)m_iWidth,(float)m_iHeight,0,0.0f,1.0f); 这样左上角为坐标(0,0). 右下角为(width,height) 透视投影: D3DXMatrixPerspectiveFovLH() 对于Opengl经过投影变换x,y,z映射到范围[-1,1]. x,y 还保持原来的符号。对于z 最远面 f 映射为1,最近面 n 映射为 -1. 但directx z 值略有差异。z 映射范围为[0,1]。最远面映射为1。最近面映射为0. 对于z值都是以 1/z 映射到 [0,1]或者[-1,1] 范围。因为一般要求近处z值判断要精细一些。而远处精度要小一些。所以用1/z来判断更好。 一个dx 投影矩阵如下: w,h 为 zn 面的宽度和高度。zn 近表面距离。zf 为远表面。
2*zn/w 0 0 0
0 2*zn/h 0 0
0 0 zf/(zf-zn) 1
0 0 zn*zf/(zn-zf) 0
其次坐标一个点p(px,py,pz,1) 经过这个变化成为(x’pz,y’pz,z’pz,pz) dx 一直透视投影函数一直默认了中心点为[0,0] (摄像机坐标x,y). 如果视景截头体不以[0,0]为中心则需要自己生成投影矩阵。 如对于zn平面,左l 右 r 上 t 下 b.这样 w = r - l h = t - b .建立的非对称投影矩阵如下(相对于dx左手坐标,对于opengl略有不同)
2*zn/r-l 0 0 0
0 2*zn/t-b 0 0
r+l/r-l t+b/t-b zf/(zf-zn) 1
0 0 zn*zf/(zn-zf) 0
dx 采用的是行向量,对于一个矢量 v 变换相当于 v * T. 而不是 T * v opengl 采用的是列向量, 对于矢量变化为 T * v
左手坐标系和右手坐标系平移、缩放矩阵是相同的。 对于旋转矩阵,输入角度时有变化: 从轴的负端向正端看,左手坐标系 逆时针为正方向。即逆时针延z旋转旋转30 度。输入正数30 到旋转矩阵. 而右手坐标系相反,逆时针为负方向。即逆时针延z旋转30度。输入-30 到旋转矩阵
用U0 U1 U2 表示变换矩阵, 对于矩阵 R(U0 | U1 | U2) 对于右手坐标 U0 = U1 X U2 U1 = U2 X U0 U2 = U0 X U1 对于左手坐标 U0 = U2 X U1 U1 = U0 X U2 U2 = U1 X U0
而有些系统如gamebryo 采用右手坐标系,这样虽然输入-30度,再经过转置成列向量矩阵,经过2次变换和dx的旋转矩阵结果反倒是相同的。但 dx 是 向量 v * T . 而 gamebryo 由于列向量 是 T * V. 不能被相同的值所迷惑. 实际上是Gamebryo旋转方向和右手坐标系相反,我日。要自己输入符号。好处换成左手不用修改矩阵了
dx 矩阵存放结构
struct {
float _11, _12, _13, _14;
float _21, _22, _23, _24;
float _31, _32, _33, _34;
float _41, _42, _43, _44;
};
DX里面一些好用的矩阵变换函数也记录下: D3DXMatrixLookAtLH:根据摄像机的三个属性坐标计算视矩阵(左手)
zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)
xaxis.x yaxis.x zaxis.x 0
xaxis.y yaxis.y zaxis.y 0
xaxis.z yaxis.z zaxis.z 0
-dot(xaxis, eye) -dot(yaxis, eye) -dot(zaxis, eye) 1 D3DXMatrixLookAtRH :根据摄像机的三个属性坐标计算
视矩阵(右手)zaxis = normal(Eye - At)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)
xaxis.x yaxis.x zaxis.x 0
xaxis.y yaxis.y zaxis.y 0
xaxis.z yaxis.z zaxis.z 0
-dot(xaxis, eye) -dot(yaxis, eye) -dot(zaxis, eye) 1
D3DXMatrixOrthoLH:根据宽高和远近平面计算(0,0在窗口中心)正交投影矩阵(左手)
2/w 0 0 0
0 2/h 0 0
0 0 1/(zf-zn) 0
0 0 zn/(zn-zf) 1
D3DXMatrixOrthoOffCenterLH:根据宽高和远近平面计算离心(0,0在窗口左上角)正交投影矩阵(左手) r,l,b,t分别为右,左,下,上的坐标
2/(r-l) 0 0 0
0 2/(t-b) 0 0
0 0 1/(zf-zn) 0
(l+r)/(l-r) (t+b)/(b-t) zn/(zn-zf) 1
D3DXMatrixOrthoOffCenterRH:根据宽高和远近平面计算(0,0在窗口中心)正交投影矩阵(右手)
2/(r-l) 0 0 0
0 2/(t-b) 0 0
0 0 1/(zn-zf) 0
(l+r)/(l-r) (t+b)/(b-t) zn/(zn-zf) 1
D3DXMatrixOrthoRH:根据宽高和远近平面计算(0,0在窗口中心)正交投影矩阵(右手)
2/w 0 0 0
0 2/h 0 0
0 0 1/(zn-zf) 0
0 0 zn/(zn-zf) 1
D3DXMatrixPerspectiveFovLH:左手透视投影(参数为纵横张角和远近平面)
xScale 0 0 0
0 yScale 0 0
0 0 zf/(zf-zn) 1
0 0 -zn*zf/(zf-zn) 0
where:
yScale = cot(fovY/2)
xScale = aspect ratio * yScale
D3DXMatrixPerspectiveFovRH:右手透视投影(参数为纵横张角和远近平面)
xScale 0 0 0
0 yScale 0 0
0 0 zf/(zn-zf) -1
0 0 zn*zf/(zn-zf) 0
where:
yScale = cot(fovY/2)
xScale = aspect ratio * yScale
D3DXMatrixPerspectiveLH:实境体投影矩阵
(D3DXMatrixPerspectiveLH(&matProj,D3DX_PI/4,1.0f,1.0f,100.0f);)
2*zn/w 0 0 0
0 2*zn/h 0 0
0 0 zf/(zf-zn) 1
0 0 zn*zf/(zn-zf) 0
D3DXMatrixPerspectiveOffCenterLH:
2*zn/(r-l) 0 0 0
0 2*zn*(t-b) 0 0
(l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1
0 0 zn*zf/(zn-zf) 0D3
DXMatrixPerspectiveOffCenterRH
2*zn/(r-l) 0 0 0
0 2*zn/(t-b) 0 0
(l+r)/(r-l) (t+b)/(t-b) zf/(zn-zf) -1
0 0 zn*zf/(zn-zf) 0
D3DXMatrixPerspectiveRH:
2*zn/w 0 0 0
0 2*zn/h 0 0
0 0 zf/(zn-zf) -1
0 0 zn*zf/(zn-zf) 0
D3DXMatrixReflect:根据平面方程计算反射矩阵 P = normalize(Plane);
-2 * P.a * P.a + 1 -2 * P.b * P.a -2 * P.c * P.a 0
-2 * P.a * P.b -2 * P.b * P.b + 1 -2 * P.c * P.b 0
-2 * P.a * P.c -2 * P.b * P.c -2 * P.c * P.c + 1 0
-2 * P.a * P.d -2 * P.b * P.d -2 * P.c * P.d 1
有这些矩阵的计算方式,在opengl中也使用同样的矩阵就可以了
「真诚赞赏,手留余香」
真诚赞赏,手留余香
使用微信扫描二维码完成支付