WebGL打开 3D 世界的大门(六):透视投影

这一节我们来介绍透视投影,那什么是透视投影呢?和我们说的正射投影有什么不同呢?在现实生活中距离我们越远的物体就看起来越小,这就是透视投影,就是在z轴方向上,距离我们越远的物体,在表现上来说就越小,这一节我们先写一个简单的透视投影,然后讨论一下透视矩阵,以及透视矩阵的生成过程,最后用透视矩阵实现E的展示。

一个简单的透视算法

我们可以这样想,一个最简单的透视算法就是用一个点的X,Y坐标除以Z坐标就行了,这就能实现到我们距离越远,距离越小的效果。我们在第5章的基础上修改顶点着色器,如下

ini 复制代码
float z_half = a_position.z * 0.005;
vec3 t_position = vec3(a_position.x/z_half,a_position.y/z_half,a_position.z);
// vec4(a_position.xy / z, z, 1.0);
vec3 position = (matrix_translate * matrix_rotateX * matrix_rotateY * matrix_rotateZ * matrix_scale * vec4(t_position, 1)).xyz;

至于为什么要乘以0.005,那是由于我们的z值有点大,并且这个算法不准确,取了一个经验值。效果如下:

可以较为明显的看到3D的透视效果。感兴趣的同学可以自行调节参数再试试其他的。很明显我们的透视算法并不好,太简单了。见到到就不太正确,下面我们介绍真能整的透视变换。

透视矩阵的生成

关于什么是透视,首先要上图,一图胜千言。

这两张图来源于计算机图形学这本书。我们要有一个感性的认识就行了。什么是感性的认识呢,从数学上来讲就是要知道相关系数,看图说话,首先在z轴方向的大小肯定和z轴距离有关,其次和上下夹角ɑ有关,再次和左右∂夹角有关,所以生成矩阵函数的肯定是这样的 Z = f(z,ɑ,∂);具体到底怎么计算的,其实不在我们的讨论范围,我们又不是搞数学的,我们你需要的是结果。结果如下:

以上内容来源于deepseek。然后感性分析一下,嗯应该是对的。然后我们在代码里面根据这个信息,构造透视矩阵。

使用透视矩阵

然后将透视矩阵放到我们以前的代码中。主要代码:

ini 复制代码
/**
 * 构造透视投影矩阵(列主序)
 * @param {number} fov - 垂直视野角(弧度制,如 Math.PI/4)
 * @param {number} aspect - 宽高比(width / height)
 * @param {number} near - 近裁剪面距离(必须 > 0)
 * @param {number} far - 远裁剪面距离(必须 > near)
 * @returns {Float32Array} 4x4 透视矩阵(列主序)
 */
function createPerspectiveMatrix(fov, aspect, near, far) {
  // 1. 计算垂直方向的缩放因子(基于视野角)
  const f = 1.0 / Math.tan(fov / 2); // 相当于 1/tan(fov/2)

  // 2. 计算深度范围倒数(用于非线性深度映射)
  const rangeInv = 1.0 / (near - far);

  // 3. 初始化列主序矩阵(16元素 Float32Array)
  const matrix = new Float32Array(16);

  // 第一列
  matrix[0] = f / aspect; // x 缩放(受宽高比影响)
  matrix[1] = 0;
  matrix[2] = 0;
  matrix[3] = 0;

  // 第二列
  matrix[4] = 0;
  matrix[5] = f;          // y 缩放
  matrix[6] = 0;
  matrix[7] = 0;

  // 第三列(深度处理)
  matrix[8] = 0;
  matrix[9] = 0;
  matrix[10] = (far + near) * rangeInv;  // 非线性深度映射
  matrix[11] = -1;                       // 透视除法关键

  // 第四列
  matrix[12] = 0;
  matrix[13] = 0;
  matrix[14] = 2 * far * near * rangeInv; // 深度平移
  matrix[15] = 0;

  return matrix;
}

效果如下:

代码地址: gitee.com/feng-lianxi...

总结

有了透视矩阵我们就可以建立摄像机的概念了,这样你就会对three.js的摄像机场景画布,有更清晰的概念。下一节我们就介绍摄像机。

相关推荐
@PHARAOH1 小时前
HOW - 在 Mac 上的 Chrome 浏览器中调试 Windows 场景下的前端页面
前端·chrome·macos
月月大王3 小时前
easyexcel导出动态写入标题和数据
java·服务器·前端
JC_You_Know4 小时前
多语言网站的 UX 陷阱与国际化实践陷阱清单
前端·ux
Python智慧行囊4 小时前
前端三大件---CSS
前端·css
Jinuss5 小时前
源码分析之Leaflet中Marker
前端·leaflet
成都渲染101云渲染66665 小时前
blender云渲染指南2025版
前端·javascript·网络·blender·maya
聆听+自律5 小时前
css实现渐变色圆角边框,背景色自定义
前端·javascript·css
牛马程序小猿猴6 小时前
17.thinkphp的分页功能
前端·数据库
huohuopro6 小时前
Vue3快速入门/Vue3基础速通
前端·javascript·vue.js·前端框架
草巾冒小子6 小时前
vue3中解决 return‘ inside ‘finally‘ block报错的问题
前端·javascript·vue.js