Unity Shader基础

Unity Shader基础

本文章的学习内容来源全部出自《UnityShader入门精要》——冯乐乐

该文章只是本人我的学习笔记,里面对《UnityShader入门精要》进行了些许概括且加了自己的些许理解

如果想更加具体地了解其内容,建议购买原著进行学习

Unity Shader与Render Pipeline以及Material三者之间的关系:

  • 每一个Shader都是为特定渲染管线所编写的运行在GPU上的可执行脚本程序!
  • 每种材质创建时都必须指明其具体渲染管线下的具体着色器类型。因此就有“没有材质就无法渲染模型”的说法!
  • Shader的动态效果是由使用该Shader的材质来体现,而材质的动态效果则由使用该材质的模型体现!

Unity Shader概述

Unity Shader本质上就是一个后缀名为.shader的文本文件。

Unity Shader ! =真正的 Shader

Unity 里 Unity Shader 实际上指的是 ShaderLab文件——硬盘上以 .shader 作为文件后缀的文件!

Unity Shader的优缺点:

优点:

  • 在传统的 Shader 中,我们仅可以编写特定类型的 Shader, 例如顶点着色器、片元着色器等。而在 Unity Shader 中,我们可以在同一个文件里同时包含需要的顶点着色器和片元着色器代码即Unity Shader 提供了一种让开发者同时控制渲染流水线中多个阶段(例如几何阶段的顶点着色器和光栅化阶段的片元着色器)的方式,不仅仅是提供 Shader 代码。
  • 在传统的 Shader 中,我们无法设置一些渲染设置,例如是否开启混合、深度测试等,这
    些是开发者在另外的代码中自行设置的。而在 Unity Shader 中,我们通过 行特定的指令
    就可以完成这些设置。
  • 在传统的 Shader 中,我们需要编写冗长的代码来设置着色器的输入和输出,要小心地处理这些输入输出的位置对应关系等。而在 Unity Shader 中,我们只需要在特定语句块中—Properties语义块中声明一些属性,就可以依靠材质来方便地改变这些属性。而且对于模型自带的数据(如顶点位置、纹理坐标、法线等), Unity Shader 也提供了直接访问的方法,不需要开发者自行编码来传给着色器。

缺点:

  • 对于一些类型的 Shader, 例如曲面细分着色器(Tessellation Shader) 、几何着色器 (Geometry Shader) 等, Unity 的支持就相对差一些!

在Unity中查看创建的各种类型着色器:

表面着色器的查看
顶点/片元着色器的查看
在该导入设置面板上,我们可以在Default Maps中指定该Unity Shader使用的默认纹理。 在下方包含该Shader的其他信息,例如它是否是一个表面着色器(Surface Shader)、是否是 一个固定函数着色器(Fixed Function Shader)等, 还有一 些信息是和我们在Unity Shader中的标签设置有关, 例如是否会投射阴影、使用的渲染队列、LOD值等。

对于表面着色器文件来说, 我们可以通过单击Show generated code按钮打开 Unity在背后为该表面着色器生成的顶点/片元着色器代码结构的文件。这可以 方便我们对这些生成的代码进行修改(需要复制到一个新的Unity Shader中才可保存)和研究。
如果固定函数着色器文件,在Fixed function的后面也会出现一个Show generated code按钮,来让我们查看该固定函数着色器生成的顶点/片元着色器代码结构文件
Compile and show code下拉列表可以让开发者检查该Unity Shader针对不同图像编程接口(例如OpenGL、D3D9 D3Dll等)最终编译成的Shader代码。

Unity Shader的语言:ShaderLab

在Unity中,所有的 Unity Shader 都是使用ShaderLab语言来编写其结构!

Unity 在背后会根据使用的平台来把这些结构编译成真正的代码和 Shader 文件,而开发者只需要和 Unity Shader 打交道即可!

Shader "ShaderName " { 
	Properties {
		       } 
	SubShader { //显卡A使用的子若色器
		      } 
	SubShader { //显卡B使用的子着色器
		  	  } 
	Fallback "VertexLit"
	}

Unity Shader文件的基本结构:

1. Unity Shader的路径名:

Shader "Custom/MyShader " { }

在这里插入图片描述

2. Properties语义块:

作用:

