zoukankan      html  css  js  c++  java
  • 视图矩阵的推导

            把物体从世界坐标系转化到视点坐标系的矩阵称为视图矩阵。

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

  • 相关阅读:
    Nginx 缓存解决方案
    Chrome去水印、自由复制的解决方法
    简单介绍正向代理和反向代理
    Lambda表达式
    项目集成hystrix-dashboard
    hystrix 添加turbine
    GsonUtil 工具类
    idea 去除import * 变成具体引入文件
    eureka 创建服务消费者
    eureka 创建注册服务提供方
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/2787636.html
Copyright © 2011-2022 走看看