Unity Shader学习笔记(三) 基础知识(语义、属性等)详解

在Unity5.2及以上版本中,Unity一共提供了4中UnityShader模板供我们选择,分别是:UnlitShader、SurfaceShader、ImageEffectShader、ComputeShader。

SurfaceShader:会产生一个包含了标准光照模型的表面着色器模板,代码如下:

Shader "Custom/SurfaceShader" {

Properties {

_Color ("Color", Color) = (1,1,1,1)

_MainTex ("Albedo (RGB)", 2D) = "white" {}

_Glossiness ("Smoothness", Range(0,1)) = 0.5

_Metallic ("Metallic", Range(0,1)) = 0.0

}

SubShader {

Tags { "RenderType"="Opaque" }

LOD 200

CGPROGRAM

// Physically based Standard lighting model, and enable shadows on all light types

#pragma surface surf Standard fullforwardshadows

// Use shader model 3.0 target, to get nicer looking lighting

#pragma target 3.0

sampler2D _MainTex;

struct Input {

float2 uv_MainTex;

};

half _Glossiness;

half _Metallic;

fixed4 _Color;

void surf (Input IN, inout SurfaceOutputStandard o) {

// Albedo comes from a texture tinted by color

fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;

o.Albedo = c.rgb;

// Metallic and smoothness come from slider variables

o.Metallic = _Metallic;

o.Smoothness = _Glossiness;

o.Alpha = c.a;

}

ENDCG

}

FallBack "Diffuse"

}

Unlit Shader 会产生一个不包含光照(但包含雾效)的基本顶点/片元着色器,代码如下:

Shader "Unlit/UnlitShader"

{

Properties

{

_MainTex ("Texture", 2D) = "white" {}

}

SubShader

{

Tags { "RenderType"="Opaque" }

LOD 100

Pass

{

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

// make fog work

#pragma multi_compile_fog

#include "UnityCG.cginc"

struct appdata

{

float4 vertex : POSITION;

float2 uv : TEXCOORD0;

};

struct v2f

{

float2 uv : TEXCOORD0;

UNITY_FOG_COORDS(1)

float4 vertex : SV_POSITION;

};

sampler2D _MainTex;

float4 _MainTex_ST;

v2f vert (appdata v)

{

v2f o;

o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);

o.uv = TRANSFORM_TEX(v.uv, _MainTex);

UNITY_TRANSFER_FOG(o,o.vertex);

return o;

}

fixed4 frag (v2f i) : SV_Target

{

// sample the texture

fixed4 col = tex2D(_MainTex, i.uv);

// apply fog

UNITY_APPLY_FOG(i.fogCoord, col);

return col;

}

ENDCG

}

}

}

Image Effect Shader 则为我们实现各种屏幕后处理效果提供了一个模板,代码如下:

Shader "Hidden/ImageEffectShader"

{

Properties

{

_MainTex ("Texture", 2D) = "white" {}

}

SubShader

{

// No culling or depth

Cull Off ZWrite Off ZTest Always

Pass

{

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

#include "UnityCG.cginc"

struct appdata

{

float4 vertex : POSITION;

float2 uv : TEXCOORD0;

};

struct v2f

{

float2 uv : TEXCOORD0;

float4 vertex : SV_POSITION;

};

v2f vert (appdata v)

{

v2f o;

o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);

o.uv = v.uv;

return o;

}

sampler2D _MainTex;

fixed4 frag (v2f i) : SV_Target

{

fixed4 col = tex2D(_MainTex, i.uv);

// just invert the colors

col = 1 - col;

return col;

}

ENDCG

}

}

}

Compute Shader会产生一张特殊的Shader文件,这类Shader旨在利用GPU的并行性来进行一些与常规渲染流水线无关的计算,

与正常着色器类似,Compute着色器是项目中的资源文件,具有* .compute文件扩展名。 它们是用DirectX 11风格的HLSL语言编写的,用最少量的#pragma编译指令来指示哪些函数要编译为计算着色器内核。

// Each #kernel tells which function to compile; you can have many kernels

#pragma kernel CSMain

// Create a RenderTexture with enableRandomWrite flag and set it

// with cs.SetTexture

