您的位置:首页 > 理论基础

计算机图形学基础(四) 观察2

2016-06-11 09:16 441 查看

透视投影

上一小节 观察1 写的很多了,这节就省略了很多定义之类的东西。

(1)简单的透视投影



后面和前面平行,这里主要讨论这一种情况,大多数物理成像设备都属于这一种情况,包括人类视觉系统和简单的照相机。更一般的情况是不平行的。

空间中的一点(x,y,z)沿着一条投影线被投影到(Xp,Yp,Zp)。所有的投影线都通过原点。因为投影平面和z轴垂直,所以Zp=d;因为照相机指向z轴负方向,所以投影平面位于z轴负方向一侧(可以看着观察1里的透视投影图加以理解)。



(a)三维视图;(b)俯视图;(c)侧视图

从b图可以看出



联系c图可以推导出



下面讨论简化这个变换(我就直接写结果了)



矩阵M把点



变换成



让q除以w分量(vec4的4个分量分别为xyzw)



就可以作为如下流水线



模–视变换—–投影变换——-透视除法

(2)OpengGL中的透视投影



视见体



前裁剪面和后裁剪面

COP位于照相机标架的原点。



下面的函数用于指定透视投影

mat4 Frustum( const GLfloat left, const GLfloat right,
const GLfloat bottom, const GLfloat top,
const GLfloat zNear, const GLfloat zFar )


该函数参数与Ortho的参数非常相似。

尽管在几乎所有的应用程序中都有far>near>0,但只要near!=far,由这些参数确定的投影变换矩阵就是有效的,不过在投影中心(原点)后面的对象所成的像将是倒立的,如果该对象位于近裁面和远裁面之间的话。



通过视角或者视域来指定视见体。

fovy是裁减体的底面和顶面之间的夹角。

aspect是投影平面的宽高比(w/h)。

用下面函数利用视域指定视见体:

mat4 Perspective( const GLfloat fovy, const GLfloat aspect,
const GLfloat zNear, const GLfloat zFar)


(3)透视投影变换矩阵

对于透视投影,采用和平行投影相似的方法。

透视投影的规范化

这里同样直接写推理过程了。





考虑下面的矩阵



可以看出d=-1,z改变

它把


变换成


x’ = x;

y’ = y;

z’ = αz+β;

w’ = -z;

用w’去除得到

x” = -(x/z);

y” = -(y/z);

z” = -(α+β/z)

w” = 1;

由此,原来视见体的侧面变换为(参考前面的简单透视):



如果令



那么z=-near映射成z”=-1。

z=-far映射成z”=1。

矩阵N称为透视规范化变换矩阵



效果如上图。

z” = -(α+β/z)可知:它保持了深度的大小关系。

如果z1>z2那么z”1>z”2。

补充:在规范化视见体中仍然可以进行隐藏面消除,不过由于深度缓存的深度分辨率有限,透视规范化变换的非线性可能导致数值精度问题。虽然原来位于z=-1的投影平面被N变换成了平面z”=β-α,但这不会有什么不良后果,因为在N之后还要进行一个正投影。

OpenGL中的透视投影变换

Frustum函数没有限制视见体一定是对称的棱台。



这里首先要把上图所示的棱台视见体变换为上上图那样的视见体(对称视见体的侧面与投影平面的夹角为45度)。这和把斜平行投影转化为正交投影类似

首先通过错切变换把不对称的棱台转化为对称棱台。

经过错切变换后,点( (left+right)/2, (top+bottom)/2, -near)应位于(0, 0, -near)。



错切后的棱台视见体由下面这几个平面围成



接下来通过缩放把这个棱台的侧面变为



但不改变前裁剪面和后裁剪面。

所需缩放矩阵为

S[-2*near/(right-left), -2*near/(top-bottom), 1]。

为了使裁剪面位于z=-1和z=1,应用上面说过的N。

最后得到的投影变换矩阵如下



由此看下面Frustum的代码

mat4 Frustum( const GLfloat left, const GLfloat right,
const GLfloat bottom, const GLfloat top,
const GLfloat zNear, const GLfloat zFar )
{
mat4 c;
c[0][0] = 2.0*zNear/(right - left);
c[0][2] = (right + left)/(right - left);
c[1][1] = 2.0*zNear/(top - bottom);
c[1][2] = (top + bottom)/(top - bottom);
c[2][2] = -(zFar + zNear)/(zFar - zNear);
c[2][3] = -2.0*zFar*zNear/(zFar - zNear);
c[3][2] = -1.0;
c[3][3] = 0.0;
return c;
}


为了得到另外一个透视观察函数Persective(fovy, aspect, near, far)的投影变换矩阵,我们首先利用矩阵P中的对称性得到

left = -right;

bottom = -top;

再利用简单三角学可以得到

top = near*tan(fovy);

right = top*aspect;

这样可以把矩阵p简化为:



下面是Perspective代码:

mat4 Perspective( const GLfloat fovy, const GLfloat aspect,
const GLfloat zNear, const GLfloat zFar)
{
GLfloat top = tan(fovy*DegreesToRadians/2) * zNear;
GLfloat right = top * aspect;

mat4 c;
c[0][0] = zNear/right;
c[1][1] = zNear/top;
c[2][2] = -(zFar + zNear)/(zFar - zNear);
c[2][3] = -2.0*zFar*zNear/(zFar - zNear);
c[3][2] = -1.0;
c[3][3] = 0.0;
return c;
}


后面还有:

隐藏面消除

显示网格

多边形偏移

在场景中漫游

投影和阴影

这些都以后有空了就写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  计算机 图形