
顶点着色器输出后三角形为什么是四个分量 (x, y, z, w)一、先给结论最重要顶点着色器输出的不是“屏幕坐标”而是裁剪空间齐次坐标Clip Space, Homogeneous Coordinates(x, y, z, w)其中分量含义x裁剪空间 Xy裁剪空间 Yz裁剪空间 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 DivisionGPU 在光栅化前自动做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 实际行为在裁剪空间 插值 (x, y, z, w)对每个像素做x/w, y/w, z/w✅ 保证纹理不变形深度正确透视正确七、w 还能干什么高级但重要1️⃣ 投影纹理Projective Textureuv (x/w, y/w)2️⃣ 阴影贴图light_space x/w3️⃣ 顶点属性插值颜色、法线、UV 都“除以 w”八、一句话总结顶点着色器输出的 (x, y, z, w)不是屏幕坐标而是“透视正确的中间表达”w是透视投影的灵魂没有w光栅化会全错屏幕坐标 (x/w, y/w)