RWTexture2D Result;

[numthreads(8,8,1)]

void CSMain (uint3 id : SV_DispatchThreadID)

{

// TODO: insert actual code here!

Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);

}

单独的Shader无法发挥任何作用,它必须和材质结合起来,才能产生化学反应。Unity Shader本质上也是一个文本文件,也有ImportSetting面板,如图:

单击Show generated code 按钮来打开一个新文件,在该文件里将显示Unity在背后为该表面着色器生产的顶点/片元着色器、这可以方便我们对这些生成的代码进行修改

如图UnityShader是一个固定函数着色器,在FixedFunction的后面也会出现一个ShowGeneratedCode按钮,来让我们查看该固定函数着色器生成的顶点/片元着色器。

CompileAndShowCode 下拉列表可以让开发者检测该UnityShader针对不同图像编程(例如OpenGL、D3D9、D3D11等)最终编译成Shader代码直接单击按钮可以查看生成的底层的汇编指令。我们可以利用这些代码来分析和优化着色器。

Unityshader 中的Properties语义块中包含了一系列属性,这些属性将会出现在材质面板上,Properties语义块支持的属性类型,如下:

下面给出一个展示所有属性类型的例子:

Shader "Custom/ShaderProperties" {

Properties {

_Int("Int",Int)=2

_Float("Float",Float) = 1.5

_Range("Range",Range(0.0,10.0)) = 3.0

_Color ("Color", Color) = (1,1,1,1)

_Vector("Vector",Vector) = (2,3,6,1)

_2D("2D",2D) = ""{}

_Cube("Cube",Cube) = "while"{}

_3D("3D",3D) = "black"{}

}

FallBack "Diffuse"

}

对于Int、Float、Range这些数字类型的属性,其默认值就是一个单独的数字;

对于Color、Vector这类属性,默认值是用圆括号包围的一个四维向量;

对于2D、Cube、3D这种纹理类型,默认值是通过一个字符串后跟一个花括号来指定,其中。字符串要么是空的,要么是内置的纹理名称,如“white”,“black”,“gray”,“bump”

显示结果如图:

每一个shader中可以包含多个SubShader语义块,但最少要有一个。但不是每一个都能用的到,这个可以根据不同的平台编写不同的SubShader,在使用的时候Unity会扫描所有的SubShader语义块,然后选择第一个能够在目标平台上运行的SubShader。如果所有的都不支持,那么Unity会使用FallBack语义指定的UnityShader,SubShade语义如下:

SubShader

{

//可选的

[Tags]

//可选的

[RenderSetup]

Pass

{

}

}

SubShader

{

}

FallBack "Diffuse"

SubShader中定义了一系列Pass,以及可选的状态[RenderSetup]和标签[Tags]设置。每一个Pass定义了一个一次完整的渲染流程,但如果Pass数目过多,就会造成渲染性能的下降,因此,我们应尽量使用最小数目的Pass。

状态和标签同样可以在Pass板块中声明,只不过,在SubShader中设置,会作用于所有的Pass,但是在Pass中设置,只会作用于本Pass板块

常见的渲染状态设置选项,如下图:

SubShader中的标签(Tags)是一个键值对,它的键和值都是字符串类型;

标签的结构如下:

Tags{"Tagname1" = "Value1" "TagName2" = "Value2"}

标签类型如下图:

Pass语义块:

Pass

{

[Name]

[Tags]

[RenderSetup]

//other Code

}

我们可以在Pass 中定义该Pass的名称。如:Name "MyPassName",通过这个名称,我们可以使用ShaderLab的UsePass命令来直接使用其他UnityShader中的Pass ,如:UsePass"MyShader/MYPASSNAME",这样就可以提高代码的复用性。但是注意:

由于Unity内部会把所有的Pass的名称转换成大写字母来表示,因此,在使用UsePass命令时必须使用大写字母

Pass中同样可以设置标签,但它的标签不同于SubShader的标签,这些标签也是用于告诉渲染引擎我们希望怎样来渲染该物体,如下

好了,这一章就写到这,欢迎大家加入QQ群:280993838  或者关注我的公众号:

推荐阅读更多精彩内容