0%

[unity shader] 1.概述

1. 概述#

1.1 shader种类#

shader主要有:固定管线着色器,顶点片元着色器,表面着色器

  • 固定管线着色器(逐渐淘汰)
  • 顶点shader:干预模型形态的shader(顶点变换)
  • 像素shader:干预像素着色的shader(不同纹理贴图)

1.2 GPU编程语言#

  1. Dirext3D-----微软(windows)
  2. OpenGL-----Linux(Android)

目前面向GPU的编程有三种高级图像语言:HLSL语言,GLSL语言,Cg语言

  1. HLSL语言:High Level Shading Language,由Microsoft公司提供,通过Direct3D图形软件库来编写的着色器语言。

  2. GLSL语言:OpenGL Shading Language,由OpenGL安委会提供,在OpenGL中进行着色器编程的语言。

  3. Cg语言:C for Graphics,由NVIDIA公司和Microsoft公司合作提供,有自己的一套关键字和函数库,独立于三维编程接口,在Direct3D和OpenGL上都可工作

2. shader lab基础语法#

2.1 ShaderLab简介#

ShaderLab: Unity 自己又封装了一层CG/HLSL/GLSL的接口,但为了实现跨平台,Unity重点支持Cg着色器语言

1
2
3
4
5
6
7
8

Shader "主色器名称"{
Properties{} //属性定义
SubShader{} //子主色器
SubShader{} //子主色器2
…………
FallBack "备用着色器名称" //如果所有子着色器不能运行,则使用备用着色器
}

简单的shader示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// colored vertex lighting
Shader "Simple colored lighting"
{
// a single color property
Properties {
_Color ("Main Color", Color) = (1,.5,.5,1)
}
// define one subshader
SubShader
{
// a single pass in our subshader
Pass
{
// use fixed function per-vertex lighting
Material
{
Diffuse [_Color]
}
Lighting On
}
}
}
Shader "name"{ }定义了一个名字为“name”的shader。

2.1.1 properties属性定义#

用来定义主色器中使用的贴图资源或者数值参数等。这些属性会在inspector视图的材质界面中显示,可以方便的进行设置和修改。

2.1.2 SubShader属性定义#

一个着色器包含一个或者多个子着色器。当Unity使用着色器渲染的时,会从上到下遍历子着色器,找到第一个被用户设备支持的子着色器,并使用该子着色器进行渲染。如果没有子着色器可以使用,则使用备用着色器

2.1.3 Fallback属性定义#

备用着色器一般会指定一个对硬件要求最低的shader。当所有子着色器不能运行的时候,unity会启用备用着色器来进行渲染。

2.2 Properties属性#

properties一般定义在着色器的起始部分,我们可以在Shader书写的时候定义多种多样的属性,而使用Shader的时候可以直接在材质检视面板(Material Inspector)里编辑这些属性,取不同的值或者纹理。这可以说是Unity贴心&可见即所得的又一体现吧。

定义了一些属性参数,可在Unity编辑器的“Inspector”面板中编辑和调整。

1
2
3
4
5
6
_Name("Display Name", type) = defaultValue[{options}]


Properties {
_Color是变量名 ("Main Color"是在“Inspector”中的名字, Color是变量类型) = (1,.5,.5,1)是默认值          
}

2.2.1 Properties 类型#

类型|说明 -:-|-:- Range(min,max)| 在(min,max)范围内的浮点数 Float |浮点数 Int |整型 Color |颜色 RGBA Vector |四维向量 2D |2D纹理 3D |3D纹理 Cube |立方体贴图纹理 Rect |矩形纹理

  • **_Name** 属性的名字,简单说就是变量名,在之后整个Shader代码中将使用这个名字来获取该属性的内容。Unity中用下划线开始_Name
  • Display Name - 这个字符串将显示在Unity的材质编辑器中作为Shader的使用者可读的内容
  • type - 这个属性的类型,可能的type所表示的内容有以下几种:
    • Color - 一种颜色,由RGBA(红绿蓝和透明度)四个量来定义;
    • 2D - 一张2的阶数大小(256,512之类)的贴图。这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终被显示出来;
    • Rect - 一个非2阶数大小的贴图;
    • Cube - 即Cube map texture(立方体纹理),简单说就是6张有联系的2D贴图的组合,主要用来做反射效果(比如天空盒和动态反射),也会被转换为对应点的采样;
    • Range(min, max) - 一个介于最小值和最大值之间的浮点数,一般用来当作调整Shader某些特性的参数(比如透明度渲染的截止值可以是从0至1的值等);
    • Float - 任意一个浮点数;
    • Vector - 一个四维数;
  • defaultValue 定义了这个属性的默认值,通过输入一个符合格式的默认值来指定对应属性的初始值(某些效果可能需要某些特定的参数值来达到需要的效果,虽然这些值可以在之后在进行调整,但是如果默认就指定为想要的值的话就省去了一个个调整的时间,方便很多)。
    • Color - 以0~1定义的rgba颜色,比如(1,1,1,1);
    • 2D/Rect/Cube - 对于贴图来说,默认值可以为一个代表默认tint颜色的字符串,可以是空字符串或者”white”,”black”,”gray”,”bump”中的一个
    • Float,Range - 某个指定的浮点数
    • Vector - 一个4维数,写为 (x,y,z,w)
  • 另外还有一个{option},它只对2D,Rect或者Cube贴图有关,在写输入时我们最少要在贴图之后写一对什么都不含的空白的{},当我们需要打开特定选项时可以把其写在这对花括号内。如果需要同时打开多个选项,可以使用空白分隔。可能的选择有ObjectLinear, EyeLinear, SphereMap, CubeReflect, CubeNormal中的一个,这些都是OpenGL中TexGen的模式,

