- 在Unity URP渲染管线中,光栅化阶段的片元着色器(Fragment Shader)是决定像素最终颜色的核心环节。
【从UnityURP开始探索游戏渲染】专栏-直达
核心功能:
- 纹理采样:通过UV坐标从贴图获取颜色数据
- 光照计算:结合材质属性和光源信息计算逐像素光照
- 特效处理:实现透明度混合、边缘检测等后处理效果
可配置:
- 重写片元函数(
#pragma fragment frag
)。语义、纹理用途、
语义体系
输入结构体(v2f)语义
SV_POSITION
:裁剪空间顶点位置(必需),由顶点着色器输出TEXCOORD0-7
:通用插值寄存器,存储UV坐标/自定义数据(如法线、视向量)COLOR0-1
:顶点颜色通道,常用于渐变效果或数据传递NORMAL
:世界空间法线向量(需手动计算后传递)
输出语义
SV_Target
:写入渲染目标(默认颜色缓冲)SV_Depth
:自定义深度值输出(需显式启用)
TEXCOORD0-7
和COLOR0-1
语义的常用数据存储内容
语义 | 常用存储数据 | 典型应用场景 |
---|---|---|
TEXCOORD0 |
主纹理UV坐标 | 采样漫反射贴图(_MainTex) |
TEXCOORD1 |
次要纹理UV坐标 | 光照贴图、细节纹理叠加 |
TEXCOORD2 |
世界空间法线向量 | 法线贴图计算、光照模型处理 |
TEXCOORD3 |
世界空间切线向量 | 切线空间转换、法线映射 |
TEXCOORD4 |
世界空间视线方向 | 高光反射计算、视差效果 |
TEXCOORD5 |
世界空间顶点位置 | 动态雾效、距离衰减计算 |
TEXCOORD6-7 |
自定义数据或额外UV集 | 顶点动画参数、流动贴图、多纹理混合 |
COLOR0 |
顶点颜色主通道 | 顶点着色效果、渐变色处理(如植被/地形) |
COLOR1 |
顶点颜色辅助通道 | 特殊效果遮罩、动态参数传递(如溶解阈值) |
关键说明:
-
数据复用性
TEXCOORD
语义本质上是通用插值寄存器,实际用途根据Shader需求动态分配4。例如简单着色器可能仅用TEXCOORD0
,而复杂PBR材质会占用更多通道。 -
优化建议
URP推荐将关联数据打包到同一寄存器(如法线/切线共用
TEXCOORD2-3
),减少插值计算开销。 -
通道限制
移动端平台最多支持8个
TEXCOORD
和2个COLOR
通道,超限需通过数据压缩或纹理烘焙解决
内容映射表
核心纹理变量
纹理变量名 | 来源类/脚本 | 用途说明 |
---|---|---|
_MainTex |
Material 属性面板 |
基础颜色/Albedo贴图(通过[MainTexture] 特性标记) |
_BaseMap |
URP Shader内置变量 | 替代_MainTex 的标准化命名(URP 7.0+版本推荐使用) |
_NormalMap |
Standard Shader /自定义Shader |
切线空间法线贴图(需配合BUMP 关键字启用) |
_MetallicGlossMap |
PBR材质系统 | 金属度(R)和光滑度(A)通道存储 |
_EmissionMap |
Material 发光属性 |
自发光纹理(需启用_EMISSION 关键字) |
特殊功能纹理
纹理变量名 | 来源类/脚本 | 用途说明 |
---|---|---|
_OcclusionMap |
光照探针系统 | 环境光遮蔽贴图(通常存储在G通道) |
_DetailAlbedoMap |
细节层材质 | 表面微结构纹理(通过_DETAIL 宏控制) |
_ParallaxMap |
高度图效果 | 视差偏移贴图(需启用_PARALLAXMAP ) |
_SpecGlossMap |
旧版高光工作流 | 高光颜色(RGB)和光滑度(A)替代金属度贴图 |
渲染管线专用纹理
纹理变量名 | 来源类/脚本 | 用途说明 |
---|---|---|
_CameraColorTexture |
URP RendererFeature |
相机颜色缓冲(后处理输入) |
_CameraDepthTexture |
URP DepthTexture 模式 |
场景深度图(需在URP Asset中启用) |
_ScreenSpaceOcclusion |
SSAO效果 | 屏幕空间环境遮蔽图(通过SSAO Renderer Feature生成) |
脚本动态引用示例
glsl
hlsl
// C#脚本中通过Material类设置纹理
material.SetTexture("_MainTex", Resources.Load<Texture2D>("Albedo"));
- 该代码通过
Material.SetTexture
方法动态绑定纹理 - 纹理变量命名遵循URP核心库规范(
Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl
),其中WS
后缀表示世界空间坐标,RWS
为相机相对坐标。移动端需注意通过SAMPLER
宏声明采样器以兼容GLES2.0平台
纹理数组高级应用
glsl
Texture2DArray _TextureArray; // 声明纹理数组
float _LayerIndex; // 动态切换纹理层
fixed4 frag(v2f i) : SV_Target {
return tex2DArray(_TextureArray, float3(i.uv, _LayerIndex));
}
该技术适用于地形系统(不同区块材质切换)或角色换装系统
片元着色器中的导数信息
每次片元着色器处理片元时都独立处理单个片元,因此片元在处理时无法得到临近片元信息。
实际GPU在运行时并不是只运行一个片元着色器,而是将其2x2的一组片元块,同时运行4个片元着色器。 通过ddx和ddy(URP中可通过ddx
/ddy
函数获取屏幕空间导数)两个偏导函数求得临近片元的差值。(偏导函数时纹理mipmaps实现的基础)
作用:
- 边缘检测:通过颜色/深度突变识别物体轮廓
- Mipmap层级选择:动态调整纹理采样精度
- 屏幕空间特效:如SSAO、运动模糊等
URP中基于导数的边缘检测示例
-
使用HLSL标准导数函数ddx/ddy
-
通过颜色梯度检测边缘
-
可调节阈值控制边缘灵敏度
-
兼容URP渲染管线
-
EdgeDetection.shader
glslShader "Custom/EdgeDetection" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _EdgeColor ("Edge Color", Color) = (1,0,0,1) _Threshold ("Threshold", Range(0,1)) = 0.1 } SubShader { Pass { HLSLPROGRAM #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); float4 _EdgeColor; float _Threshold; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert(Attributes v) { v2f o; o.pos = TransformObjectToHClip(v.positionOS); o.uv = v.uv; return o; } half4 frag(v2f i) : SV_Target { half3 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv).rgb; // 计算屏幕空间导数 half3 dx = ddx(col); half3 dy = ddy(col); float edge = sqrt(dot(dx,dx) + dot(dy,dy)); // 边缘检测 edge = step(_Threshold, edge); return lerp(float4(col,1), _EdgeColor, edge); } ENDHLSL } } }
在延迟渲染 中,片元着色器会利用G缓冲中的深度/法线信息进行更精确的光照计算,而前向渲染则直接在每个Pass中处理光照(内置管线每个pass处理灯光,URP中将所有灯光汇聚在一个Pass中处理)。URP通过优化后的着色器变体减少重复计算,提升多光源场景性能。
【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)