1.4:SubShader
文章著作权归作者所有。转载请联系作者,并在文中注明出处,给出原文链接。
本系列原更新于作者的github博客,这里给出链接。
在了解了渲染流水线之后,我们可以开始SubShader的学习了。
什么是SubShader
我们在1.1节中提到:
SubShader:SubShader是Shader代码的核心部分。由于运行终端的不同,其所能支持的渲染等级也是不同的,所以我们在必要时可以编写多个SubShader,Unity会为我们从上到下寻找并使用终端所能支持的第一个SubShader。在SubShader中,可以设置细节层级,渲染方式等,也可以插入Cg/HLSL代码块,这也是Shader核心中的核心。
顾名思义,SubShader是整个着色器的一个子着色器,当一个Mesh(网格)需要被绘制时,Unity就会在Shader中寻找渲染它的方式,并从Shader中挑选第一个能被完全支持的SubShader去实现。为了让材质,或者说让游戏画面能够在不同平台发挥其最佳的效果,我们可以定义多个SubShader。每一个SubShader都包含完整的渲染参数,渲染设置,渲染方法等。在初学阶段,我们为材质编写一个SubShader即可,剩下的工作我们可以交给强大的FallBack去完成。
SubShader包含了什么
下面是SubShader的语法:
Subshader { [Tags][CommonState] Passdef [Passdef ...] }
一个SubShader包含了渲染标签Tags,一些共同的渲染声明CommonState,以及一或多个Pass,每个SubShader至少包含一个Pass,其他都是可选参数。下面给出一个例子:
SubShader {
Tags {
"Queue" = "Transparent"
"RenderType" = "Transparent"
"IgnoreProjector" = "True"
}
Pass {
// ...
}
}
Tags
标签提供了整个SubShader的渲染设置基准,比如使用哪一个渲染队列,使用哪一种渲染类型。在之后的学习中我们会逐渐学习这些标签,这些标签的含义在官方文档中也可以查阅了解。标签是一个键值对。下面给出几个最常用的标签以及他们各自的常用可选值。
Tag Name | Optional Values |
---|---|
Queue | Background / Geometry / AlphaTest / Transparent / Overlay |
RenderType | Opaque / Transparent / Background / Overlay |
IgnoreProjector | True / False |
DisableBatching | True / False / LODFading |
PreviewType | Plane / Sphere / Skybox |
Queue:设置物体的渲染队列。Unity内使用渲染队列来标识物体的渲染层级顺序,这个顺序可以无视物体原本的渲染顺序。渲染队列是一个数值,上面五种预设对应值为1000,2000,2450,3000,4000 。渲染顺序是按值从小到大,我们也可以细分这些值,更精细地控制渲染顺序,如:Tags { "Queue" = "Geometry + 1" }
。
RenderType:设置物体的渲染类型。这个标签主要是用于区分着色器的渲染类型,以供后处理使用。
IgnoreProjector:默认值是False,当设置为True时,这个渲染命令将不受其他物体投射的阴影的影响。
DisableBatching:Unity会默认将同类型的渲染命令合批处理,这会导致单个物体的模型空间数据丢失,在模型空间上所作的操作也就会失效,这时我们可以将这个标签设为True。默认值是False,设置为True时取消对这个物体的批处理,保留模型空间的信息,而LODFading则是常用于树等需要设置LOD的材质。
PreviewType:设置物体预览时的默认Mesh。
CommonState
在Unity文档中我没有找到关于CommonState的相关说明,个人倾向于理解成注释或者说明文档。
Pass
Pass是shader的核心部分。每一个Pass对应一次Draw Call,对于一个可用的SubShader,其中的每一个声明了的Pass都会被按次序调用(也可以通过后处理指定Pass的调用)。通俗一点的理解就是,每个Pass对应着一次图像的绘制,而Shader的最终结果就是多个Pass叠加的结果。
Pass的种类
Pass的声明一般有3种:Regular Pass,Use Pass,Grab Pass。
Regular Pass
Regular Pass是最常规也是使用最多的一种Pass,下面给出一个例子:
Pass {
Tags {
"LightMode" = "ForwardBase"
}
Cull Front
ZTest Always
ZWrite Off
// Blend Off
// ...
}
官方给出的Regular Pass的格式如下:
Pass { [Name] [Tags] [RenderSetup] }
可以看到,Pass的内容都是可选的。
Name
可以通过Name "PassName"
给出这个Pass的名称,这个名称可以标识这个Pass以备后续重用。需要注意的是,Pass名称包含的小写字母会被转换成大写字母。
Tags
Pass也有自己的标签设置,Pass的标签表明这个Pass在渲染管线是怎样的role(官方文档用词)(它可能是ambient,vertex lit,pixel lit等等),标签的顺序不影响作用。下面给出Pass的专属标签以及对应的常用值,详细的内容可以参考官方文档。
Tag Name | Optional Value |
---|---|
LightMode | Always / ForwardBase / ForwardAdd / ShadowCaster |
PassFlags | OnlyDirectional |
RequireOptions | SoftVegetation |
LightMode是最常见的设置,用于设置Pass在渲染管线中的role,一般用于表面着色器,让Unity为我们处理光照、阴影等细节。各可选值的含义如下:
Always
:总是被渲染,不使用光照。
ForwardBase
:使用Forward Rendering(前向渲染,Unity内置的渲染管线),会为我们准备好环境光,主平行光,顶点光,SH(Spherical Harmonics) Lights(球谐函数计算的光照)和光照贴图。
ForwardAdd
:使用前向渲染,会为我们准备好所有的逐像素光,每一个逐像素光都会调用一次这个Pass。
Defered
:使用Deferred Shading(延迟渲染),用于渲染g-buffer(g缓冲),而不是输出到屏幕。
ShadowCaster
:把物体的深度信息渲染到阴影贴图或者深度纹理。
Tags的格式于Subshader的格式一致。
RenderSetup
RenderSetup是一系列对GPU渲染管线的配置,具体包含以下设置:
Legacy fixed-function Shader commands:这是Unity固定函数着色器使用的配置,不作展开。
Cull
:Cull命令设置管线中的剔除操作,可选值有Back / Front / Off 。默认是Back,即剔除背面。Front即剔除正面,Off 不剔除任何片元。正面、背面是相对于视角而言的,基于视线向量和片元法向量的点积结果。正面剔除常用于法线外扩实现描边特效等。
ZTest
:设置深度测试的比较模式,可选值有Less / Greater / LEqual / GEqual / Equal / NotEqual / Always。Always让该片元总是可以通过深度测试,即关闭深度测试,其他可选值按字面意思理解即可。
ZWrite
:设置深度写入的开关。默认为On,当ZWrite值为Off 时,这个片元的深度值不会被写入深度缓冲区。
Blend
:设置这个片元在颜色缓冲区的写入模式,默认值为Off,即不混合,通过所有测试就直接覆盖颜色,否则舍弃片元。Blend有两种常用的声明方式:
// Src是片元信息,Dst是颜色缓冲的信息,Result是混合结果
// 混合公式为 ResultRGBA = SrcColorRGBA * SrcFactor + DstColorRGBA * DstFactor
Blend SrcFactor DstFactor
// 混合公式为 ResultRGB = SrcColorRGB * SrcFactor + DstColorRGB * DstFactor
// ResultA = SrcColorA * SrcFactorA + DstColorA * DstFactorA
Blend SrcFactor DstFactor, SrcFactorA DstFactorA
Blend的Factor也是一些可选值:
Factor | Value |
---|---|
One | 1 |
Zero | 0 |
SrcColor | 源颜色值 |
SrcAlpha | 源Alpha值 |
DstColo | 缓冲区颜色值 |
DstAlpha | 缓冲区Alpha值 |
OneMinusSrcColor | 1 - 源颜色值 |
OneMinusSrcAlpha | 1 - 源Alpha值 |
OneMinusDstColor | 1 - 缓冲区颜色值 |
OneMinusDstAlpha | 1 - 缓冲区Alpha值 |
通过参数的组合,我们可以实现几种常见的混合模式:
Blend SrcAlpha OneMinusSrcAlpha // 正常的透明效果
Blend One OneMinusSrcAlpha // 预乘的透明效果
Blend One One // 叠加模式
Blend OneMinusDstColor One // 柔和叠加
Blend DstColor Zero // 乘法
Blend DstColor SrcColor // 二次乘法
在Regular Pass的最后,可以插入代码块,进行GPU编程。
UsePass
UsePass
命令可以插入一个已经存在且命名了的Pass。
// 使用自己定义的Pass
UsePass "Shader/Name"
// 使用Unity的内置Pass
UsePass "VertexLit/SHADOWCASTER"
GrabPass
GrabPass
是一个特殊的Pass,它会获取屏幕的内容,并把其储存在一张纹理中,这个纹理可以用于后续的Pass。
GrabPass { } // 这种获取方式会把纹理储存在一个叫_GrabTexture的临时纹理中
// 每一个调用它的物体都会实时抓取一次屏幕
GrabPass { "TextureName" } // 这种获取方式只会在每一帧的第一个物体获取时抓取一次
// 并将抓取的内容储存在给定名称的纹理中
1.4:SubShader的更多相关文章
- Unity3d之Shader编程:子着色器、通道与标签的写法 & 纹理混合
一.子着色器 Unity中的每一个着色器都包含一个subshader的列表,当Unity需要显示一个网格时,它能发现使用的着色器,并提取第一个能运行在当前用户的显示卡上的子着色器. 我们知道,子着色器 ...
- 1.1:Get Started with Unity Shaders
文章著作权归作者所有.转载请联系作者,并在文中注明出处,给出原文链接. 本系列原更新于作者的github博客,这里给出链接. 第1章开始正式进入Unity Shader的学习. 什么是Shader 本 ...
- 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1117/120.html 作者:毛星云 ...
- 初次学习shader
Shader "Custom/Diffuse Texture" { //在shader中的位置 Properties { //着色器的属性 _MainTex ("Base ...
- Shader的语法
Shader "name" { [Properties] Subshaders [Fallback] }(1)Properties:{ Property [Property ... ...
- Unity3D ShaderLab 各向异性高光
Unity3D ShaderLab 各向异性高光 各向异性时一种模拟物体表面沟槽方向性的高光反射类型,它会修改或延伸垂直方向上的高光.当我们想模拟金属拉丝高光的时候,它非常适合.下面就一步一步实现. ...
- Unity3D ShaderLab 使用BlinnPhong高光类型
Unity3D shaderLab 使用BlinnPhong高光类型 上一篇我们实现了自定义高光类型,这一篇,我们说Blinn高光,它是另一种计算和估算高光更高效的方式,它是通过视线防线和光线方向,所 ...
- Unity3d Shader
Unity3d Shader 预览Surface Shader主要用来实现光照相关处理,可能更简洁. Vertex and Fragment Shader 如果不与光照交互, 则可以用这个shader ...
- Unity3D中的Shader
简单的说,Shader是为渲染管线中的特定处理阶段提供算法的一段代码.Shader是伴随着可编程渲染管线出现的,从而可以对渲染过程加以控制. 1. Unity提供了很多内建的Shader,这些可以从官 ...
随机推荐
- mysql 查询 练习题及答案
CREATE DATABASE school;USE school;/*1.创建student表格*//*id为主键 非空 唯一 */CREATE TABLE student (id INT(10) ...
- 一码阻塞,万码等待:ASP.NET Core 同步方法调用异步方法“死锁”的真相
在我们 2015 年开始的从 .NET Framework 向 .NET Core 迁移的工程中,遇到的最大的坑就是标题中所说的--同步方法中调用异步方法发生"死锁".虽然在 .N ...
- 与前端(使用vue框架)对接的问题
1.跨域问题 跨域问题是: 浏览器的同源安全策略 没错,就是这家伙干的,浏览器只允许请求当前域的资源,而对其他域的资源表示不信任.那怎么才算跨域呢? 请求协议http,https的不同 域domain ...
- SecureCRT连接linux步骤
SecureCRT连接linux步骤 做个笔记,以免隔段时间后忘了 LINUX系统一般都是用来作服务器使用,而且都是通过命令行来操作,为了操作方便我们都会使用第三方软件来远程操作.CRT就是比较常用 ...
- cadence16.6 暴力破解出现再次安装出现问题为Sever-----------问题
根据本人,实测,本人研究几天和在网络上借鉴,此方法是几天的成果,如有借鉴,请说明出处,谢谢,不懂的请留言. 最优解决方式,是自己卸载软件,有人会说,都完全删除了还怎么卸载软件. (1)在安装包里有个注 ...
- NAT(Network Address Translation)
一.概述 NAT英文全称是“Network Address Translation”,中文意思是“网络地址转换”,它是一个IETF(Internet Engineering Task Force, I ...
- pc端字体大小自适应几种方法
$(window).resize(function ()// 绑定到窗口的这个事件中 { var whdef = 100/1920;// 表示1920的设计图,使用100PX的默认值 var wH ...
- fastJson解析报错:com.alibaba.fastjson.JSONException: can't create non-static inner class instance.
原因: 如果出现类嵌套类的情况,需要将被嵌套的那个类设置为static. 比如: public class AA { // 相关属性 public class BB {//会报错 // 相关属性 } ...
- supervise守护进程
通过二进制supervise文件可以直接对进程进行守护 ./supervise -f 要守护的程序 -p 守护信息存储位置 例如: ./supervise -f http_server -p s ...
- Cache Aside Pattern
Cache Aside Pattern 即旁路缓存是缓存方案的经验实践,这个实践又分读实践,写实践 对于读请求 先读cache,再读db 如果,cache hit,则直接返回数据 如果,cache m ...