计算机图形-WEBGL视点与视线-lookAt函数源码分析

视点与视线

摄像机视角、视线、上方向概念

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矩阵,所以最终的得到一个相机的矩阵

相关推荐
皮皮陶2 小时前
Unity WebGL交互通信
unity·交互·webgl
刘好念3 天前
[OpenGL]使用OpenGL实现硬阴影效果
c++·计算机图形学·opengl
鸢_3 天前
【Threejs】相机控制器动画
javascript·实时互动·动画·webgl
_oP_i5 天前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
新中地GIS开发老师6 天前
WebGIS和WebGL的基本概念介绍和差异对比
学习·arcgis·webgl
_oP_i7 天前
Unity 中使用 WebGL 构建并运行时使用的图片必须使用web服务器上的
前端·unity·webgl
flying robot9 天前
Three.js简化 WebGL 的使用
webgl
小彭努力中10 天前
114. 精灵模型标注场景(贴图)
前端·3d·webgl·贴图
小彭努力中10 天前
109. 工厂光源(环境贴图和环境光)
前端·深度学习·3d·webgl·贴图
黑猫很白10 天前
计算机图形学-动画Animation-仿真物理模拟Simulation
计算机图形学