关于ViewMatrix计算

标签:
3d视点矩阵viewmatrixopengldirect3dit |
分类: 技术 |
一、列主序(OPENGL)和行主序(Direct3D)
不管是D3D还是OpenGL,使用的矩阵都是线性代数标准的矩阵,只是在存储方式上有所不同。分别为:行主序(Direct3D),列主序(OpenGL)
存储顺序说明了线性代数中的矩阵如何在线性的内存数组中存储。例如:内存中使用一个二维数组m存储矩阵,第i行第j列的表示方法分别为:
行主序:m[i][j]
列主序:m[j][i]
a21,a22,a23,a24
a21,a22,a23,a24
a12,a22,a32,a42
a31,a32,a33,a34
a31,a32,a33,a34
a13,a23,a33,a43
a41,a42,a43,a44
a41,a42,a43,a44
a14,a24,a34,a44
不难发现,M行=M列的转稚
OpenGL与Direct3D几点不同(坐标系,向量,绕序):
向量的行列性导致矩阵与向量乘法方式有所不同:
列向量 ==>
矩阵右乘向量
行向量 ==>
矩阵左乘向量
其中OpenGL可以设置顺时针为多边形正面顶点绕序。
视点矩阵(view matrix)模拟我们的眼睛或者摄像机。 在流水线(pipeline)中,
视点矩阵将作用于所有顶点. 在进行投影转换时设置的视景体,
决定了我们能在屏幕上看见什么.
在D3D中, 视景体是以坐标原点为视点,
直视Z轴正方向. 所以, 如果希望看到3D空间中不同位置, 不同角度的图像.
就需要将视点转换回坐标原点.从本质上讲,
所有这些矩阵变换都将作用于顶点. 所以都是模型的变换.
第一步 : 将视点移回原点.
这个矩阵很好计算:
第二步 :
建立视点坐标系.
在这里,
我们需要根据Q和U计算出三个互相垂直的单位向量, 用来表示当前的视点坐标系. Q相对于Z轴正方向, W相对于Y轴正方向,
S相对于X轴正方向.
第三步: 将XYZ坐标系下的点转换到SWQ坐标系下.
这里需要一些思考, 现在的S(Sx, Sy, Sz),
W(Wx, Wy, Wz), Q(Qx, Qy, Qz)都是在XYZ坐标系下表示的向量. XYZ坐标系下的点,
要转换到SWQ坐标系下, 其实并不难. 假设点K(Kx, Ky, Kz)是XYZ坐标系下的点, L是SWQ坐标系下的点:
Lx = Kx *
Sx + Ky * Sy + Kz * Sz;
Ly = Kx *
Wx + Ky * Wy + Kz * Wz;
Lz = Kx *
Qx + Ky * Qy + Kz * Qz;
第四步 : 将第一步和第二步的矩阵相乘,
我们就可以得出最终的view矩阵:
double
centerx, double centery, double centerz, // view center:(0, 0, 0)
double
upx, double upy, double upz,//up
vector :(0, 1, 0)
float
m[16]) //View Matrix
double x[3], y[3], z[3], mag;
// Difference eye and
center vectors to make Z vector.
z[0] = eyex - centerx;
z[1] = eyey - centery;
z[2] = eyez - centerz;
// Normalize
Z.
mag = sqrt(z[0]*z[0] + z[1]*z[1] +
z[2]*z[2]);
if (mag) {
z[0] /= mag;
z[1] /= mag;
z[2] /= mag;
}
// Up vector makes Y
vector.
y[0] = upx;
y[1] = upy;
y[2] = upz;
// X vector = Y cross
Z.
x[0] = y[1]*z[2] -
y[2]*z[1];
x[1] = -y[0]*z[2] + y[2]*z[0];
x[2] = y[0]*z[1] -
y[1]*z[0];
// Recompute Y = Z
cross X.
y[0] = z[1]*x[2] -
z[2]*x[1];
y[1] = -z[0]*x[2] + z[2]*x[0];
y[2] = z[0]*x[1] -
z[1]*x[0];
// Normalize
X.
mag = sqrt(x[0]*x[0] + x[1]*x[1] +
x[2]*x[2]);
if (mag) {
x[0] /= mag;
x[1] /= mag;
x[2] /= mag;
}
// Normalize
Y.
mag = sqrt(y[0]*y[0] + y[1]*y[1] +
y[2]*y[2]);
if (mag) {
y[0] /= mag;
y[1] /= mag;
y[2] /= mag;
}
// Build resulting
view matrix.
m[0*4+0] = x[0]; m[0*4+1]
= x[1];
m[0*4+2] = x[2]; m[0*4+3]
= -x[0]*eyex + -x[1]*eyey + -x[2]*eyez;
m[1*4+0] = y[0]; m[1*4+1]
= y[1];
m[1*4+2] = y[2]; m[1*4+3]
= -y[0]*eyex + -y[1]*eyey + -y[2]*eyez;
m[2*4+0] = z[0]; m[2*4+1]
= z[1];
m[2*4+2] = z[2]; m[2*4+3]
= -z[0]*eyex + -z[1]*eyey + -z[2]*eyez;
m[3*4+0] = 0.0; m[3*4+1]
= 0.0; m[3*4+2] = 0.0; m[3*4+3]
= 1.0;
在计算ViewMatrix之前先讲明列主序(OPENGL)和行主序(Direct3D),搞清楚这个,理解算法程序会很有帮助。
1.矩阵在内存中的存储
线性代数意义的同一个矩阵,在D3D和GL中的存储顺序:
线代: a11,a12,a13,a14 d3d : a11,a12,a13,a14 gl:
a11,a21,a31,a41
2.行主序的矩阵与列主序的矩阵如何转换呢?
总结:
|
OpenGL |
Direct3D |
坐标系 |
右手坐标系 |
左手坐标系 |
向量 |
列向量 |
行向量 |
矩阵存储方式 |
列主序 |
行主序 |
多边形正面顶点绕序 |
逆时针 |
顺时针 |
二、视点矩阵计算:
假设视点位于P(Px, Py, Pz)点, 方向为Q(Qx, Qy, Qz), 头顶方向U(Ux, Uy,
Uz)根据这些计算视点矩阵.
由此, 我们可以推出转换矩阵:
在OPENGL中,列主序,视点矩阵为:
实现子程序(OPENGL):
static void buildLookAtMatrix(double eyex, double eyey, double
eyez, //eye position
{
}
申明:
程序选自:NVIDIA
Corporation\Cg\examples\OpenGL\basic\08_vertex_transform
下一节将介绍《从Model Space到Canonical view volume转换矩阵的计算》
后一篇:GLEW扩展库