一、什么是Unity Shader?

本文详细介绍了UnityShader的概念、与材质的关系,以及RenderQueue的作用。重点讲解了ShaderLab语言中的Properties和SubShader,包括它们在Unity中的应用和示例。此外,还涵盖了不同类型的Shader和光照模型。
摘要由CSDN通过智能技术生成
原址:一、什么是Unity Shader? - 知乎

作者:changyun


目录

原址:1 什么是Unity Shader?

2 Unity Shader和材质的关系?

3 什么是RenderQueue?

4 什么是ShaderLab语言?

4.1 Properties语义块

4.2 SubShader语义块

5 小结

6 本章参考文献


1 什么是Unity Shader?

Unity Shader是由UnityLab语言编写的一段计算机程序,用来定义渲染管线在不同阶段的处理流程,本质上是一段文本文件。编写完成后,需要进行编译,将其转换成GPU可以执行的机器指令。Unity提供了四种不同的Shader模板:Standard Surface Shader、Unlit Shader、Image Effect Shader和Compute Shader。这些模板为开发者提供了一些预设的基础代码和着色算法。具体来说,
(1) Standard Surface Shader是一种基于表面属性的着色算法,而不是基于像素的着色算法。表面属性就是材质属性,如颜色、纹理、透明度、反射率等。Standard Surface Shader可以自动的基于表面属性实现光照计算。Standard Surface Shader支持多种光照模型,如Lambert、Phong、Blinn-Phong、Cook-Torrance、Oren-Nayar、Minnaert、Fresnel等。如果需要改变光照模型,需要打开Surface Standard Shader文件,修改代码

#pragma surface surf Phong

即可将光照模型改成Phong光照模型。
(2) Unlit Shader是一种不考虑场景中光照影响的着色算法。
(3) Image Effect Shader定义了屏幕后处理特效的Unity Shader,它在图像渲染完成后,将渲染结果作为输入,进行一系列的处理,例如模糊、色彩调整、镜头畸变,最终输出加入特效后的图像。
(4) Compute Shader是一种GPU的并行性来进行一些与渲染流水线无关计算的编程模型。为大规模的数据处理提供了强有力的支持。使用Compute Shader需要掌握多线程编程能力。

2 Unity Shader和材质的关系?

在Unity中,材质是一种用于描述物体表面外观的数据结构,其中包含了颜色、纹理、透明度等属性信息。材质在被赋予给游戏对象之后,可以被Mesh Renderer组件所使用,Mesh Renderer会将材质属性数据传递给Unity Shader程序进行处理。因此,材质与Unity Shader共同构成了实现高质量渲染的必要组成部分。通过精心设计和调整材质和Shader,可以使游戏对象在渲染时呈现出更加真实、细腻、吸引人的视觉效果。

3 什么是RenderQueue?

每个材质都具有RenderQueue属性,用于定义材质在渲染管线中的渲染顺序,RenderQueue值越小优先级越高。具有相同RenderQueue值的材质物体会根据其在场景中的顺序进行依次渲染。在Unity中,常见的RenderQueue值设置如下:
1. Geometry(默认值为 1000):该RenderQueue值用于渲染几何体,例如立方体、球体等等。如果您的场景中只包含几何体,则无需对RenderQueue进行修改。
2. AlphaTest(默认值为 2000):该RenderQueue值用于渲染使用Alpha Test的材质,例如一些使用半透明纹理的材质。
3. Transparent(默认值为 3000):该RenderQueue值用于渲染半透明的材质,例如玻璃、水等物体。
4. Overlay(默认值为 4000):该RenderQueue值用于渲染覆盖在其他物体之上的材质,例如UI元素。
5. Background(默认值为 100):该RenderQueue值用于渲染场景的背景,例如天空盒等。

4 什么是ShaderLab语言?

ShaderLab是Unity提供的编写Unity Shader的一种说明性语言,它使用一个个语义块来描述Unity Shader。Unity会在平台背后将Unity Shader的这些结构编译成真正的代码和shader文件,而开发者只需要和Unity Shader打交道即可。一个Unity Shader的基础结构如下所示:

Shader "ShaderName"{
   Properties{
      // 显示在材质面板中的属性
      _Name ("Display Name", PropertyType)=DefaultType
   }
   SubShader{
      // 显卡A使用的子着色器
   }
   SubShader{
      // 显卡B使用的子着色器
   }
   Fallback "OtherShaderName"
}

4.1 Properties语义块

Properties语义块的作用仅仅是为了让里面定义的属性可以出现在材质面板中。因此,即使没有在Properties语义块中定义的属性也可以在代码块中定义。Properties语义块支持的属性类型见表1所示。

表1 Properties语义块支持的属性类型

属性类型默认值定义语法例子
Intnumber_MyInt("DisplayInt",Int)=2
Floatnumber_MyFloat("DisplayFloat",Float)=1.5
Range(min,max)number_Range("Range",Range(0.0,5.0))=3.0
Color(number,number,number,number)_Color("Color",Color)=(1,1,1,1)
Vector(number,number,number,number)_Vector("Vector",Vector)=(2,3,4,1)
2D"defaulttexture"{}_2D("2D",2D)=""{}
Cube"defaulttexture"{}_Cube("Cube",Cube)="white"{}
3D"defaulttexture"{}_3D("3D",3D)="black"{}