用于声明使用该Unity Shader的材质在材质面板上所显示的属性!即该Unity Shader在材质面板上的输入输出的出入口,为了在材质面板中能够方便地调整Unity Shader(材质)的各种属性!

格式:
Properties { 
	Name ("display name" , PropertyType) = DefaultValue 
	Name ("display name", PropertyType) = DefaultValue 
}
解释:
  • 每个属性名 (Name) 通常由下划线开始。
  • 自定义显示名(display name) 则是出现在材质面板上的名名称。
  • 我们需要为每个属性指定它的属性类型 (Property Type)。
常见的属性名和属性类型:

在这里插入图片描述

有关自定义着色器实现添加纹理的基本功能:
Shader "myshaders/myshader1"
{
    Properties
    {
        //shader的属性名与对应类型
        _MainTex ("主纹理", 2D) = "white" {}
        _RectTex("Rect纹理",Rect) = ""{}
        _CubeTex("Cube纹理",Cube) = ""{}//与天空盒的纹理有关
        _Int("整型",Int)=1
        _Float("浮点数",Float)=1.5
        _Range("范围",Range(0,1))=0.5
        _Vector("齐次坐标",Vector)=(0,0,0,0)
        _Color("颜色",Color)=(1,0,0,1)
    }
    SubShader
    {
        pass {
                    SetTexture[_MainTex]
                    {
                            Combine texture
                    }
                }
    }
}

为了在 shader 中可以访问到这些属性,我们需要在 CG 代码片中定义和这些属性类型相匹配的变量。需要说明的是,即使我们不在Properties语义块中声明这些属性,也可以直接在 CG 代码片中定义这些变量 。此时,我们可以通过脚本向 Shader 中传递这些属性 。因此 Properties 语义块的作用仅仅是为了让这些声明的属性可以出现在材质面板上。

3. SubShader语义块:

作用:

为了兼容不同处理能力的显卡,通过定义多个SubShader结构为各种显卡提供相应的可运行的方案!

结构:
SubShader { 
	[Tags] //可选的
	[RenderSetup]//可选的
	Pass { 
	}
// Other Passes
}
解释:
  • 多个SubShader只运行一个!

每一个Unity Shader文件可以包含多个SubShader语义块,但最少要有一个。 当Unity需要加载这个Unity Shader时,Unity会扫描所有SubShader语义块, 然后选择第一个能够在目标平台上运行的SubShader。 如果都不支持的话, Unity就会使用Fallback语义块中指定的Unity Shader(例如Diffusion)。

  • pass通道

SubShader中定义了 一系列Pass通道以及可选的状态([RenderSetup])和标签([Tags])设置。

每个Pass通道定义了一次操作, 但如果Pass的数目过多, 往往会造成渲染性能的下降。 因此, 我们应尽量使用最小数目的Pass。

  • 标签与状态设置

状态和标签同样可以在Pass声明。 不同的是,SubShader中的一些标签设置是特定的。 也就是说, 这些标签设置和Pass中使用的标签是不一样的。 而对于状态设置来说,其使用的语法是相同的。 但是, 如果我们在SubShader进行了这些设置, 那么将会用于所有的Pass。


SubShader的状态设置和标签设置与pass语义块
3.1 状态设置

ShaderLab提供了一 系列设置显卡的各种状态的指令, 例如是否开启混合/深度测试等。
在这里插入图片描述


3.2 标签设置

SubShader的标签(Tags)是一个键值对(Key/Value Pair), 它的键和值都是字符串类型。 这些键值对是SubShader和渲染引擎之间的沟通桥梁。 它们用来告诉Unity的渲染引擎: 我希望怎样以及何时渲染这个对象

Tags { " TagNamel " = "Valuel " "TagName2" = "Value2 " }

以下标签仅可以在 SubShader块中声明 ,而不可以在 Pass 块中声明。
在这里插入图片描述

3.3 pass语义块

在这里插入图片描述
Pass块中同样可以设置标签,但它的标签不同于SubShader块中的标签。这些标签也是用于告诉渲染引擎我们希望怎样来渲染该物休。

常见的pass块中标签:
在这里插入图片描述

4. FallBack指令

作用:

用于告诉 Unity, "如果上面所有的SubShader块在这显卡上都不能运行,那么就使用FallBack所指定的最低级的 Shader 吧!”

