学习:顶点着色器输出后,三角形为什么是四个分量

顶点着色器输出后,三角形为什么是四个分量 (x, y, z, w)?


一、先给结论(最重要)

顶点着色器输出的不是"屏幕坐标",

而是 裁剪空间齐次坐标(Clip Space, Homogeneous Coordinates):

复制代码
(x, y, z, w)

其中:

分量 含义
x 裁剪空间 X
y 裁剪空间 Y
z 裁剪空间 Z(深度)
w 齐次坐标的"除数"

👉 真正的屏幕坐标 = (x/w, y/w, z/w)


二、为什么不是 (x, y, z) 就够了?

1️⃣ 透视投影无法用 3D 坐标正确表达

在透视投影下:

  • 远处的物体更小
  • 平行线会交汇(透视收敛)

如果用普通 3D 坐标:

复制代码
(x, y, z)

你无法在后续步骤中做正确的透视除法


2️⃣ 齐次坐标的本质作用

w 的作用是:

把"透视除法"延迟到最后一步

这样:

  • 裁剪
  • 插值
  • 深度计算

都可以在 线性空间​ 中正确进行


三、这四个值是怎么来的?

1️⃣ 顶点着色器中你通常写的代码

复制代码
gl_Position = projection * view * model * vec4(aPos, 1.0);

最终得到的:

复制代码
gl_Position = (x, y, z, w)

2️⃣ 投影矩阵做了什么?

以透视投影为例:

复制代码
x_clip = x_eye * fov_scale / aspect
y_clip = y_eye * fov_scale
z_clip = 混合(near, far)
w_clip = -z_eye

✅ 注意:w 通常等于 -z_eye


四、为什么 z 也要保留?

1️⃣ z 不是"深度值本身"

在裁剪空间中:

复制代码
z ∈ [-w, w]

它用于:

  • 深度缓冲(Z-Buffer)
  • 裁剪判断
  • 透视正确插值

2️⃣ 屏幕深度是"非线性"的

经过透视除法后:

复制代码
depth = z/w

结果:

  • 近处精度高
  • 远处精度低

✅ 这是故意设计的(符合人眼)


五、w 到底为什么这么重要?

1️⃣ 透视除法(Perspective Division)

GPU 在光栅化前自动做:

复制代码
x_ndc = x / w
y_ndc = y / w
z_ndc = z / w

得到 NDC(标准化设备坐标):

复制代码
x ∈ [-1, 1]
y ∈ [-1, 1]
z ∈ [-1, 1]

2️⃣ 再映射到屏幕

复制代码
screen_x = (x_ndc + 1) * width  / 2
screen_y = (1 - y_ndc) * height / 2

👉 这才是你最终看到的像素位置


六、为什么插值也必须用 (x, y, z, w)?

❌ 错误做法

直接在屏幕空间插值 (x, y)

→ 近大远小会变形


✅ 正确做法(GPU 实际行为)

  1. 在 裁剪空间 插值 (x, y, z, w)

  2. 对每个像素做:

    x/w, y/w, z/w

✅ 保证:

  • 纹理不变形
  • 深度正确
  • 透视正确

七、w 还能干什么?(高级但重要)

1️⃣ 投影纹理(Projective Texture)

复制代码
uv = (x/w, y/w)

2️⃣ 阴影贴图

复制代码
light_space = x/w

3️⃣ 顶点属性插值

颜色、法线、UV 都"除以 w"


八、一句话总结

**顶点着色器输出的 (x, y, z, w)**​

不是屏幕坐标,而是"透视正确的中间表达"

  • w 是透视投影的灵魂
  • 没有 w,光栅化会全错
  • 屏幕坐标 = (x/w, y/w)

相关推荐
撩得Android一次心动3 小时前
Jetpack Compose 知识点整理2【个人用】
android·笔记·学习·kotlin·compose
dadaobusi4 小时前
学习:灵犀指令集
学习
xhyu615 小时前
【学习笔记】图像质量评估方法 (5.生成图像是否符合用户要求)
笔记·学习·计算机视觉
卿卿的产品经理日记7 小时前
【AI产品经理实战】Day 38|try-except 踩坑实录:报错是数据
人工智能·笔记·python·学习·产品经理
keyipatience7 小时前
TypeScript学习(1)
前端·javascript·学习·typescript·html·css3
lazy H8 小时前
【计算机网络】第 2 篇:一条数据如何穿过网络?彻底理解数据封装与解封装
网络·经验分享·后端·学习·计算机网络
我命由我123458 小时前
软件工程概念 - 可插拔性
java·后端·学习·java-ee·系统架构·软件工程·学习方法
kkkkkkkkkk_Z10 小时前
新手自学嵌入式 | 学习日记:I2C总线协议、时序分析、读写流程与代码实现
学习
鬼手点金11 小时前
构建有效 Agent 的核心原则
java·人工智能·git·学习·自动化
姜九笙56112 小时前
python学习---归来仍是新人
java·python·学习