- 用户指南
- 资源商店 (Asset Store)
- 资源服务器 (Asset Server)(仅限团队许可证)
- 缓存服务器(仅限团队许可证)
- 幕后场景
- 创建游戏
- 运行时实例化预设 (Prefabs)
- 变换 (Transforms)
- 物理
- 添加随机的游戏元素
- 粒子系统(Particle Systems)
- Mecanim 动画系统
- 旧动画系统
- 导航网格 (Navmesh) 和寻路 (Pathfinding)(仅限专业版 (Pro))
- Sound (音频侦听器)
- 游戏界面元素
- 多玩家联网游戏
- iOS 开发入门
- Android 开发入门
- Blackberry 10 开发入门
- Metro:入门指南
- 本地客户端开发入门
- FAQ
- Advanced
- Vector Cookbook
- 资源包(仅限专业版)
- Graphics Features
- 资源数据库 (AssetDatabase)
- 构建播放器管道
- 分析器(仅限专业版)
- 光照贴图快速入门
- 遮挡剔除(仅限专业版)
- 相机使用技巧
- 运行时加载资源
- 通过脚本修改源资源
- 用程序生成网格几何体
- 富文本
- 在 Unity 工程 (Project) 中使用 Mono DLL
- 事件函数的执行顺序
- 移动优化实用指南
- Unity XCode 工程结构
- 优化图形性能
- 减少文件大小
- 理解自动内存管理
- 平台依赖编译
- 泛型函数
- 调试
- 插件(专业版/移动版特有功能)
- 文本场景文件格式(仅限专业版)
- 流媒体资源
- 启动时运行编辑器脚本代码
- 网络模拟
- VisualStudio C 集成
- 分析
- 检查更新
- 安装多版本 Unity
- 故障排除
- Unity 中的阴影
- Unity 中的 IME
- 对集成显卡进行优化
- 网络播放器 (Web Player) 部署
- 使用网络播放器中的信任链系统
着色器:顶点和片段程序
此教程将介绍如何在 Unity 着色器中编写自定义顶点和片段程序。有关 ShaderLab 的简介,请参阅入门教程。如需编写与照明交互的着色器,则需了解表面着色器 (Surface Shaders)。
让我们一起回顾一下着色器的一般结构:
Shader "MyShaderName" { Properties { // ... properties here ... } SubShader { // ... subshader for graphics hardware A ... Pass { // ... pass commands ... } // ... more passes if needed ... } SubShader { // ... subshader for graphics hardware B ... } // ... Optional fallback ... FallBack "VertexLit" }
这里的结尾处介绍了一个新命令: FallBack "VertexLit"
您可在着色器结尾处使用 Fallback 命令;它指出当用户图形硬件上没有运行当前着色器中的任何子着色器 (SubShaders) 时,应该使用哪种着色器。其效果与备用着色器在末尾处添加所有子着色器 (SubShaders) 的效果相同。例如,如果您要撰写法线贴图着色器,则只需回退至内置顶点光照 (VertexLit) 着色器,无需为旧图形卡编写非常简单的非法线贴图着色器。
第一个着色器教程 中介绍着色器的基本构建块, 同时提供 完整的属性 (Properties)、子着色器 (SubShaders) 和通道 (Passes) 文档。
使用其他着色器中定义的通道可快速构建子着色器。命令 UsePass 可执行上述操作,因此,您可以巧妙地重复使用着色器代码。例如,以下命令使用内置高光 (Specular) 着色器中名为 "BASE" 的通道: UsePass "Specular/BASE"
要使 UsePass 有效运行,则必须为需要使用的通道命名。通道中的 Name 命令为其命名: Name "MyPassName"
顶点和片段程序
我们在第一个教程中介绍了一个只使用单个纹理合成的通道。现在,我们将介绍如何使用通道中的顶点和片段程序。
使用顶点和片段程序(所谓的“可编程管道”)时,程序将关闭图形硬件中的大部分硬编码功能(“固定功能管道”)。例如,使用顶点程序完全关闭标准三维转换、照明和纹理坐标生成功能。同样地,使用片段程序替换本应在 SetTexture 命令中定义的任何纹理合成模式;因而无需使用 SetTexture 命令。
编写顶点/片段程序需要对三维转换、照明和坐标空间有全面了解 – 因为您必须像处理 OpenGL 一样重写内置到 API 的固定功能。另外,还可实现更多内置以外的功能!
在 ShaderLab 中使用 Cg
通常,我们通过在着色器文本中插入“Cg 片段”,以使用 Cg 编程语言在 ShaderLab 中编写着色器。Unity 编辑器将 Cg 片段编译至低级别的着色器程序集中,添加至游戏数据文件的最终着色器仅包含此低级别程序集。在工程视图 (Project View) 中选择着色器时,检视器 (Inspector) 在编译 Cg 后显示着色器文本,这可能有助于调试。Unity 自动编译 Direct3D、OpenGL 和 Flash 等平台的 Cg 片段,因此您的着色器可在所有平台上运行。注意,由于 Cg 代码由编辑器编译,无法在运行时使用脚本创建 Cg 着色器。
通常,Cg 片段位于通道 (Pass) 块中。示例如下:
Pass { // ... the usual pass state setup ...
CGPROGRAM // compilation directives for this snippet, e.g.: #pragma vertex vert #pragma fragment frag
// the Cg code itself
ENDCG // ... the rest of pass setup ...
}
以下示例介绍含 Cg 程序(将对象法线渲染为彩色)的完整着色器:
Shader "Tutorial/Display Normals" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos :SV_POSITION; float3 color :COLOR0; }; v2f vert (appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.color = v.normal * 0.5 + 0.5; return o; } half4 frag (v2f i) :COLOR { return half4 (i.color, 1); } ENDCG } } Fallback "VertexLit" }
应用到对象时,将看到与下图类似的效果(当然是在图形卡支持顶点和片段程序的前提条件下):
“显示法线”着色器不含任何属性,只包含一个子着色器 (SubShader),其单一通道 (Pass) 只有 Cg 代码。最终确定内置顶点光照 (VertexLit) 着色器为备用着色器。让我们逐个部分分析 Cg 代码:
CGPROGRAM #pragma vertex vert #pragma fragment frag // ... snip ... ENDCG
整个 Cg 片段位于 CGPROGRAM 和 ENDCG 关键字之间。开头的编译指令由 #pragma 语句给出:
- #pragma vertex name 说明给定函数的顶点程序包含的代码(此处为 vert)。
- #pragma fragment name 说明给定函数的片段程序包含的代码(此处为 frag)。
编译指令后面是普通的 Cg 代码。首先,我们需要导入一个 内置 Cg 文件:
- include UnityCg.cginc
UnityCg.cginc 文件包含常用声明和函数,从而令着色器保持简短(有关详细信息,请参阅着色器导入文件页面)。在这里,我们将使用该文件中的 appdata_base 结构。当然,可以不导入此文件,直接在着色器中定义这些内容。
接下来,定义一个“顶点至片段”结构(此处为 v2f)- 从顶点传递至片段程序的信息。我们传递位置和颜色参数。顶点程序计算出颜色并只在片段程序中输出。
然后定义顶点程序 - vert 函数。在这里计算位置并用一种颜色输出输入法线: o.color = v.normal * 0.5 + 0.5;
法线组件位于 -1..1 范围之间,但颜色位于 0..1 范围之间,所以我们微调并微移上述代码中的法线。接下来,定义一个片段程序 – 只输出计算的颜色和 1 作为 alpha 组件的 frag 函数:
half4 frag (v2f i) :COLOR
{
return half4 (i.color, 1);
}
就是这样,着色器分析到此为止!即使这个着色器很简单,但这对可视化网格法线非常有用。
当然,此着色器根本不能响应光照。这让事情变得越来越有趣了;有关更多信息,请参阅表面着色器 (Surface Shaders)。
在 Cg 代码中使用着色器属性
在着色器中定义属性时,将其命名为 _Color 或 _MainTex。要在 Cg 中使用这些属性,只需定义一个与名称和类型相符的变量。Unity 将自动设置其名称与着色器属性相符的 Cg 变量。
以下是一个其纹理由颜色调整过的完整着色器。当然,您可以在纹理合成调用中执行上述操作,但这里旨在说明如何在 Cg 运用属性:
Shader "Tutorial/Textured Colored" { Properties { _Color ("Main Color", Color) = (1,1,1,0.5) _MainTex ("Texture", 2D) = "white" { } } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" float4 _Color; sampler2D _MainTex; struct v2f { float4 pos :SV_POSITION; float2 uv :TEXCOORD0; }; float4 _MainTex_ST; v2f vert (appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX (v.texcoord, _MainTex); return o; } half4 frag (v2f i) :COLOR { half4 texcol = tex2D (_MainTex, i.uv); return texcol * _Color; } ENDCG } } Fallback "VertexLit" }
此着色器的结构与上一示例的结构相同。在这里,我们定义了两个属性,即 _Color 和 _MainTex 我们在 Cg 代码中定义相应变量:
float4 _Color; sampler2D _MainTex;
有关更多信息,请参阅在 Cg 中访问着色器属性。
此处的顶点和片段程序未制作出任何特殊效果;顶点程序使用 UnityCG.cginc 中的 TRANSFORM_TEX 宏确保纹理缩放和偏移得到正确应用,而片段程序只是对纹理采样,然后乘以颜色属性。
注意,我们正在编写自己的片段程序,因而无需使用任何 SetTexture 命令。着色器应用纹理的方式完全取决于片段程序。
总结
我们已介绍了如何通过几个简单的步骤生成自定义着色器程序。虽然这里列出的示例都非常简单,但这完全不阻碍您轻松撰写出复杂的着色器程序!这还有助于您充分利用 Unity 的优势,实现最理想的渲染效果。
此处有完整的 ShaderLab 组件手册。我们还在 forum.unity3d.com 建立了一个着色器论坛,还等什么,立即为你的着色器寻求帮助吧!祝您编程愉快,畅享强大的 Unity 和 Shaderlab 带给您的无限乐趣。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论