視圖矩陣的推導


        把物體從世界坐標系轉化到視點坐標系的矩陣稱為視圖矩陣。

     下面我們先看下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)

image

image

 

 

      假設視點坐標系初始和世界坐標系重合,它先進行一個旋轉變化,然后再進行一個平移,得到現在視點位置和方位。則此時進行的矩陣變化為image,其中T是平移變化,R是旋轉變化,因為OpenGL頂點坐標,使用列向量,所以我們使用逆變換。

image

T的逆矩陣為:

image

對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

則轉化矩陣為:

image

則完整的公式為:image      image

 

則gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);最終視圖矩陣是image

你可以用下面的代碼來驗證它:

#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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM