开始学习unity也有一个多月了,之前就想把学习的东西总结一下,记录下来方便自己以后查阅,可是工作太忙总是忘记了这个事情,最近 终于有时间了,打算把每天学的东西记录下来。写这个文章的原因有两点:1.很多想法都是在学的时候可能会想到,但是过一段时间又忘记了。2.以前都是翻看别人的博文,然后突然找不到别人的博客了,然后有些内容重新找起来感觉很麻烦,那就干脆把自己的想法记录下来,方便自己以后查阅。
shader是unity里面比较重要的一个东西,将shader和纹理(texture)一起输出打包会得到一个材质(material),将材质赋予给某个对象,某个对象上就能看到我们想要的效果。
新建一个shader文件,选择standard surface shader,
双击打开文件,可以看到里面的内容:
Shader "Custom/NewSurfaceShader" {
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"
}
文件中代码的最外层框架是
Shader“”{}
其实“”引号内可以输入任何内容,输入的内容就是你自定义的shader名字,该名称和文件名称没有任何关系,名称可以用/分割,如果使用了/分割,那么/前面的内容就是文件的上级目录,这个可以用来分类管理。
花括号里面的内容:分为Properties ,SubShader和FallBack三大块
Properties{}
这个模块里面定义的shader的属性,所有用到的都是声明在这个模块里面,并且声明的变量可以在Inspector面板里面看到。Shader的属性类型以及属性的定义方式一共有如下几种:
属性定义结构
属性名 (属性面板上显示的名称,属性类型) 默认值
属性类型
Color 颜色
_Color ("Color", Color) = (1,1,1,1)
Vector 向量(默认四维向量)
_Vector ("Vector", Vector) = (1,1,1,1)
Int 整数类型
_Int("Int",Int) = 2
Float 小数类型
_Float("Float",Float) = 4.5 Range 范围类型 小括号内为最大值和最小值,如果输入超过最大值的数值时,会自动调节至括号内的最大数值
_Range("Range",Range(1,11)) = 6
2D 图片类型 ""里面可以给颜色的值 当2D没有制定图片的时候 会显示""里面制定的颜色 {}里面进行制定具体的纹理
_2D("Texture",2D) = ""{}
Cube 立方体纹理 类似于skybox天空盒纹理
_Cube("Cube",Cube) = ""{}
3D 纹理 使用较少
_3D("3DTexture",3D) = ""{}
语义块SubShader
这个是shader里面最重要的内容,因为里面的语法控制就是电脑的gpu如何对物体进行渲染,决定了我们会看到的物体效果。一个shader里面是有多个SubShader的,shader加载的时候会从上到下进行加载SubShader里面的内容,先加载第一个SubShader里面的内容,如果第一个SubShader里面的效果都可以实现,那么就使用第一个SubShader ,如果显卡发现这个SubShader里面某个效果它实现不了,他会自动去运行下一个SubShader。SubShader里面定义了一系列的Pass(可以认为是高级语言中的方法函数,一个SubShader至少要包含一个Pass
ps:有一点奇怪的是为啥示例中的SubShader里面没有Pass,但是shader却没问题) ,在Pass里面编写具体的渲染细节。
Pass{
//在这里编写Shader代码 也可以用HLSLPROGRAM
CGPROGRAM
ENDCG
}
Pass中可以对Pass进行命名
例如 Name "FirstPass"
进行命名了的Pass可以在别的Shader中使用Use Pass直接引用
例如 UsePass "MyShader/FIRSTPASS"
除了自定义的Pass之外,Unity 还自定义了一些特殊的Pass,方便代码的复用,例如:
UsePass 前面提到的,用来引用别的shader中的pass
GrabPass 该Pass是负责抓取屏幕结果并储存为一张纹理,用于后续的Pass处理
[RenderSetup] 状态设置
通过设置RenderSetup的属性值我们可以设置显卡的各种状态,设置显卡的渲染状态,常见的渲染状态设置选项有:
状态名 设置指令
Cull Back|Font|Off 设置剔除模式:剔除背面/正面/关闭
ZTest Less Greater|LEqual|GEqual|Equal|NotEqual|Always 设置深度值测试时使用的函数
ZWrite On|Off 开启/关闭深度写入
Blend Blend SrcFactor DstFactor 开启并设置混合模式
使用的时候直接设置就好 例如 ZWrite On 来开启深度写入
[Tags] 标签
标签是用来告诉系统我希望如何以及什么时候来渲染这个对象的,Tags即可以在SubShader里面使用也可以在Pass中使用,不过两者的类型并不一样
SubShader的Tags类型
Queue 用来控制该物体属于哪个渲染队列,渲染队列可以自定义,该标签一般用来控制所有透明物体在不透明物体之后渲染 Tags{"Queue"= "Trans"}
RenderType 用于对着色器进行分类,例如将着色器分类为透明着色器和不透明着色器。 Tags{"RenderType"="Opaque"}
DisableBatching 用于设置是否对该SubShader使用批处理操作 Tags{"DisableBatching"= "True"}
ForceNoShadowCasting 用于控制该物体是否是否产生投影效果 Tags{"TagForceNoShadowCasting="True"}
IgnoreProjector 用于控制物体是否收到Projector的影响,通常是用于半透明物体
Tags{"IgnoreProjector"="True"}
CanUseSpriteAtlas 当该标签是用于sprites时,需要将该标签设置为FALSE Tags{"CanUseSpriteAtlas"="False"}
PreviewType 用于指定材质的预览形状,系统默认是圆形,可以更改为"skybox"之类的类型
Tags{"PreviewType"="Plane"}
Pass的Tags类型
LightMode 指定该Pass在Unity的渲染流水线中的角色 Tags{"LightMode"="ForwardBase"}
RequireOptions 指定一些值,当系统满足指定的条件时才会渲染该Pass,它的值是一个由空格分隔的字符串,目前unity支持的选项有SoftVegetation Tags{"RequireOptions"="SoftVegetation"}
Tags和RenderSetUp如果在SubShader里面设置,那么所有的Pass都会受到影响,如果在Pass里面设置,那么只会对当前的Pass产生影响
需要注意的是这两句CGPROGRAM和ENDCG不能忘记,这两句语句的意思是里面的代码都是使用的CG语法来编写Shader,编写Shader的语法一共有三种,一种是OPENGL的开发,使用的GLSL 语法来编写shader,不过这类更适合手机端的开发,第二种就是DirectX的开发,使用的是HSSL语法来编写shader,这类的语法只适用于pc端的开发,两种语法都不能在另一平台上使用。第三种就是英伟达公司
的CG语法进行shader的开发,具有良好的跨平台性。
在SubShader里面是不能直接使用上面定义好的属性,在SubShader里面,我们需要对使用的属性进行重新定义,将属性转换成另一种变量,具体的转换如下:
使用属性的时候需要进行重新定义
Color ==> float4
Vector ==> float4
Int ==> float
Float ==> float
Range ==> float
2D ==> sampler2D
Cube ==> samplerCube
3D ==> sampler3D
需要注意的是任何使用float类型的属性都可以用half和fixed替代,如
float ==> half ==> fixed
float4 ==> half4 ==> fixed4
区别:
float 使用32位来存储
half 使用16位来存储
fixed 使用11位来存储
为了节省内存 选择适当的数据类型
例如:颜色一般会使用fixed来进行存储
fixed4 _Color;
FallBack 后备方案
fallback在shader文件里面是紧跟在SubShader后面的,这个语义块的作用是当前面的SubShader没有一个是可用的,那么就执行这个语义块,这个语义块里面一般定义是定义为:
FallBack "Diffuse" or FallBack Off
FallBack 后面的额字符串里面的内容一般是一个系统定义好的shader,这样当前面的SubShader都不能使用的时候,就会调用系统的SubShader属性,但是如果你使用的是FallBack Off ,那么系统 可以理解为如果上面所有的SubShader都不能使用,那么就不管他了,不去渲染这个物体了。
有一点需要注意的是,如果FallBack指定了系统shader,如果系统的shader定义了和我们在Properties里面相同的属性名称的属性,并使用了该属性,就算是我们能在Inspector面板看到该属性并调节它,但是并不会对物体的颜色产生影响。
本人是学习unity的新手一枚,如果上述文章中有任何错误和不正确的地方,欢迎指出。写的不好,如果喷,请轻喷。,。