当前位置: 首页 > news >正文

CG笔记之一——透视投影

以前以为投影也就投影了,并不了解投影也可视作坐标变换,而且也是一个齐次坐标(Homogeneous Coordinate)系的坐标变换。因此书中的介绍一开始也不明白——它说透视投影会把直线映射成曲线,还特地验证一下,发现投影为2D空间(摄像机平面)并不会发生这种情况,在仔细一看才知道,它指的是映射到3D空间,在z方向发生了畸变。而后逐渐了解,原来z方向的位置信息(depth)在渲染级模块处(所谓的Z-Buffer)有特殊用处(直线上每个点的depth均通过直线两端的点线性插值完成,因此可能造成depth位序异常)。当然这个问题在某些场合是不会发生的,例如完全基于光线跟踪算法的渲染并不是这样形成depth的。

于是,投影事实上成了投影变换。投影变换需要满足两个基本要求[1]
  1.保持depth的位序;
  2.将直线变换为直线。
  在x和y方向仍根据投影方法定义(投射在摄像机平面上的坐标),而在z方向上,需要引入伪距离映射(pseudo-distance),数学上,透视投影的伪距离映射具有形式z' = A + B / z。假设z方向截断分别为n和f = 1 / rf,截断分别映射为pnpf。于是列写方程式1
  pn = A + B / n   (式1)
  pf = A + B * rf (式2)
  解得:
  A = (n * rf - pf) / (n * rf - 1) (式3)
  B = n * (pf - pn) / (n * rf - 1) (式4)
  可以证明,相应的齐次坐标变换矩阵为:
  [ d, 0, 0, 0;
    0, d, 0, 0;
    0, 0, A, B;
    0, 0, 1, 0]   
(式5)
  一个很赏心悦目的方案是将n=d(目屏距)映射为0,而将rf=0(无穷远处)映射为1,这种情况下:A=1, B=-d。然而事实上,为了能够提供较好的depth分辨效果,n和f的选择(尤其是f)非常重要,f必须能容纳所有需要关心的物体,需要足够大,但是过大的话会导致depth分辨率的相对降低;而pn和pf则主要取决于为depth分配的位数,通常,现代显卡为depth配置了32位定点数。而透视投影的伪距离映射的一个较好的性质是,它对较近的物体提供了较大的分辨率,较远的物体则即使由于分辨率低而发生错误也是可以接受的。
  然而在OpenGL中,用一个锥形顶点在圆点,截平面与z = 0平面平行的平截头体(frustum)向任意矩形映射的方式定义透视投影。它是一种更一般的透视投影形式。
  列写关系式:
  px = kx * x / z + dx    (式6)
  py = ky * y / z + dy    (式7)
  pz = kz / z + dz   (式8)
  可以导出齐次线性变换矩阵为:
  P = [ kx,  0, dx, 0;
         0, ky, dy, 0;
         0,  0, dz, kz;
         0,  0,  1, 0]
    (式9)
  注意到:
    M = [ 1, 0, 0, dx;
          0, 1, 0, dy;
          0, 0, 1, dz;
          0, 0, 0, 1]

    A = [ kx, 0,  0, 0;
           0, ky, 0, 0;
           0, 0,  0, kz;
           0, 0,  1, 0]
 
 有P = M * A    (式10)
  即P变换矩阵由投影(A矩阵)和屏幕平移(M矩阵)两部分变换组成。
  
根据映射关系:
  (x0, ?, z0) -> (px0, ?, pz0), (x1, ?, z0) -> (px1, ?, pz0)    (式11)
  (?, y0, z0) -> (?, py0, pz0), (?, y1, z0) -> (?, py1, pz0)    (式12)
  (?, ?, z0) -> (?, ?, pz0), (?, ?, z1) -> (?, ?, pz1)    (式13)
  可以解得:
  kx = z0 * (px1 - px0) / (x1 - x0), dx = (x1 * px0 - x0 * px1) / (x1 - x0)    (式14)
  ky = z0 * (py1 - py0) / (y1 - y0), dy = (y1 * py0 - y0 * py1) / (y1 - y0)    (式15)
  kz = z0 * (pz0 - pz1) / (1 - z0 / z1 ), dz = (pz1 - pz0 * z0 / z1) / (1 - z0 / z1)    (式16)
  注意到,kz是小于0的,这使得式8给出的伪距离映射是合法的。

注释
1 本笔记采用传统的z轴,即从眼睛指向屏幕,x从左至右,y从上至下(符合光栅扫描顺序),因此它仍是右手系的。

参考文献
[1] 3-D Computer Graphics, A Mathematical Introduction with OpenGL, Samuel R. Buss

转载于:https://www.cnblogs.com/quanben/archive/2007/04/08/3129011.html


http://www.taodudu.cc/news/show-647367.html

相关文章:

  • 【physx/wasm】在physx中添加自定义接口并重新编译wasm
  • excel---常用操作
  • Lora训练Windows[笔记]
  • linux基础指令讲解(ls、pwd、cd、touch、mkdir)
  • InnoDB 事务处理机制
  • 启明云端ESP32 C3 模组WT32C3通过 MQTT 连接 AWS
  • SQLite B+树实现代码
  • Some thoughts on my own O/R Mapping or Code Generation tools
  • [翻译] 构建完美的WPF开发工作站
  • J2EE Architecture(4)
  • JSF优点(转载自中国IT实验室)
  • 如何自学JSP。--摘抄http://hi.baidu.com/comasp
  • max与top的效率
  • 精确计算代码执行时间
  • 理解 ActivityExecutionContextManager
  • Linq 演变的过程(delegate = Lamb = Linq)
  • 光阴四载,梦想在望
  • CSS常用文本属性
  • VSS2005 添加文件夹方法!
  • 一个不错的SQL储存过程分页,储存过程+Repeater,如果只是浏览数据的话,快就一个字...
  • DotNetNuke与MemberShip的结合(五年版) 三步汇总
  • 快速恢复Word、Excel的默认初始设置
  • AnkhSVN 1.0.2778 简体中文版发布
  • [转]获取xml节点值和属性值(兼容ie和firefox)
  • 请问如何把.net framework框架集成在安装程序里头?
  • 修改资料时碰到的问题,
  • 过滤脚本(C#,script,iframe,html)
  • 聊聊我对黑客技术的思考
  • 以Post方式发送数据采用WebClient
  • 今天20号!
  • discuz nt 安装,完全攻略。
  • SQL概述及在网络安全中的应用
  • F41G-UT 安装Windows server 2003系统后无法安装显卡驱动的解决办法
  • 《算法设计与分析基础》Chapt 2 算法效率分析基础
  • [转]C#中得到程序当前工作目录和执行目录的一些方法
  • MySQL 同步(三)不同版本问题