视点与视线
摄像机视角、视线、上方向概念
1.视点,视线,观察点,上方向 视点 指的是摄像机所处位置 视线 指的是摄像机观察的方向 观察点 指的是被观察目标所在的点 上方向 由于在视点与视线确定的情况下,摄像机还是可以沿着视线旋转的,所以还缺少一种信息描述摄像机的状态,那就是像上的方向(上方向)
2.视图矩阵 我们可以用视点、观察点、上方向者三个矢量创建一个 视图矩阵 ,这个视图矩阵会影响显示在屏幕上的视图,也就是会影响观察者观察到的场景,接下来我们看一下gl-matrix.js 库源码分析提供的 lookAt(out, eye, center, up)函数
out 是一个4*x4单位矩阵
视点:观察者所处的位置称为视点。从视点出发沿着观察方向的射线称作视线。坐标用(eyee=[yeX,eyeY,eyeZ])表示。
观察目标点:被观察目标所在的点,它可以用来确定视线。坐标用center=[atX,atY,atZ]表示。
上方向:最终绘制在屏幕上的影像中的向上的方向。坐标用up=[upX,upY,upZ]表示。
推导:
opengl 本身是没有相机的,但是我们可以通过把场景中的所有物体往相反方向移动的方式来模拟相机。产生一种移动的感觉。这个感觉其实是一种错觉。
以相机位置为原点的,创建一个3个垂直单位轴的坐标系
二 相机坐标系 定义: 以视点为原点,以视线为z轴负方向,x轴与y轴与图像的x,y轴平行。
推导
由前文得知,视图变换构建了一个视空间/摄像机空间坐标系,为了对应于世界坐标系的XYZ,可以将其命名为UVN坐标系,它由之前提到的三个条件量构建而成:
选取视线的方向为N轴:N = eye--at;并归一化N。 选取up和N的叉积为U轴: U= up×N,并归一化U。 选取N和U叉积得到V轴:V = N×U,并归一化V。
如图所示[7]:
gl-matrix.js 库源码分析
ini
/**
* Generates a look-at matrix with the given eye position, focal point, and up axis.
* If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {ReadonlyVec3} eye Position of the viewer
* @param {ReadonlyVec3} center Point the viewer is looking at
* @param {ReadonlyVec3} up vec3 pointing up
* @returns {mat4} out
*/
function lookAt(out, eye, center, up) {
var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
/*
eye=[xx,xx,xx]
up=[xx,xx,xx]
center=[xx,xx,xx]
*/
var eyex = eye[0];
var eyey = eye[1];
var eyez = eye[2];
var upx = up[0];
var upy = up[1];
var upz = up[2];
// AT
var centerx = center[0];
var centery = center[1];
var centerz = center[2];
if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
return identity$3(out);
}
// N = eye--at 并归一化N。
z0 = eyex - centerx;
z1 = eyey - centery;
z2 = eyez - centerz;
len = 1 / Math.hypot(z0, z1, z2);
z0 *= len;
z1 *= len;
z2 *= len;
/*
u = up x n up 叉乘 n 并归一化U。
eye=[xx,xx,xx]
up=[xx,xx,xx]
center=[xx,xx,xx]
// 向量现相减
n=[
eyex - centerx,
eyey - centery,
eyez - centerz
]=Z(x,y,z)
up=[xx,xx,xx]
Z=[xx,xx,xx]
*/
/*
up(y,z) 与 Z(y,z) 叉乘
x0 = |upy , upz|
|z1 , z2 |
*/
x0 = upy * z2 - upz * z1;
/*
up(z,x) 与 Z(z,x) 叉乘
x1 = |upz, upx|
|z2 , z0|
*/
x1 = upz * z0 - upx * z2;
/*
up(x,y) 与 Z(x,y) 叉乘
x2 = |upx, upy|
|z0 , z1|
*/
x2 = upx * z1 - upy * z0;
len = Math.hypot(x0, x1, x2);
if (!len) {
x0 = 0;
x1 = 0;
x2 = 0;
} else {
len = 1 / len;
x0 *= len;
x1 *= len;
x2 *= len;
}
// V = N×U,并归一化V
/*
y0 = |z1 , z2|
|x1 , x2|
*/
y0 = z1 * x2 - z2 * x1;
/*
y1 = |z2 , z0|
|x2 , x0|
*/
y1 = z2 * x0 - z0 * x2;
/*
y1 = |z0 , z1|
|x0 , x1|
*/
y2 = z0 * x1 - z1 * x0;
len = Math.hypot(y0, y1, y2);
if (!len) {
y0 = 0;
y1 = 0;
y2 = 0;
} else {
len = 1 / len;
y0 *= len;
y1 *= len;
y2 *= len;
}
/*
eye 就是等于移动矩阵
-eyey = [xx,xx,xx]
*/
let mat4_UVN = [
// u v n
x0, y0, z0, 0,
x1, y1, z1, 0,
x2, y2, z2, 0,
-(x0 * eyex + x1 * eyey + x2 * eyez),-(y0 * eyex + y1 * eyey + y2 * eyez),-(z0 * eyex + z1 * eyey + z2 * eyez),1
];
out[0] = x0;
out[1] = y0;
out[2] = z0;
out[3] = 0;
out[4] = x1;
out[5] = y1;
out[6] = z1;
out[7] = 0;
out[8] = x2;
out[9] = y2;
out[10] = z2;
out[11] = 0;
out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
out[15] = 1;
return out;
}
1 首先我们要求出 向量 N,
ini
// N = eye--at 并归一化N。
z0 = eyex - centerx;
z1 = eyey - centery;
z2 = eyez - centerz;
U = up x n up 叉乘 n 并归一化U。
ini
/*
u = up x n up 叉乘 n 并归一化U。
eye=[xx,xx,xx]
up=[xx,xx,xx]
center=[xx,xx,xx]
// 向量现相减
n=[
eyex - centerx,
eyey - centery,
eyez - centerz
]=Z(x,y,z)
up=[xx,xx,xx]
Z=[xx,xx,xx]
*/
/*
up(y,z) 与 Z(y,z) 叉乘
x0 = |upy , upz|
|z1 , z2 |
*/
x0 = upy * z2 - upz * z1;
/*
up(z,x) 与 Z(z,x) 叉乘
x1 = |upz, upx|
|z2 , z0|
*/
x1 = upz * z0 - upx * z2;
/*
up(x,y) 与 Z(x,y) 叉乘
x2 = |upx, upy|
|z0 , z1|
*/
x2 = upx * z1 - upy * z0;
V = N×U,并归一化V
ini
// V = N×U,并归一化V
/*
y0 = |z1 , z2|
|x1 , x2|
*/
y0 = z1 * x2 - z2 * x1;
/*
y1 = |z2 , z0|
|x2 , x0|
*/
y1 = z2 * x0 - z0 * x2;
/*
y1 = |z0 , z1|
|x0 , x1|
*/
y2 = z0 * x1 - z1 * x0;
得到UVN矩阵
ini
let mat4_UVN = [
// u v n
x0, y0, z0, 0,
x1, y1, z1, 0,
x2, y2, z2, 0,
0, 0 , 0, 1
];
然后再让平移矩阵T-1乘以UVN矩阵
eye 就是等于移动矩阵
因为我们眼睛和物体方向是刚好相反的所以得到一个逆矩阵
然后让移动矩阵乘以u v n矩阵,所以最终的得到一个相机的矩阵