2.3 SubShader#

2.3.1 定义语法#

1
2
3
4
Subshader { 
[Tags]
[CommonState]
Passdef [Passdef ...] }

2.3.2 标签(Tags)#

1
2
3
4
//写在SubShader的第一句
Tags { "TagName1" = "Value1" "TagName2" = "Value2" }
//比如
Tags { "RenderType"="Opaque" }

作用#

SubShaders使用标签来告诉引擎如何以及何时将其渲染。

Unity识别的以下标记必须在SubShader节内,而不是Pass!

  1. “Queue”标签。定义渲染顺序-队列标签。预制的值为 (1)”Background”。值为1000。比如用于天空盒。 (2)”Geometry”。值为2000。大部分物体在这个队列。不透明的物体也在这里。这个队列内部的物体的渲染顺序会有进一步的优化(应该是从近到远,early-z test可以剔除不需经过FS处理的片元)。其他队列的物体都是按空间位置的从远到近进行渲染。 (3)”AlphaTest”。值为2450。已进行AlphaTest的物体在这个队列。 (4)”Transparent”。值为3000。透明物体。 (5)”Overlay”。值为4000。比如镜头光晕。 (6)用户可以定义任意值,比如”Queue”=”Geometry+10”
  2. “RenderType”标签。Unity可以运行时替换符合特定RenderType的所有ShaderCamera.RenderWithShader或者Camera.SetReplacementShader配合使用。Unity内置的RenderType包括: (1)”Opaque”:绝大部分不透明的物体都使用这个; (2)”Transparent”:绝大部分透明的物体、包括粒子特效都使用这个; (3)”Background”:天空盒都使用这个; (4)”Overlay”:GUI、镜头光晕都使用这个; (5)还有其他可参考Rendering with Replaced Shaders;用户也可以定义任意自己的RenderType字符串。
  3. ”ForceNoShadowCasting”,值为”true”时,表示不接受阴影
  4. ”IgnoreProjector”,值为”true”时,表示不接受Projector组件的投影

2.3.3 Pass(通道:插入到渲染流水线)的定义语法#

subshader包装了一个渲染方案,这些方案由一个个通道(pass)来执行的,subshader可以包含很多通道块,每个Pass都能使几何体渲染一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Pass{
[Name and Tags名称和标签]
[Render Setup 渲染设置]
[Texture setup 纹理设置]
}

//实例代码
Shader "Custom/Shader_01" {
SubShader {
Pass{
Name "ONE"
Material{
Diffuse(1,0.7,0.4,1)
Ambient(1,0.7,0.4,1)
}
Lighting On
SetTexture[_]{ combine primary }

}
}
}

2.3.4 pass名称和标签(Name and tags)#

可以定义Pass的名字以及任意数量的标签。为Pass命名后,可以在别的着色器中通过Pass名称来引用它,减少重复操作。Name命名必须大写

2.3.5 pass渲染设置(Render Setup)#

pass里可以设置图形硬件的各种状态,例如开启Alpha混合,开启雾效等。

RegularPass渲染设置#

