You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用gl-matrix进行透视投影后坐标值异常问题排查

问题:透视变换后点坐标极小不符合预期?

我使用gl-matrix JS库进行3D点变换,使用model-view矩阵(lookAt)时,变换后的点结果合理。但在此基础上添加透视投影后,得到的变换点坐标值极小,不符合预期。我预期透视变换后的点坐标应保持在~100的合理范围,而非集中在±0.5左右,请问问题出在哪里?

代码示例

// four points on a square
const points = [
  vec3.fromValues(  0,   0, 0),
  vec3.fromValues(200,   0, 0),
  vec3.fromValues(  0, 200, 0),
  vec3.fromValues(200, 200, 0),
]

points.forEach(function(p, i) {
  console.log("point", i, p)
})

// look from the center above the points towards the center between the points
const viewer = vec3.fromValues(100, 100, 200)
const lookat = vec3.fromValues(100, 100,   0)
const mv = mat4.create()
mat4.lookAt(mv, viewer, lookat, vec3.fromValues(0, 1, 0))

const transformed_points = [
  vec3.create(),
  vec3.create(),
  vec3.create(),
  vec3.create(),
]

points.forEach(function(p, i) {
  vec3.transformMat4(transformed_points[i], p, mv)
})

// the points transformed through model-view matrix make sense, the center is (0,0)
// and the four points are +/- 100 around the center
transformed_points.forEach(function(p, i) {
  console.log("point mv", i, p)
})

const p = mat4.create()
const mvp = mat4.create()
// then adding perspective to the model-view-perspective matris, the values
// of the transformed points are riducuously small, like +/-0.5
mat4.perspective(p, Math.PI/2, 1 /* aspect */, 100 /* near */, 1000 /* far */)
mat4.multiply(mvp, p, mv)

points.forEach(function(p, i) {
  vec3.transformMat4(transformed_points[i], p, mvp)
})

transformed_points.forEach(function(p, i) {
  console.log("point mvp", i, p)
})

运行结果

// those are the original points on a square
point 0   [ 0, 0, 0 ]
point 1   [ 200, 0, 0 ]
point 2   [ 0, 200, 0 ]
point 3   [ 200, 200, 0 ]

// the original points transformed with MV matrix, values make sense
// because the "world" is now centered at the observers eye
point mv 0   [ -100, -100, -200 ]
point mv 1   [ 100, -100, -200 ]
point mv 2   [ -100, 100, -200 ]
point mv 3   [ 100, 100, -200 ]

// when I add the perspective, the transformed points make no sense.
point mvp 0   [ -0.5, -0.5, 0.11111106723546982 ]
point mvp 1   [ 0.5, -0.5, 0.11111106723546982 ]
point mvp 2   [ -0.5, 0.5, 0.11111106723546982 ]
point mvp 3   [ 0.5, 0.5, 0.11111106723546982 ]

问题原因与解决办法

这是透视投影矩阵的正常行为,并非代码错误。

gl-matrix的mat4.perspective生成的是符合OpenGL规范的透视投影矩阵,它的核心作用是将3D视锥体内的点转换到标准化设备坐标(NDC)——这个坐标系的x、y、z范围默认都是[-1, 1]区间,所以你的点变换后落在±0.5是完全合理的。

为什么会出现这种情况?

  • 透视投影的本质是模拟人眼的近大远小效果,同时将所有可见空间内的点压缩到归一化的坐标区间,这样GPU才能正确完成后续的裁剪、光栅化等渲染步骤。
  • 结合你的参数:90度视场角(Math.PI/2)、1:1的宽高比、近裁剪面100、远裁剪面1000,再加上model-view变换后点的z坐标为-200(处于相机前方的视锥体内),经过透视矩阵计算后,x/y轴会被相应缩放,最终落在NDC的合理区间内。

如何得到你预期的坐标范围?

如果想要保留类似原始的坐标量级,有两种方案:

  1. 改用正交投影:如果不需要透视效果,使用mat4.ortho生成正交投影矩阵,它会保持坐标的线性缩放,不会将点压缩到归一化区间。
  2. 调整渲染流程认知:如果你需要透视效果,其实不需要纠结NDC的坐标大小——GPU会自动将NDC坐标转换为屏幕坐标,这个过程会根据你的画布尺寸重新映射到像素级的坐标范围。如果你确实需要手动获取屏幕空间坐标,可以在得到NDC后自行进行逆映射计算。

内容的提问来源于stack exchange,提问作者Jakub M.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:59:17