URP Shader编程规则之Properties

完整Properties示例

c 复制代码
Shader "Custom/URPExample"
{
    Properties
    {
        // ========== 1. 基础属性 ==========
        [Header(Base Properties)]
        [MainTexture] _BaseMap("Base Texture", 2D) = "white" {}
        [MainColor] _BaseColor("Base Color", Color) = (1,1,1,1)
        
        // ========== 2. 纹理属性 ==========
        [Header(Texture Maps)]
        [NoScaleOffset] _NormalMap("Normal Map", 2D) = "bump" {}
        _NormalScale("Normal Scale", Float) = 1.0
        
        [HDR] _EmissionMap("Emission Map", 2D) = "black" {}
        [HDR] _EmissionColor("Emission Color", Color) = (0,0,0,1)
        
        _MetallicGlossMap("Metallic (R) Smoothness (A)", 2D) = "white" {}
        _OcclusionMap("Occlusion Map", 2D) = "white" {}
        
        // ========== 3. 数值属性 ==========
        [Header(Surface Properties)]
        [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
        _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5
        _OcclusionStrength("Occlusion Strength", Range(0.0, 1.0)) = 1.0
        
        // ========== 4. 开关/枚举属性 ==========
        [Header(Options)]
        [Toggle] _UseEmission("Use Emission", Float) = 0
        [Toggle(_PARALLAXMAP)] _UseParallax("Use Parallax", Float) = 0
        [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0
        [ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0
        
        [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Src Blend", Float) = 1
        [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Dst Blend", Float) = 0
        [Enum(Off,0,On,1)] _ZWrite("Z Write", Float) = 1
        [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("Z Test", Float) = 4
        
        // ========== 5. 特殊属性 ==========
        [Header(Advanced)]
        [KeywordEnum(None, Add, Multiply)] _Overlay("Overlay Mode", Float) = 0
        [Space(20)]
        [Vector] _DetailUV("Detail UV Tiling", Vector) = (1,1,0,0)
        [IntRange] _StencilRef("Stencil Reference", Range(0, 255)) = 0
        
        // ========== 6. 自定义编辑器属性 ==========
        [HideInInspector] _QueueOffset("Queue offset", Float) = 0.0
    }
}

URP Shader和内置渲染管线Shader不同的是一个采用CG一个采用HSLS语言。其中关于Properties有一些默认的属性名

Unity 在 ShaderLab + 材质系统里写死的一套【命名约定驱动机制】。

Unity Shader"黑魔法级别的约定系统"**。

你看到的并不是"巧合关联",而是 Unity 在 ShaderLab + 材质系统里写死的一套【命名约定驱动机制】

我按底层逻辑 → 具体到你这四个变量,一步一步给你讲清楚。


一、先给结论(非常重要)

这几个变量之间"能自动关联",不是因为 Shader 写了什么逻辑,
而是因为 Unity 引擎在 C++ 层对"特定名字"做了硬编码识别。

也就是说:

  • ❌ 不是 HLSL 特性
  • ❌ 不是 Properties 的能力
  • ❌ 不是 URP 的机制
  • ✅ 是 Unity 材质系统的"命名协议(Convention)"

二、_BumpMap 和 _BumpScale 的关系是怎么来的?

hlsl 复制代码
// 法线贴图
_BumpMap ("Normal Map", 2D) = "bump" {}
_BumpScale ("Normal Scale", Float) = 1.0

1️⃣ 核心点:Unity"认识" _BumpMap

在 Unity 引擎内部(C++):

_BumpMap"标准法线贴图槽位名"

一旦你在 Properties 里声明:

hlsl 复制代码
_BumpMap ("Normal Map", 2D)

Unity 会自动:

  • 把这个贴图当作 法线贴图

  • 在材质 Inspector 中:

    • 显示为 Normal Map
    • 启用 Normal Map 的导入校验
    • 自动提示 "Fix Now"

📌 这一切都不是 Shader 代码做的


2️⃣ 那 _BumpScale 为什么能"跟着它"?

这是第二条硬编码规则:

当 Unity 看到 _BumpMap
并且同时存在 _BumpScale
它就认为:这是"法线强度"

所以在 Inspector 里你会看到:

  • 法线贴图槽
  • 一个 Normal Scale 滑条

📌 注意重点:

Shader 并不知道 _BumpScale 是干嘛的

Shader 只知道:这是一个 float

是否"关联",完全是 Inspector UI 逻辑


3️⃣ Shader 里发生了什么?

Shader 里你必须自己用它:

hlsl 复制代码
float4 normalTS = UnpackNormalScale(
    SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, uv),
    _BumpScale
);

👉 不写这行,_BumpScale 一点用都没有


三、_MainTex 和 _MainTex_ST 的关系(这是更典型的)

hlsl 复制代码
_MainTex ("Texture", 2D) = "white" {}
_MainTex_ST ("Texture Tiling/Offset", Vector) = (1,1,0,0)

这个关系更底层、更硬


1️⃣ _MainTex 是"主纹理"的保留名

Unity 内部规定:

_MainTex = 主纹理(Base Map / Albedo)

所以它会:

  • 在材质 Inspector 中作为主贴图
  • 被很多系统默认引用(UI、粒子、SRP)

2️⃣ _MainTex_ST 是 Unity 自动生成 / 识别的变量

ST 是什么?

text 复制代码
ST = Scale + Translation

即:

hlsl 复制代码
xy → Tiling
zw → Offset

3️⃣ 为什么"必须显式声明"?

因为 URP + SRP Batcher 下,Unity 不再偷偷帮你声明

Built-in 管线 时代:

hlsl 复制代码
_MainTex_ST

👉 Unity 会在背后自动塞进来

但在 URP / SRP

你不写,Shader 里就没有

所以你必须:

hlsl 复制代码
CBUFFER_START(UnityPerMaterial)
    float4 _MainTex_ST;
CBUFFER_END

4️⃣ Unity 是怎么把它们"绑定在一起"的?

这条规则是:

如果存在 _XXX_ST,并且存在 _XXX 的 Texture 属性,
Unity 会自动:

  • 在 Inspector 里显示 Tiling / Offset
  • 在修改 UI 时,写入 _XXX_ST

📌 依然是:C++ 层硬编码规则


四、这不是"魔法",是"协议"

你现在要形成一个非常重要的认知:

Unity Shader 中很多"自动行为",
不是语言能力,而是命名协议。


五、Unity 中最重要的"隐式命名协议表"(送你)

名字 含义
_MainTex 主纹理
_MainTex_ST 主纹理 Tiling / Offset
_BaseMap URP 主纹理
_BaseMap_ST URP 主纹理 ST
_BumpMap 法线贴图
_BumpScale 法线强度
_MetallicGlossMap 金属度
_OcclusionMap AO
_EmissionMap 自发光
_EmissionColor 自发光颜色

📌 命名对 = 自动 UI + 自动流程

📌 命名错 = 一切手动


六、一个"反例",帮你彻底想通

如果你写:

hlsl 复制代码
_MyNormal ("Normal", 2D) = "bump" {}
_MyNormalScale ("Scale", Float) = 1

结果是:

  • ❌ 不会显示为 Normal Map
  • ❌ 不会自动 Fix
  • ❌ 不会自动绑定 Scale
  • Shader 里一切都要你自己管

👉 因为 Unity 不认识这些名字


七、为什么 Unity 要这样设计?

原因很现实:

  1. 保证 美术工作流统一
  2. 兼容 旧 Shader / 老项目
  3. Inspector 不需要理解 Shader 代码
  4. SRP / Built-in / UI 共用一套规则

这份表来自 URP 源码 + ShaderLibrary + 实际 Inspector 行为总结,你可以放心用。

说明

  • 版本背景:URP(Unity 2021+ / 团结 1.67 适用)
  • 这是 "命名即行为" 的协议
  • 不按这个命名 → Inspector / 管线不会帮你做任何事

一、【最重要】主贴图 / 基础颜色(Base Map)

名称 类型 作用
_BaseMap 2D URP 主贴图(等价于旧 _MainTex
_BaseMap_ST Vector Tiling (xy) + Offset (zw)
_BaseColor Color 主颜色 / Albedo Tint

说明

  • URP Lit / SimpleLit 只认 _BaseMap
  • _MainTex 在 URP 中 不是推荐命名

二、法线贴图(Normal Map)

名称 类型 作用
_BumpMap 2D 法线贴图
_BumpScale Float 法线强度

引擎行为

  • Inspector 显示为 Normal Map
  • 自动提示 Fix Normal Map
  • _BumpScale 自动显示为滑条

三、金属 / 光滑度(Metallic / Smoothness)

名称 类型 作用
_MetallicGlossMap 2D 金属度贴图
_Metallic Range/Float 金属度常量
_Smoothness Range/Float 光滑度
_GlossMapScale Float Smoothness 强度

说明

  • Metallic / Smoothness 通常共用一张图

  • Smoothness 默认来自:

    • A 通道(URP 约定)

四、遮蔽(Ambient Occlusion)

名称 类型 作用
_OcclusionMap 2D AO 贴图
_OcclusionStrength Range AO 强度

五、自发光(Emission)

名称 类型 作用
_EmissionMap 2D 自发光贴图
_EmissionColor Color 自发光颜色

引擎行为

  • 启用 Emission 后:

    • 自动写入 GI
    • 影响光照贴图

六、透明 / 裁剪(Alpha)

名称 类型 作用
_Cutoff Range Alpha Clip 阈值
_Surface Float 0=Opaque / 1=Transparent
_Blend Float 混合模式

注意

  • _CutoffAlphaTest 的硬协议名
  • 用错名字 = Clip 不生效

七、细节贴图(Detail)

名称 类型 作用
_DetailMap 2D 细节贴图
_DetailAlbedoScale Float 细节颜色强度
_DetailNormalMap 2D 细节法线
_DetailNormalScale Float 细节法线强度

八、阴影 / 接收控制(Shadow)

名称 类型 作用
_ReceiveShadows Float 是否接收阴影
_ShadowStrength Float 阴影强度

九、URP 内部 / 管线控制(高级)

⚠️ 这些一般不手写,但你必须认识

名称 作用
_TimeParameters 时间参数
_ProjectionParams 投影相关
_ScreenParams 屏幕尺寸
_ZBufferParams 深度反算

十、ST(Scale + Offset)命名规则(非常重要)

通用规则(你一定要记)

任何 Texture:
只要名字是 _XXX
对应的 Tiling/Offset 必须叫:_XXX_ST

例如:

hlsl 复制代码
_BaseMap     → _BaseMap_ST
_BumpMap     → _BumpMap_ST
_OcclusionMap → _OcclusionMap_ST

否则:

  • Inspector 不显示 Tiling/Offset
  • SRP Batcher 不识别
  • Shader 里采样错位

十一、哪些"看似对,但其实是坑"的命名?

❌ 不推荐:

hlsl 复制代码
_MainTex        // URP 不推荐,保留字
_MainColor
_NormalMap
_NormalScale

👉 Inspector 不帮你做任何事


十二、SRP Batcher / Instancing 特别注意

SRP Batcher

hlsl 复制代码
CBUFFER_START(UnityPerMaterial)
    float4 _BaseColor;
    float4 _BaseMap_ST;
CBUFFER_END
  • 顺序不能乱
  • 不能跨 Shader 不一致

GPU Instancing / GRD

hlsl 复制代码
UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)

⚠️ 不要和 CBUFFER 同名混用


复制代码
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl"

这个会自动引入一些已经默认定义好的名字变量属性,如,BaseMap等,如果继续冲重复加入到CBUFFER_START(UnityPerMaterial),则会提示重复。

所有的属性都需要写进去CBUFFER_START(UnityPerMaterial),除了Texture2D / Sampler,因为他们不走CBUFFER

相关推荐
mxwin6 小时前
Unity Shader 半透明物体为什么不能写入深度缓冲?
unity·游戏引擎·shader
晚枫歌F7 小时前
三层时间轮的实现
网络·unity·游戏引擎
咸鱼永不翻身9 小时前
Lua脚本事件检查工具
unity·lua·工具
leo__52010 小时前
单载波中继系统资源分配算法MATLAB仿真程序
算法·matlab·unity
努力长头发的程序猿12 小时前
Unity使用ScriptableObject序列化资源
unity·游戏引擎
mxwin12 小时前
Unity Shader 手写基于 PBR 的 URP Lit Shader 核心光照计算
unity·游戏引擎·shader
小贺儿开发12 小时前
Unity3D 智能云端数字标牌系统
unity·阿里云·人机交互·视频·oss·广告·互动
魔士于安12 小时前
Unity windows 同步 异步 打开文件文件夹工具
游戏·unity·游戏引擎·贴图·模型
魔士于安13 小时前
unity lowpoly 风格 城市 建筑 道路 交通标志
游戏·unity·游戏引擎·贴图·模型
mxwin13 小时前
Unity GPU Shader 性能优化指南
unity·游戏引擎·shader