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的摄像机场景画布,有更清晰的概念。下一节我们就介绍摄像机。

相关推荐
lecepin9 小时前
AI Coding 资讯 2025-09-17
前端·javascript·面试
IT_陈寒9 小时前
React 18实战:7个被低估的Hooks技巧让你的开发效率提升50%
前端·人工智能·后端
树上有只程序猿10 小时前
终于有人把数据库讲明白了
前端
猩兵哥哥10 小时前
前端面向对象设计原则运用 - 策略模式
前端·javascript·vue.js
司宸10 小时前
Prompt设计实战指南:三大模板与进阶技巧
前端
RoyLin10 小时前
TypeScript设计模式:抽象工厂模式
前端·后端·typescript
华仔啊10 小时前
Vue3+CSS 实现的 3D 卡片动画,让你的网页瞬间高大上
前端·css
江城开朗的豌豆10 小时前
解密React虚拟DOM:我的高效渲染秘诀 🚀
前端·javascript·react.js
vivo互联网技术10 小时前
拥抱新一代 Web 3D 引擎,Three.js 项目快速升级 Galacean 指南
前端·three.js