zoukankan      html  css  js  c++  java
  • View Transform(视图变换)详解

    http://www.cnblogs.com/graphics/archive/2012/07/12/2476413.html

    什么是View Transform

    我们可以用照相机的原理来阐释3D图形的绘制过程,想象一下,我们在摄影的时候都需要做哪些工作,大致可分为如下几个步骤

    1. 摆放好待拍摄的物品,或者人物。
    2. 调整好拍摄角度。
    3. 调整焦距。
    4. 拍摄。

    好了,来分析一下,上面的第一步就相当于世界变换了,将一个模型置于一个公认的坐标系中,这里所谓的公认,也就是大家都遵守的,目的是保证待拍摄的物体和照相机在同一个坐标系。第二步相当于视图变换,这个过程是调整Camera到合适的位置以便拍摄,在3D程序中,也就是设置View Matrix了。第三步调整焦距,这就相当于3D编程中的投影变换。

    View Transform的过程就是在世界坐标系中摆放Camera的过程,并将顶点由世界坐标系转换到Camera Space,在Camera Space中,观察者(Camera)位于坐标原点,观察方向指向Z轴正方向。

    为什么要进行View Transform?

    在world space中,camera并不一定位于坐标原点,并且观察方向不一定指向Z轴正方向,对于投影变换及其他的一些操作来说,如果不满足这两个条件,后续的的操作就会变得非常低效,所以为了提高效率,我们需要进行view transform。

    View Transform的作用

    View Transform主要有下面两个作用。

    • 移动camera,使其位于world space的坐标原点
    • 旋转camera,使其朝向z轴正方向,也就是视线由原点指向z轴正方向。

    这两个过程,前一个实际上是平移,后一个实际上是旋转。你可以想象成Camera也有三个坐标轴x,y,z,视图变换的过程就是将Camera的坐标轴与世界坐标系的坐标轴对齐的过程。

    注意:view transform中,所有位于world space中的models都随着camera一起变换,所以视野并未发生变化,具体过程见下图

    如何求解View Matrix?

    使用D3D函数

    使用下面的D3D函数可以计算view matrix,第一个参数是输出参数,返回求得的视图矩阵,第二个参数是眼睛的位置,第三个参数是观察点中心,最后一个参数是向上向量。该函数的最后两个字母表示左手系(Left Hand)。

    D3DXMatrixLookAtLH(&M, &eyePt, &lookCenter, &upVec) ;

    手动求解

    手动求解View matrix并不是难事,一个camera一般有如下四个属性,

    • 向前向量(direction),相当于Z轴
    • 向上向量(up vector),相当于Y轴
    • 向右向量(right vector),相当于X轴
    • 位置(position)

    其中前三个向量要求是相互垂直的。假设我们分别用d, u, v和p来表示这四个变量。并假设待求的视图矩阵为V,根据前面的介绍我们知道,V的作用就是将摄像机移动到原点,并将摄像机的三个向量分别与坐标轴对齐,d与z轴正方向对齐,u与y轴正方向对齐,r与x轴正方向对齐。假设将摄像机与坐标轴对齐的矩阵为V,那么V的推导过程如下。

    通常在实际的编程中,只会给出如下三个量。至于d和r这两个量,只能通过计算求得。

    • 摄像机(眼睛)的位置(eye point),相当于p
    • 观察点中心(look at),假设为向量c
    • 向上向量(up vector),相当于u

    可以通过下面方法求得d, r和u。

    • d = c - p,下面第一幅图
    • r = d x u,下面第二幅图
    • u = r x d,下面第三幅图

    注意上面的x是叉积运算(cross product),现在p,d,r,u四个量都已经知道,于是就可以根据上面的矩阵M求得视图变换矩阵了,对应的代码如下。该函数有三个参数,分别是摄像机位置p,向上向量u和视点中心lookAt。

    复制代码
    D3DXMATRIX buildViewMatrix(D3DXVECTOR3& p, D3DXVECTOR3& u, D3DXVECTOR3& lookAt)
    {
        // Calculate d
        D3DXVECTOR3 d = lookAt - p;
        D3DXVec3Normalize(&d, &d);
    
        // Calculate r
        D3DXVECTOR3 r;
        D3DXVec3Cross(&r, &u, &d);
        D3DXVec3Normalize(&r, &r);
    
        // Calculate up
        D3DXVec3Cross(&u, &r, &d);
        D3DXVec3Normalize(&u, &u);
    
        // Fill in the view matrix entries.
        float x = -D3DXVec3Dot(&p, &r);
        float y = -D3DXVec3Dot(&p, &u);
        float z = -D3DXVec3Dot(&p, &d);
    
        D3DXMATRIX M;
        M(0,0) = r.x; 
        M(1,0) = r.y; 
        M(2,0) = r.z; 
        M(3,0) = x;   
    
        M(0,1) = u.x;
        M(1,1) = u.y;
        M(2,1) = u.z;
        M(3,1) = y;  
    
        M(0,2) = d.x; 
        M(1,2) = d.y; 
        M(2,2) = d.z; 
        M(3,2) = z;   
    
        M(0,3) = 0.0f;
        M(1,3) = 0.0f;
        M(2,3) = 0.0f;
        M(3,3) = 1.0f;
    
        return M;
    }
    复制代码

    注意事项,在求取View Matrix的时候有几点是需要注意的:

    • 叉积满足右手法则。
    • 叉积不满足交换律。 a x b = - b x a
    • DirectX使用左手系,满足左手法则。

    只要最终求得的三个向量,up, right和d满足左手法则即可。如果应用了View Matrix之后发现模型左右或者上下颠倒了,那么就说明求取的时候没有满足左手系。

    好了,矩阵求解完毕,赶快使用SetTransform(D3DTS_VIEW, &M) ;来试试吧,效果和使用函数D3DXMatrixLookAtLH是一样的!

    Happy Coding!!!

    我们看DX9帮助文档中,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

    唯一的不同就是D3DXMatrixLookAtLH的函数参数只有四个,即摄像机位置Eye、摄像机朝向At、摄像机上向量Up,通过简单的运算就可以转换成我们上面所说的那四个描述量了,在这里就不赘言了。

  • 相关阅读:
    mapreduce 函数入门 二
    mapreduce 函数入门 一
    Flume+Kafka+Storm+Redis 大数据在线实时分析
    mapReduce 大数据离线分析
    docker 简介
    flume安装使用+根据数据源分类
    hiho 171周
    如何新建一个空的optix工程
    读 Real-Time Rendering 收获
    hiho 1590
  • 原文地址:https://www.cnblogs.com/kex1n/p/3527470.html
Copyright © 2011-2022 走看看