把物體從世界坐標系轉化到視點坐標系的矩陣稱為視圖矩陣。
下面我們先看下OpenGL中視圖矩陣的推導過程:
假設視點或camera的局部坐標系為UVN,UVN分別指向右方、上方和后方從而構成右手坐標系,視點則處於局部坐標系的原點位置。
就如OpenGL中的函數gluLookAt(eyex, eyey, eyez, lookatx, lookaty, lookatz, upx, upy, upz)一樣,給定視點、觀察點、以及up向量之后,我們就可以求得視圖矩陣。
1、首先我們來求得N = eye – lookat,並把N歸一化。
2、up和N差積得到U, U= up X N,歸一化U。
3、然后N和U差積得到V
假定設定攝像機參數如下:gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
則N=Normalize((0.0,3.0,4.0)-(0.0,0.0,0.0))=Normalize((0.0,3.0,4.0))= (0.0,0.6,0.8)
U=up X N= (1.0*0.8-0.6*0.0,0.0*0.0-0.0*0.8, 0.0*0.6-0.0*1.0)=(0.8,0.0,0.0), 歸一化后為U=(1.0,0.0,0.0)
V=N X U=(0.0,0.8,-0.6),歸一化后為(0.0,0.8,-0.6)
假設視點坐標系初始和世界坐標系重合,它先進行一個旋轉變化,然后再進行一個平移,得到現在視點位置和方位。則此時進行的矩陣變化為,其中T是平移變化,R是旋轉變化,因為OpenGL頂點坐標,使用列向量,所以我們使用逆變換。
T的逆矩陣為:
對gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); (Tx,Ty,Tz)=(0.0,3.0,4.0)
當相機變換進行完Inverse Translation這一步之后,相機的原點和世界原點就重合了,也就是處理完了關於平移的變換。
我們要把一個世界坐標系點K(Kx, Ky, Kz),表示成(U,V,P)坐標系的點(假設此時,已經經過平移操作,攝像機在世界坐標系的原點),則其公式為:
因為(Lx, Ly, Lz)=(Kx,Ky,Kz)*(U,V,P),【因為世界坐標系的三個基乘以(U,V,P),就會把世界坐標系轉變到uvp坐標系,所以世界坐標的頂點坐標,乘以這個矩陣,也會轉化到uvp坐標系中的頂點坐標】則有
Lx = Kx * Ux + Ky * Uy + Kz * Uz;
Ly = Kx * Vx + Ky * Vy + Kz * Vz;
Lz = Kx * Px + Ky * Py + Kz * Pz
則轉化矩陣為:
則gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);最終視圖矩陣是
你可以用下面的代碼來驗證它:
#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdlib.h>
#include <cmath>
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0); //背景黑色
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0); //畫筆白色
glLoadIdentity(); //加載單位矩陣
gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glutWireCube(1.0f);
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
GLdouble mv[16] = { 0 }, pv[16] = { 0 };
glGetDoublev( GL_MODELVIEW_MATRIX, mv );
printf("view1:%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f\n", mv[0], mv[1], mv[2], mv[3], mv[4], mv[5], mv[6], mv[7], mv[8], mv[9], mv[10], mv[11], mv[12], mv[13], mv[14], mv[15]);
glGetDoublev(GL_PROJECTION_MATRIX, pv);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
以上是OpenGL的視圖矩陣,對於D3D,由於使用行向量,左乘,以及左手坐標系,所以視圖稍有不同,在D3D11教程中,曾加做過推導:
http://www.cnblogs.com/mikewolf2002/archive/2012/03/11/2390669.html