【渲染流水线】[几何阶段]-[屏幕映射]以UnityURP为例

  • 屏幕映射阶段是将NDC三维空间坐标转换为最终屏幕像素位置的关键步骤。
  • 此阶段由GPU固定管线完成,开发者不可编程,仅可通过视口设置调整映射范围

【从UnityURP开始探索游戏渲染】专栏-直达

NDC坐标范围

  • NDC空间是裁剪空间经过透视除法(除以w分量)后得到的归一化立方体,坐标范围为:
  • x, y轴:[-1, 1](左下角为(-1,-1),右上角为(1,1)
  • z轴:[0, 1](深度值,0为近裁剪面,1为远裁剪面)

视口变换(屏幕映射)

  • 将NDC坐标映射到屏幕空间:
  • x轴 ‌:将[-1, 1]线性映射到[0, 屏幕宽度]
    • xScreen=(xNDC+1)×0.5×屏幕宽度
  • y轴 ‌:因屏幕坐标系原点在左上角,需反转y轴(1 - NDC_y)再映射到[0, 屏幕高度]
    • yScreen=(1−yNDC)×0.5×屏幕高度
  • 保留z_{ndc}用于深度测试‌

URP中的具体映射案例‌

  • 假设屏幕分辨率为1920×1080,一个NDC坐标为(0, 0, 0.5)
  • x轴映射 ‌:Screen_x = (0 + 1)/2 × 1920 = 960
  • y轴映射 ‌:Screen_y = (1 - 0)/2 × 1080 = 540(因y轴反转,NDC的0对应屏幕顶部)
  • 结果 ‌:该点位于屏幕正中央像素(960, 540)

‌技术细节说明‌

  • 视口调整 ‌:可通过UnityEngine.Rendering.CommandBuffer.SetViewport修改映射区域(如画中画效果),默认映射全屏。
  • 与裁剪空间关系 ‌:顶点着色器需输出齐次裁剪坐标(如UnityObjectToClipPos(v.vertex)),GPU自动执行透视除法和屏幕映射。
  • 精度影响‌:高分辨率下浮点精度误差可能引起像素偏移,需注意抗锯齿设置。
glsl 复制代码
//计算点在屏幕空间中的位置:首先positionCS中的值还没有进行其次除法,需要先除以positionCS.w转换为
//NDC坐标,范围[-1,1],然后*0.5+0.5后转为[0,1],最后乘以_ScreenParams转换为最终的屏幕空间位置
float2 p0 = _ScreenParams.xy * (p[0].positionCS.xy / p[0].positionCS.w * 0.5 + 0.5);

几何阶段完整流程及数据变换示例‌

初始坐标 ‌:模型空间顶点坐标 (2.0, 1.0, -3.0, 1.0)(齐次坐标w=1),摄像机使用透视投影,近平面z=0.3,远平面z=1000,视口分辨率1920x1080。

‌1. 顶点着色器(Vertex Shader)‌

  • 输入 ‌:模型空间坐标 (2.0, 1.0, -3.0, 1.0)
  • 操作 ‌:应用MVP矩阵(Model-View-Projection)变换到齐次裁剪空间。假设变换后输出为:(x ′,y ′,z ′,w′)=(1.5,0.8,−2.2,3.0)
  • 输出 ‌:齐次裁剪坐标 (1.5, 0.8, -2.2, 3.0)

‌2. 曲面细分着色器(可选,Tessellation Shader)‌

  • 输入‌:若启用细分,接收控制点数据(如原始三角形顶点)。
  • 操作 ‌:细分生成新顶点,例如输出新增顶点 (1.2, 0.6, -2.0, 2.8)
  • 输出‌:细分后的齐次裁剪坐标(假设未启用,跳过此阶段)

‌3. 几何着色器(可选,Geometry Shader)‌

  • 输入‌:图元顶点(如三角形三个顶点)。
  • 操作‌:可生成新图元(如将三角形拆分为多个线段)。若未启用,直接传递数据。
  • 输出‌:原始或新增的齐次裁剪坐标(假设未启用,跳过此阶段)

‌4. 图元装配(Primitive Assembly)‌

  • 输入 ‌:齐次裁剪坐标 (1.5, 0.8, -2.2, 3.0)(假设为三角形的一个顶点)。
  • 操作‌:将顶点组装为图元(如三角形),并计算包围盒。
  • 输出‌:完整的三角形图元(三个顶点数据)

‌5. 视锥体裁剪(Frustum Culling)‌

  • 输入 ‌:齐次裁剪坐标 (1.5, 0.8, -2.2, 3.0)
  • 操作 ‌:
    • 透视除法 ‌:转换为NDC坐标 (1.5/3.0, 0.8/3.0, -2.2/3.0) = (0.5, 0.267, -0.733)
    • 边界检查‌:若NDC坐标超出[-1,1]范围则裁剪。本例中x/y在范围内,但z=-0.733(OpenGL下有效,DirectX需z∈[0,1]则剔除)。
    • 插值裁剪‌:若部分顶点超出边界,生成新顶点(如裁剪z边界时插值计算新坐标)。
  • 输出 ‌:裁剪后的NDC坐标(假设全部保留) (0.5, 0.267, -0.733)

‌6. 屏幕映射(Screen Mapping)‌

  • 输入 ‌:NDC坐标 (0.5, 0.267, -0.733)
  • 操作 ‌:
    • 视口变换 ‌:将NDC的xy映射到屏幕像素坐标(如1920x1080):
      • xscreen=(0.5+1)∗1920/2=1440
      • yscreen=(0.267+1)∗1080/2=684.18
    • 深度保留 ‌:z值转换为深度缓冲值(如OpenGL下 (-0.733+1)/2=0.1335)。
  • 输出 ‌:屏幕空间坐标 (1440, 684, 0.1335)

【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

相关推荐
变身缎带5 小时前
Unity中的NetworkManager基于protobuf, Socket-TCP
tcp/ip·unity·游戏引擎
AllBlue13 小时前
unity调用安卓方法
android·unity·游戏引擎
郝学胜-神的一滴13 小时前
Horse3D游戏引擎研发笔记(十):在QtOpenGL环境下,视图矩阵与投影矩阵(摄像机)带你正式进入三维世界
c++·3d·unity·游戏引擎·godot·图形渲染·unreal engine
AllBlue16 小时前
unity导出成安卓工程,集成到安卓显示
android·unity·游戏引擎
Sator119 小时前
Unity的FishNet相关知识
网络·unity·游戏引擎
AllBlue19 小时前
安卓调用unity中的方法
android·unity·游戏引擎
jtymyxmz1 天前
《Unity Shader》10.1.4 折射
unity·游戏引擎
在路上看风景1 天前
12. Burst
unity
平行云PVT2 天前
实时云渲染解决UE5 像素流插件迁移及传输数据受限问题
unity·ue5·xr·实时云渲染·云桌面·像素流·云推流
熬夜敲代码的小N2 天前
Unity WebRequest高级操作:构建高效稳定的网络通信模块
android·数据结构·unity·游戏引擎