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

相关推荐
m0_7482480210 小时前
WebAssembly与WebGL结合:高性能图形处理
webgl·wasm
刘好念15 小时前
[OpenGL]使用 Compute Shader 实现矩阵点乘
c++·计算机图形学·opengl·glsl
程序员_三木2 天前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
汪洪墩3 天前
【Mars3d】设置backgroundImage、map.scene.skyBox、backgroundImage来回切换
开发语言·javascript·python·ecmascript·webgl·cesium
m0_748234343 天前
webGL硬核知识:图形渲染管渲染流程,各个阶段对应的API调用方式
图形渲染·webgl
MossGrower3 天前
36. Three.js案例-创建带光照和阴影的球体与平面
3d图形·webgl·three.js·光照与阴影
MossGrower4 天前
34. Three.js案例-创建球体与模糊阴影
webgl·three.js·3d渲染·阴影效果
charlee444 天前
深度科普文:细数倾斜摄影数据的缺点
三维可视化·计算机图形学·倾斜摄影
刘好念4 天前
[OpenGL]使用TransformFeedback实现粒子效果
c++·计算机图形学·opengl