flowchart LR
classDef importentNode fill:#f7630c,stroke:#999,stroke-width:1px,color:#eff1f5;
subgraph A[几何处理]
direction TD
A1[输入装配]
A2[顶点着色器]
A4[<图元装配><br>顶点组成:点线,三角形]
A5[剪裁]:::importentNode
A6[<透视除法><br>也就是:xyz ÷ w 得到 NDC ]
A7[<视口变换><br>将 NDC 坐标映射到屏幕]
A8[正反面判定与剔除]:::importentNode
end
subgraph A3[可选阶段]
direction TD
A3_1[几何着色器]
A3_2[曲面细分]
A3_3[流式输出]
end
A1-->A2-->A3-->A4-->A5-->A6-->A7-->A8
A2-->|可以不选|A4
图元装配_剪裁_透视除法与NDC坐标_视口变换_剔除
flowchart LR
classDef importentNode fill:#f7630c,stroke:#999,stroke-width:1px,color:#eff1f5;
classDef note fill:#16c60c,stroke:#999,stroke-width:1px,color:#eff1f5;
subgraph A[剪裁与剔除]
direction LR
A1[图元装配]
A2[裁剪]:::importentNode
A3[透视除法]
A4[视口变换]
A5[正反面判定与剔除]:::importentNode
A6[/输出/]
end
A1-->A2-->A3-->A4-->A5-->A6
🟠剪裁
-
剪裁就是沿着视锥的边界,把三角形露在视野外的部分切掉,在边界上插入新顶点,只保留视野里的部分。
-
剪裁在 剪裁空间里干活,判断顶点着色器输出的剪裁空间的顶点坐标,是否在视锥内。
- 一个顶点在视锥内的判断规则:
- -w ≤ x ≤ w
- -w ≤ y ≤ w
- -w ≤ z ≤ w
- 正好对应视锥的 6 个面:左、右、上、下、近、远,共 6 个边界。
- 一个顶点在视锥内的判断规则:
-
剪裁输入输出
- 剪裁接收图元装配阶段的完整图元,每个顶点都带有顶点着色器输出的全部属性:顶点剪裁空间位置(x,y,z,w)、法线、颜色、UV等。
🟠剔除(这里一般说的是背面剔除)
- 封闭物体的背面,从摄像机方向永远看不见,那干脆就不画了。它可以手动切换剔除模式。
- 做三角形的正反面判定
- 对每一个三角形,用 NDC 空间的三个顶点,计算环绕顺序,判断是正面还是背面在 NDC 里看是逆时针(CCW)→ 正面,是顺时针(CW)→ 背面。
[!note] 我们可以在 图形 api 中配置是逆时针顶点顺序决定三角形正面还是顺时针决定正面。
`IsFrontFaceCCW`:CCW = 逆时针为正面;CW = 顺时针为正面
- 剔除 指定的面
- 是 GPU 几何处理阶段的固定步骤
- 每个三角形都有正反面,由顶点顺序决定正反。
- 不渲染三角形的背面,比如一个封闭的物体,相机正常来讲都看不到里边的面。
- 他可以节省一半的性能。游戏引擎一般会默认开启
[!note] cocos 中的背面剔除
- 在cocos 材质属性面板中 可以更改pipeline state 中的cull mode 来决定使用什么 背面剔除模式
剔除模式 效果 使用场景 BACK 默认值,剔除背面,只渲染正面 绝大多数封闭的 3D 物体(立方体、角色、建筑等),性能最好 FRONT 剔除正面,只渲染背面 用来做 “从物体内部看” 的特殊效果、比如天空球 NONE 不剔除,正反面都渲染 薄物体(树叶、纸张、布料)、透明面片、需要双面显示的物体
[!error] cocos 中,阴影投射 pass2 : Shadow-caster 也默认开启了背面剔除模式。会导致单面不封闭模型投射出来的阴影缺失
🟢透视除法_NDC坐标_视口变换
裁剪空间:四维,边界随 w 改变
↓ xyz / w
NDC:三维,统一落在规范立方体内
↓ 视口变换
屏幕/窗口坐标:以像素计
flowchart LR
classDef importentNode fill:#f7630c,stroke:#999,stroke-width:1px,color:#eff1f5;
classDef note fill:#16c60c,stroke:#999,stroke-width:1px,color:#eff1f5;
subgraph A[透视除法_NDC坐标_视口变换]
direction LR
A1[< 裁剪空间 ><br>四维,边界随 w 改变]
A2[< NDC空间 ><br>三维,落在规范立方体内]
A3[< 屏幕空间 ><br>二维,以像素计算]
end
A1-->|透视除法|A2-->|视口变换|A3
透视除法
- 透视除法 = 把裁剪空间的 x、y、z 全都除以 w
- 除以 w 之后,远处物体坐标被压缩,自动实现近大远小的透视效果。也就是自动实现了透视相机的效果
- 如果想要正交相机的效果,w=1 除以 w 坐标不变就能实现
NDC 坐标空间
NDC 是一个正方形立方体(归一化盒子)。
在NDC空间中的所有可见顶点坐标都会被归一化: x ∈ [-1, 1],y ∈ [-1, 1],z ∈ [-1,1]
视口变换
- 下面是视口变换的公式
- screen_x=(x_{ndc}+1)\times0.5\times viewportWidth+viewportX
- screen_y=(y_{ndc}+1)\times0.5\times viewportHeight+viewportY
screenX = (ndc.x + 1) * 0.5 * viewportWidth + viewportX
screenY = (ndc.y + 1) * 0.5 * viewportHeight + viewportY
+ viewportX 是为了把“视口内部坐标”平移到“整个渲染目标中的实际位置”。
评论区