4.2 SubShader语义块

每一个Unity Shader都至少包含一个SubShader语义块,Unity会默认选择第一个能在当前平台上运行的SubShader语义块执行,如果都不支持运行则会使用Fallback语义块指定的Unity Shader。Unity提供这种语义块的原因在于不同显卡处理能力不同,我们希望在较低性能的显卡上执行简单的渲染任务,而在高级显卡上使用计算复杂度更高的着色器。SubShader语义块中包含的定义通常如下:

SubShader{
   // 当前上下文环境中所有pass的标签设置
   Tags{"TagName1"="Value1" "TagName2"="Value2"}
   // 当前上下文环境中所有pass的状态设置
   StateName Value // 比如 Cull Back
   pass{
      Name "MyPassName1"
      [Tags]
      [RenderSetup]
      // other code
   }
   // other passes
}

其中,SubShader中支持的Tags标签类型如表2所示。

表2 标签类型

标签类型说明例子
Queue控制渲染顺序,指定该物体属于哪一个渲染队列。Tags{"Queue"="Transparent"}
RenderType用来指定shader的渲染类型,不同的渲染类型会有不同的处理过程,常见的渲染类型包括Opaque(不透明)、Transparent(透明)、Overlay(覆盖层)、Background(背景)等。Tags{"RenderType"="Opaque"}
DisableBatching一些SubShader在进行批处理时会出现问题。Tags{"DisableBatching"="True"}
ForceNoShadowCasting如果该SubShader中pass被设置成前向渲染,那么就会在正常的渲染流水线之前增加一个Shadow Caster Pass阶段,该阶段会会生成ShadowMap也就是深度贴图,通过ForceNoShadowCasting标签可以强制取消Shadow Caster Pass阶段,从而不产生阴影。Tags{"ForceNoShadowCasting"="True"}
IgnoreProjector设置是否该Shader会忽视投射器的影响。Tags{"IgnoreProjector"="True"}
CanUseSpriteAtlas当该SubShader是用于精灵时,该标签设置为True。Tags{"CanUseSpriteAtlas"="True"}
PreviewType指定材质面板将如何预览该材质。默认情况下,材质将显示为一个球形,可以通过改变该标签为"Plane"或"SkyBox"来改变预览类型。Tags{"PreviewType"="Plane"}

Pass语义块中支持的标签类型如表3所示。

表3 Pass语义块支持的标签类型

标签类型说明例子
LightMode在Unity Shader中有多种渲染路径,如前向渲染、延迟渲染、ShadowMap渲染等。LightMode就是用来指定某个Pass的渲染路径的,通常包括:
(1) ForwardBase:前向渲染,只采用最主要的光源(平行光)执行最基础的光照计算,如漫反射、高光反射。
(2) ForwardAdd:前向渲染,将场景中所有光源(平行光、点光源、聚光灯等)都参与光照计算,然后进行融合。
(3) Deferred:延迟渲染,包括两个pass,首先第一个pass用于将通过深度测试的片元存储到G-Buffer中。第二个pass根据G-Buffer进行光照计算。
(4) ShadowCaster:该渲染路径用于生成ShadowMap,将相机放到光源位置投射来产生一个深度贴图(ShadowMap)。
Tags{"LightMode"="ForwardBase"}
RequireOptions用于指定当满足某些条件时才渲染该Pass。Tags{"RequireOptions"="SoftVegetation"}

5 小结

目前为止,本文详细解释了什么是Unity Shader以及Unity Shader中语义标签格式的粗略介绍。不同类型的Unity Shader其SubShader语义块的内容略有不同,只需要重点关注表面着色器和顶点/片元着色器即可。其中表面着色器是Unity特有的,Unity在背后做了很多工作,它和顶点/片元着色器在本质上是一样的,即Unity会自动将表面着色器转换成顶点/片元着色器。一个简单的表面着色器代码如下:

Shader "Custom/Simple Surface Shader"{
   SubShader{
      Tags{"RenderType"="Opaque"}
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input{
         float4 color:COLOR;
      }
      void surf(Input IN, inout SurfaceOutput o){
         o.Albedo = 1;
      }
      ENDCG
   }
   Fallback "Diffuse"
}

表面着色器程序被直接定义在SubShader语义块内,Unity会在内部自动将其转换为对应的Pass语义块,我们只需要定义好光照模型,Unity就会自动在背后执行光照计算。

而顶点/片元着色器想要执行光照计算则只能自己编码实现了,一个简单的顶点/片元着色器的代码如下所示。

Shader "Custom/Simple VertexFragment Shader"{
   SubShader{
      Pass{
         CGPROGRAM
         #pragma vertex vert //定义顶点着色器函数名为vert
         #pragma fragment frag //定义片元着色器函数名为frag
         float4 vert(float4 v:POSITION) : SV_POSITION{
            return mul(UNITY_MATRIX_MVP, v);
         }
         fixed4 frag() : SV_Target {
            return fixed4(1.0, 0.0, 0.0, 1.0);
         }
         ENDCG
      }
   }
}

6 本章参考文献

[1] 冯乐乐. Unity Shader 入门精要[M]. 人民邮电出版社, 2016.

[2] 编写着色器 - Unity 手册 (unity3d.com)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值