Opengl Camera相关知识点

1、视图矩阵

视图矩阵即用于将要渲染的物体从世界坐标转换到视觉坐标的过程。即视觉坐标 = 视图矩阵 * 世界坐标。
例如指定物体的世界坐标为(0, 0, 0),设置摄像机的位置为(0, 0, 300),即转换后物体的实际坐标即以摄像机的位置(眼睛看到的)为起点(0, 0, 0),物体相对摄像机的位置即为视觉坐标(0, 0, -100)。视觉坐标除了在物体渲染时的坐标变换中用到,还有个就是在光照的时候,光照的计算都是在视觉坐标下进行计算的。

视图矩阵的推导:
视觉矩阵即正常使用的gluLookAt,gluLookAt 调用即会去构造一个视图矩阵,当我们需要渲染物体前,需要去创建一个视图矩阵,否则默认为(0,0,0)的位置。
1. 取得当前摄像机看的目标,正常我们默认设置为

mTarget(0.0, 0.0, -1.0);

即朝向屏幕里面的方向。

2. 眼睛的位置,即我们初始化设置摄像机的位置,如设置为

mEyePos(0, 0, 300);

3. 设置摄像机向上的方向,默认设置为y轴正方向:

Vector3(0.0, 1.0, 0.0)

4. 通过上述三个变量来构造视图矩阵,也就是gluLookAt调用的9个参数。

Vector3 zAxis = (target - eyePos).normalize();

取得摄像机的z轴的朝向,也就是眼睛看的朝向。

Vector3 yAxis = up.normalize();

摄像机向上的朝向。
通过以上两个坐标,可以计算x轴的朝向(即z与y的叉乘):

Vector3 xAxis = (zAxis.cross(yAxis)).normalize();

接下来通过这三个坐标轴来构造一个矩阵,由于眼睛看的z轴方向与物体的方向是相反的,所以z轴需要取反:

Matrix4 mat;
mat[0] = xAxis.x;
mat[1] = xAxis.y;
mat[2] = xAxis.z;

mat[4] = yAxis.x;
mat[5] = yAxis.y;
mat[6] = yAxis.z;

mat[8] = -zAxis.x;
mat[9] = -zAxis.y;
mat[10] = -zAxis.z;

接下来将构造出的矩阵平移摄像机的位置,即可构造出当前的视图矩阵:

mat.translate(-eyePos.x, -eyePos.y, -eyePos.z);

由于视觉坐标的移动与世界坐标是相反的,所以移动为相反的方向。
完整代码如下所示:

Matrix4 Camera::lookAt(Vector3 eyePos, Vector3 target, Vector3 up)
{
	Vector3 zAxis = (target - eyePos).normalize();
	Vector3 yAxis = up.normalize();
	Vector3 xAxis = (zAxis.cross(yAxis)).normalize();

	Matrix4 mat;
	mat[0] = xAxis.x;
	mat[1] = xAxis.y;
	mat[2] = xAxis.z;

	mat[4] = yAxis.x;
	mat[5] = yAxis.y;
	mat[6] = yAxis.z;

	mat[8] = -zAxis.x;
	mat[9] = -zAxis.y;
	mat[10] = -zAxis.z;

	mat.translate(-eyePos.x, -eyePos.y, -eyePos.z);
	return mat;

2、投影矩阵
2.1 透视投影矩阵
投影就是将物体从视觉坐标投影到屏幕上,而透视投影就是使物体看起来能产生近大远小的效果。投影后的坐标即为NDC坐标(标准设备坐标),即x、y、z的坐标皆为[-1, 1]的范围内。透视投影矩阵为:
void Camera::setFrustum(float l, float r, float b, float t, float n, float f)
{
	mMatrixProjection.identity();
	mMatrixProjection[0]  =  2 * n / (r - l);
	mMatrixProjection[2]  =  (r + l) / (r - l);
	mMatrixProjection[5]  =  2 * n / (t - b);
	mMatrixProjection[6]  =  (t + b) / (t - b);
	mMatrixProjection[10] = -(f + n) / (f - n);
	mMatrixProjection[11] = -(2 * f * n) / (f - n);
	mMatrixProjection[14] = -1;
	mMatrixProjection[15] =  0;
}

2.2 正交投影矩阵
即物体不产生变形的效果,每个物体的大小都是等比例的,即正交投影是直接从视觉坐标中根据在-1, 1的范围内直接转换而来,而透视投影则是先将物体坐标先透视到近裁剪平面,接着再将其变换到-1和1的范围。正交投影矩阵为:

void Camera::setOrtho(float l, float r, float b, float t, float n, float f)
{
	mMatrixProjection.identity();
	mMatrixProjection[0]  =  2/(r-l);
	mMatrixProjection[3]  =  -(r+l)/(r-l);
	mMatrixProjection[5]  =  2/(t-b);
	mMatrixProjection[7]  =  -(t+b)/(t-b);
	mMatrixProjection[10] = -2 / (f - n);
	mMatrixProjection[11] = -(f + n) / (f - n);
}

具体矩阵推导可参考:http://www.songho.ca/opengl/gl_projectionmatrix.html

3、坐标原点
在使用opengl开发过程中,经常会遇到坐标原点问题,最常出现的是屏幕中心为原点和屏幕左下角为原点,为什么会有这些坐标原点呢?其实是在设置矩阵变换时指定的。
正常设置透视投影矩阵时,如果通过
setOrtho(float l, float r, float b, float t, float n, float f)

设置时,传入的参数为:

camera->setOrtho(0, w, 0, h, 0.1, 100);

此时则原点在屏幕左下角,具体原因即为矩阵的计算时是根据输入的前后左右来进行计算的。而如果当前输入的参数为:

camera->setOrtho(-w/2, w/2, -h/2, h/2, 0.1, 100);

则此时坐标原点则是在屏幕中心。同时,通过上述设置后,绘制时坐标也为具体的坐标,即在屏幕范围内的坐标[-w/2, w/2]。

4、坐标计算
当我们在绘制时,有时需要取得我当前位置的最大范围的宽高,即不会在视窗之外。例如:摄像机位置为(0, 0, 300),物体位置为(0, 0, -100),那么当前物体所在的最大范围是多少呢?其实这问题也就是求当前z轴在-100的视景体的范围是多大。需要计算当前平面的宽高,我们需要知道当前摄像机的视角范围,例如摄像机视角范围为60,则z=-100处的高为h=tan(60/2) * (300-(-100)) = 230.9,即上方最大范围为230.9,下方为-230.9,w则直接通过窗口的h/w即可取得。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值