命令 |说明 -:-|-:- Meterial{} |材质,定义一个使用顶点光照管线的材质 Lighting |光照,设置光照,取值为off或on Cull |裁剪,设置裁剪模式,模式包括:back、Front、off ZTest |深度测试,设置深度测试,包括:Less、Greater、LEqual、GEqual、Equal、NotEqual、Always。 ZWrite |深度缓存写入,设置深度缓存写入的开关,取值为Off或On Fog{} |雾效,设置雾效参数 AlphaTest |Alpha测试,设置Alpha测试,包括:Less、Greater、LEqual、GEqual、Equal、NotEqual、Always。 Blend |Alpha混合,设置Alpha混合模式 Stencil| 蒙版,用蒙版来实现像素的取舍操作,选项有:keep、Zero、Replace、Incrsat、DecrSat、Invert、Incrwrap和DecrWrap Color |颜色,是指顶点光照关闭时使用的颜色值 ColorMask |颜色遮罩,设置颜色遮罩,当值为0时关闭所有的颜色通道的渲染,取值为RGB offset |深度偏移,设置深度偏移 SeparateSpecular |高光颜色。开启或关闭顶点光照的独立高光颜色,取值为On或Off ColorMaterial |颜色集,当计算顶点光照时使用每个顶点的颜色。

特殊通道#

  1. UsePass 命令 使用 来自另一个着色器的命名通道

    1
    **UsePass "Shader/Name"**
    插入所有来自给定着色器中的给定名字的通道。Shader/Name包含了通过斜杠字符分割的着色器的名字和通道的名字 某些着色器重用其他着色器中已存在的通道,减少重复的代码。例如,在许多像素光照着色器中,阴影色或顶点光照通道在在相应的顶点光照着色器中是相同的。UsePass命令只是包含了另一个着色器的给定通道。例如当如下的命令可以使用内置的高光着色器中的名叫"Base"的通道:
    1
    UsePass "Specular/BASE"
    为了让UsePass能正常工作,必须给希望使用的通道命名。通道中的Name命令将提供这个名字:
    1
    Name "MyPassName"
    注意,所有通道名字都是大写开头,因此UsePass必须使用大写开头的名字来书写索引

  2. GrabPass是一种特殊的通道类型 - 捕获物体所在位置的屏幕的内容并写入到一个纹理中。这个纹理能被用于后续的通道中完成一些高级图像特效。 有两种方式将GrabPass放入一个 subshader中:

  • GrabPass {} 能捕获当前屏幕的内容到一个纹理中。纹理能在后续通道中通过 _GrabTexture 进行访问。注意:这种形式的捕获通道将在每一个使用该通道的对象渲染过程中执行昂贵的屏幕捕获操作
  • GrabPass { "TextureName" } 能捕获屏幕内容到一个纹理中,但只会在每帧中处理第一个使用给定纹理名的纹理的对象的渲染过程中产生捕获操作。纹理在未来的通道中可以通过给定的纹理名访问。当你在一个场景中拥有多个使用GrabPass的对象时将提高性能。

GrabPass能使用Name 和 Tags命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Shader "GrabPassInvert" {
SubShader {
// Draw ourselves after all opaque geometry
// 在所有不透明几何体之后自画
Tags { "Queue" = "Transparent" }

// Grab the screen behind the object into _GrabTexture
// 捕获对象后的屏幕到_GrabTexture
GrabPass { }

// Render the object with the texture generated above, and invert it's colors
// 用前面捕获的纹理渲染对象,并反相它的颜色
Pass {
SetTexture [_GrabTexture] { combine one-texture }
}
}
}

2.3.6 pass纹理设置(Texture Setup)#

纹理设置语法:setTexture 纹理属性{[命令选项} 纹理设置用于固定功能管线,如果使用表面着色器或者自定义的顶点或者片段着色器,那么纹理设置将会被忽略。 setTexture的命令选项包括三种: 1. Conbine:将两个颜色源混合,混合源可以是previous(上一次setTexture的结果)、constant(常量颜色值)、primary(顶点颜色)和texture(纹理颜色中的一种) 2. ConstantColor设置一个颜色常量 3. matrix:设置矩阵对纹理坐标进行变换

2.4 Fallback备用着色器#

语法:#

1
2
(1)Fallback “备用着色器名称”
(2)Fallback off

2.5 unity内置Surface shader关照效果计算的性能开销排序#

  1. Unlit:仅适用纹理颜色,不受光照影响
  2. VertexLit:顶点光照
  3. Diffuse:漫反射
  4. Specular:在满反射的基础上增加了高光计算
  5. Normal Mapped:法线贴图,增加了一张法线贴图和几个着色器指令
  6. Normal Mapped Specular:带高光的法线贴图
  7. Parallax Normal Mapped:视差法线贴图,增加了视察贴图的计算开销。
  8. Parallax Normal Mapped Specular:带高光的视差法线贴图