zoukankan      html  css  js  c++  java
  • 【转载】3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解

    原文:3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解

    3D中z值会影响屏幕坐标系到世界坐标系之间的转换,2D中Z值不会产生影响(而只是屏幕宽高比会产生影响,z值只对深度剔除产生影响)。所以U3D中如果用2D摄像机那么屏幕坐标和世界坐标之间的转换需要用指定的2D摄像机才行,如果用主3D摄像机那么UI转换会产生计算结果异常。

    一、D3DXMatrixPerspectiveFovLH函数

    作用:Builds a left-handed perspective projection matrix based on a field of view.获得指定参数的透视投影矩阵,用于3D投影变换。

    使用:

    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
                &proj,
                D3DX_PI * 0.5f, // 90 - degree
                (float)Width / (float)Height,
                1.0f,
                1000.0f);
    Device->SetTransform(D3DTS_PROJECTION, &proj); // 设置变换矩阵和状态,没有真正开始变换,提交后交给图形硬件

    1.镜头平移:改变cameraPos用来计算观察位置

    2.镜头拉近拉远缩放物体对象:

    1).设置观察点的位置,cameraPos用来计算观察位置(没有忽略z值故可以)。

    2) fovy z轴和zy上斜线之间夹角变小,那么物体也会变大(aspect不能随便变换否则就不等比例了)。

    3.镜头拉高拉低:

    1)cameraPos来拉高,y变就可以了。

    原型:

    D3DXMATRIX* D3DXMatrixPerspectiveFovLH(

      _Inout_  D3DXMATRIX *pOut,

      _In_     FLOAT  fovy, 

      _In_     FLOAT  aspect, 

      _In_     FLOAT  zn,  

      _In_     FLOAT  zf

    );

     

    pOut:透视变换矩阵,将视锥内的物体变换到(-1,-1,-1)->(1,1,1)的正方体内。

    fovy:视锥体的上下夹角(6面体),z轴平分该夹角。

     当fovy变小时候,因为也要在屏幕90度中用,所以高度方向被放大了,反之fovy变大,高度方向变小。

    aspect:aspect = w / h,fovy = 90度,由投影矩阵的计算过程,投影yScale = cot(fovy/2); xScale = yScale /aspect.

    当屏幕w:h = 100:20时,当aspect = 5:1,那么视锥内的[5,1]正方形截面世界将被变换映射到(1,1)的平面内,

    xScale压缩了1/5,当透视投影映射到屏幕坐标时候[5,1],xScale方向需要根据屏幕放大5倍,这样视锥体里面的世界等比缩放到屏幕。

    当aspect = 1变小;那么yScale = 1, xScale = 1,视锥体内的xy正方形截面[1,1]世界被放置到(1,1); 映射到屏幕为[5,1]xScale映射到屏幕被放大了5倍,yScale不变。

    当aspect = 10变大,那么yScale = 1,xScale = 1/10,视锥体内的xy正方形截面[10,1]世界->(1,1)->[5,1],xScale被缩小了2倍,yScale不变。

    zn,zf:z近裁剪面,z远裁剪面,z视锥体depth深度的改变,映射到屏幕上,也是zn深度变大了,那么屏幕上物体变小了,zn深度变小了,那么屏幕上物体将变大。

    变换矩阵:

     

    xScale     0          0               0
    0        yScale       0               0
    0          0       zf/(zf-zn)         1
    0          0       -zn*zf/(zf-zn)     0
    where:
    yScale = cot(fovY/2)
    
    xScale = yScale / aspect ratio

    yScale是根据视锥夹角求得的,xScale由屏幕大小来设置等于xScale = yScale / aspect = yScale * h / w,也就是希望: xScale /yScale = h / w.即当yScale = 1时,屏幕w/h = 4/3。那么xScale的缩放比例为 3 / 4,就是是cot(fovX / 2)更小,fovX越大投影的点越多;当xScale更小,除以w = z后,那么[-1,1]的设备坐标系x范围内可以放入更多的点,当转换到屏幕坐标系时,x方向的点放大为y方向放大的4/3, 所以x方向和y方向的缩放比例为1:1,也就是等比的缩放不会导致问题,主要的缩放来自于fovY视锥夹角,和摄像机位置。

    也就是说xScale = yScale / aspect ratio是英明的公式,保证了等比缩放,而和真正的缩放分离了。

    z轴方向的zf/(zf-zn)是对1/z插值的常数部分, -zn*zf/(zf-zn)是对1/z插值的系数部分。

    m31 = 1是最隐秘的雕虫小技。

     

    二、D3DXMatrixOrthoLH函数

    作用:生成一个左手坐标系正交投影矩阵,用于视图坐标到投影坐标系的2D转换。
    使用:
    D3DXMatrix mOrtho
    D3DXMatrixOrthoLH(&mOrtho, WINDOW_WIDTH, WINDOW_HEIGHT, 0.1f, 1000.0f);

    g_pd3dDevice->SetTransform(D3DTS_PROJECTION,&mOrtho); // 设置变换矩阵和状态,没有真正开始变换,提交后交给图形硬件实现变换

     

    1.镜头平移:改变cameraPos用来计算观察位置

    2.镜头拉近放大物体对象:

    1).Z深度值被丢弃了,可以通过放大屏幕投影来变大,那么需要放大正交投影的值,因为正交投影后2/w、2/h,所以可以通过缩小正交投影传入的w、h来实现放大;放大传入的w、h可以实现模拟的远离。

     

     

    3.镜头拉高拉低:

    1)cameraPos,y值变大来拉高;通过放大传入的w、h可以实现模拟的远离缩小。

     



    原型:

    D3DXMATRIX* D3DXMatrixOrthoLH(
      _Inout_  D3DXMATRIX *pOut, // 输出的变幻矩阵
      _In_     FLOAT w, // 屏幕的宽度
      _In_     FLOAT h, // 屏幕的高度
      _In_     FLOAT zn, // z深度缓存最小值
      _In_     FLOAT zf // z深度缓存最大值
    );

    得到的变换矩阵为:
    2/w  0    0           0
    0    2/h  0           0
    0    0    1/(zf-zn)   0
    0    0    zn/(zn-zf)  1

    2D正交变换将摄像机坐标空间里面的点变换到设备规范化坐标空间中

    2/w,2/h对摄像机空间内的x,y进行正交投影,进行了一定的缩放,当w,h越大那么缩小越大,设备规范化坐标系内[-1,1]容纳的像素就越多,变换到屏幕坐标系中就感觉远离缩小了。z轴空间上是对z进行了线性插值,使得z值在[0,1]空间内,zn时候为0,zf时候为1(深度缓存用于遮挡剔除深度测试,和stencil测试)。

    参考:

    http://msdn.microsoft.com/en-us/library/windows/desktop/bb205350%28v=vs.85%29.aspx

    http://msdn.microsoft.com/en-us/library/windows/desktop/bb204940%28v=vs.85%29.aspx

  • 相关阅读:
    Atitit。D&D drag&drop拖拽功能c#.net java swing的对比与实现总结
    Atitit . 编程模型的变革总结
    Atitit.mysql oracle with as模式临时表模式 CTE 语句的使用,减少子查询的结构性 mssql sql server..
    Atitit.编程语言的主要的种类and趋势 逻辑式语言..函数式语言...命令式语言
    atitit.编程语言会形成进化树--哪些特性会繁荣??通才还是专才的选型 现代编程语言的特性总结
    Atitit.多媒体区----web视频格式的选择总结
    Atitit.web 视频播放器classid clsid 大总结quicktime,vlc 1. Classid的用处。用来指定播放器 1 2. <object> 标签用于包含对象,比如图像、音
    Atitit.部分错误 设计模式,异常处理框架atiPartErr 的总结
    Atitit.js javascript异常处理机制与java异常的转换 多重catc hDWR 环境 .js exception process Vob7
    atitit.判断时间重叠方法总结 java c++ c#.net js php
  • 原文地址:https://www.cnblogs.com/zhehan54/p/5525436.html
Copyright © 2011-2022 走看看