ShaderLab还有其他的语义吗?

除了上述的语义,还有一些不常用到的语义。例如,如果我们不满足于 Unity 内置的属性类型,想要自定义材质面板的编辑界面,就可以使用 CustomEditor 语义来扩展编辑界面 。我们还可以使用 Category 语义来对 Unity Shader 中的命令进行分组 。由千这些命令很少用到,本书将不再进行深入的讲解。

Unity Shader的类型:

Unity Shader最重要的任务是指定各种着色器所需的代码。这些着色器代码可以写在SubShader语义块中(表面着色器的做法) ,也可以写在pass语义块中(顶点/片元着色器和固定函数着色器的做法)。而不管使用哪种形式 真正意义上的 Shader 代码都需要包含在ShaderLab语义块中,如下所示:

Shader "MyShader" { 
	Properties { 
	//所需的各种属性
	}
	SubShader { 
		//真正意义上的 Shader 代码会出现在这里
		//表面着色器 (Surface Shader) 或者
		//顶点/片元着色器 (Vertex/Fragment Shader) 或者
		//固定函数着色器 (Fixed Function Shader) 
		}
	SubShader { 
		//和上—个 SubShader 类似
		}
}

1. Unity 的宠儿:表面着色器

Surface Shader是Unity 自己创造的一种着色器代码类型。
当给 Unity 提供一个表面着色器的时候,它在背后仍旧把它转换成对
应的顶点/片元着色器。
在这里插入图片描述

2. 顶点/片元着色器

在这里插入图片描述

3. 被抛弃的角落:固定函数着色器

表面着色器和顶点/片元着色器都使用了可编程渲染管线。而对于一些较旧 的设备 (其 GPU 仅支持DirectX 7.0 OpenGL 1.5 OpenGL ES 1. 1), 例如 iPhone 3, 它们不支持可编程渲染管线的着色器,因此,这时候我们就需要使用固定函数着色器 (Fixed Function Shader) 来完成渲染。

选择哪种 Unity Shader 形式?

建议:
• 除非你有非常明确的需求必须要使用固定函数着色器,例如需要在非常旧的设备上运行你的游戏(这些设备非常少见),否则请使用可编程管线的着色器,即表面着色器或顶点/片元着色器。
• 如果你想和各种光源打交道,你可能更喜欢使用表面着色器 ,但需要小心它在移动平台的性能表现。
• 如果你需要使用的光照数目非常少,例如只有 个平行光,那么使用顶点/片元着色器是个更好的选择。
• 最重要的是,如果你有很多自定义的渲染效果,那么请选择顶点/片元着色器

Unity Shader 与CG/HLSL 之间的关系

正如我们之前所讲, Unity Shader 是用 ShaderLab 语言编写的,但对于表面着色器和顶点/片
元着色器,我们可以在 ShaderLab 内部嵌套 CG/HLSL 言来编写这些着色器代码。这些 CG/HLSL
代码是嵌套在 CGPROGRAM ENDCG 之间的,正如我们之前看到的示例代码 样。由于 CG DX9 风格的 HLSL 从写法上来说几乎是同 种语言,因此在 Unity CG HLSL 是等价的。我们可以说, CG/HLSL 代码是区别于 ShaderLab 的另 个世界。

Unity 编辑器会把这些 CG 片段编译成低级语言,如汇编语言等。通常, Unity 会自动把这些 CG 片段编译到所有相关平台 (这里的平台是指不同的渲染平台,例如 Direct3D OpenGL Direct3D 11 OpenGLES 等)上 。这些编译过程比较复杂 Unity会使用不同的编译器来把 CG 转换成对应平台的代码 。这样就不会在切换平台时再重新编译 ,而且如果代码在某些平台上发生错误就可以立刻得到错误信息。
在Unity Shader的导入设置面板中可以通过Compile and show code按钮查看Unity对CG片段编译后的代码。通过单击Compile and show code按钮右端的倒三角可以打开下拉菜单,在这个下拉菜单中可以选择编译的平台种类,如只为当前的显卡设备编译特定的汇编代码, 或为所有的平台编译汇编代码, 我们也可以自定义选择编译到哪些平台上。通过查看这些编译后的代码, 有助于进行Debug或优化等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值