请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

getPerspective 实现原理

我开发中发现,老师实现的透视投影矩阵与第三方库,在相同参数的情况下,得到的结果不一致,请问下老师这两种实现方式有什么区别。

我测试三种方案

  • 老师的
  • gl-matrixmat4perspective
  • chatgpt 生成的
import {mat4} from 'gl-matrix'
const WIDTH = 500
const HEIGHT = 500

/**
 * getPerspectiveMatrix 获取透视投影矩阵 (chatgpt 给出的)
 * @param {number} fieldOfView 视野角度,单位为弧度
 * @param {number} aspectRatio 宽高比
 * @param {number} nearPlane 近平面距离
 * @param {number} farPlane 远平面距离
 * @returns {Float32Array<number>} 透视投影矩阵,使用 Float32Array 表示
 */
const getPerspectiveMatrix = (fieldOfView, aspectRatio, nearPlane, farPlane) => {
    const f = Math.tan(Math.PI * 0.5 - 0.5 * fieldOfView);
    const rangeInv = 1.0 / (nearPlane - farPlane);

    return new Float32Array([
        f / aspectRatio, 0,                                     0,  0,
        0,               f,                                     0,  0,
        0,               0,   (nearPlane + farPlane) * rangeInv,    -1,
        0,               0,   nearPlane * farPlane * rangeInv * 2,  0
    ]);
}

// 获取透视投影矩阵 (老师的)
function getPerspective(fov, aspect, far, near) {
    fov = fov * Math.PI / 180;
    return new Float32Array([
        1/(aspect*Math.tan(fov / 2)), 0, 0, 0,
        0, 1/(Math.tan(fov/2)),0,0,
        0,0,-(far+near)/(far-near),-(2*far*near)/(far-near),
        0,0,-1,0,
    ])
}

const perspectiveMatrix1 = getPerspective(150, WIDTH / HEIGHT, 100, 1) // 老师的
const perspectiveMatrix2 = mat4.perspective(new Float32Array(16), 150, WIDTH / HEIGHT, 1, 100)  // gl-matrix
const perspectiveMatrix3 = getPerspectiveMatrix(150, WIDTH / HEIGHT, 1, 100) // chatgpt

console.log(perspectiveMatrix1) // 老师的
console.log(perspectiveMatrix2) // gl-matrix
console.log(perspectiveMatrix3) // chatgpt

返回结果:
图片描述

得出的结果: gl-matrix = chatgpt != 老师

正在回答 回答被采纳积分+3

6回答

提问者 核桃丷 2023-04-17 11:20:21

https://img1.sycdn.imooc.com//szimg/643cba930916731f08350865.jpg

如果按照着矩阵公式的形状来实现js矩阵函数,这个坐标完全就对应不上

1 回复 有任何疑惑可以回复我~
提问者 核桃丷 2023-04-17 11:06:38

官方给出的实现代码是

class Mat4 {
  static perspective(fovy, aspect, near, far, out = []) {
    const f = 1 / Math.tan(fovy / 2);
    out[0] = f / aspect;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[4] = 0;
    out[5] = f;
    out[6] = 0;
    out[7] = 0;
    out[8] = 0;
    out[9] = 0;
    out[11] = -1;
    out[12] = 0;
    out[13] = 0;
    out[15] = 0;
    if (far != null && far !== Infinity) {
      const nf = 1 / (near - far);
      out[10] = (far + near) * nf;
      out[14] = 2 * far * near * nf;
    } else {
      out[10] = -1;
      out[14] = -2 * near;
    }
    return out;
  }
}

https://img1.sycdn.imooc.com//szimg/643cb75209182f6203690122.jpg

这个 -1 明明在下标 14上,但是却赋值在了 11上,这个11是竖着数的,但是js数组是横着来的,就不是很理解,老师可以帮忙解释下吗

1 回复 有任何疑惑可以回复我~
  • 提问者 核桃丷 #1
    这个问题换句话说,就是我怀疑老师的这个坐标是不是弄错了,除了这个 透视矩阵 ,我发现 正交矩阵的推导和老师的也不一样。
    回复 有任何疑惑可以回复我~ 2023-04-17 11:18:32
  • 慕运维2471188 回复 提问者 核桃丷 #2
    矩阵元素在javascript代码中是按列主序展示和存储,而在数学推导上主要是以行主序展示和存储
    回复 有任何疑惑可以回复我~ 2023-07-06 14:24:11
  • 提问者 核桃丷 回复 慕运维2471188 #3
    你可以对比下第三方库的实现,老师的是错的
    回复 有任何疑惑可以回复我~ 2023-07-06 14:26:29
yancy 2023-04-17 16:45:41

可以看下lib文件里的使用,有说明要做矩阵转换

0 回复 有任何疑惑可以回复我~
yancy 2023-04-17 14:31:51

可以看下相关实现,比如:z轴的方向,归一化的处理,坐标的处理。一般的不同是由于z轴方向不同导致的

0 回复 有任何疑惑可以回复我~
  • 提问者 核桃丷 #1
    老师,你在根据推导矩阵,实现js函数的时候没有把行矩阵转成列矩阵
    回复 有任何疑惑可以回复我~ 2023-04-17 14:34:17
提问者 核桃丷 2023-04-17 11:45:19
0 回复 有任何疑惑可以回复我~
  • 提问者 核桃丷 #1
    老师在根据矩阵实现js函数的时候没有做行列转换
    回复 有任何疑惑可以回复我~ 2023-04-17 11:51:11
提问者 核桃丷 2023-04-17 11:28:43

关于矩阵顺序:如图

https://img1.sycdn.imooc.com//szimg/643cbccd0946ec3007310432.jpg

0 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信