动机
最近项目中经常遇到需要修改或者编写shader的需求,每次百度搞完都是懵懵懂懂,也大概查了一些文档,甚至里面的名词都没看懂。所以准备系统的学习入门一下。
基本理解
首先介绍Unity中两个很重要并且相当常见的组件1.MeshFilter 2.MeshRenderer
MeshFilter
存储一个Mesh(网格,模型的网格,就是模型是由哪些三角面组成,组成一个什么杨的模型,三角面的一些顶点信息)
MeshRenderer
用来渲染一个模型的外观,就是样子。按照Mesh给他皮肤,给他颜色。通过Material控制模型渲染的样子
Material
贴图(可以没有,可以是一个单纯的颜色)
Shader
Shader也就是着色器,实际上就是负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用,然后输出,
绘图
单元可以依据这个输出来将图像绘制到屏幕上。输入的贴图或者颜色等,加上对应的Shader,以及对Shader的特定的参数设
置
,将这些内容(Shader及
输入
参数)打包存储在一起,得到的就是一个Material.。之后,我们便可以将材质赋予合适的Remderer
来进行渲染了。
Shader程序的基本结构
着色器(shader)
属性定义(Properties)(用来指定这段代码将有那些输入。)
子着色器(Subshader)( 子着色器是代码的主体,每一个子着色器中包含一个或者多个的Pass。在计算着色时,
平台先选
择
最优先可以使用的着色器,然后依次运行其中的Pass,然后得到输出的结果。)
Pass
Pass
回滚(FallBack)
Hellow Shader
首先创建一个标准表面着色器(Standard Surface Shader)来验证上面说的结构和阐述一些基本语法。
Shader "Custom/Demo1" {
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;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_CBUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_CBUFFER_END
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"
}
属性
在Properties{}中定义着色器属性,这些属性将作为输入提供给所有子着色器,使我们在程序代码中修改
_Color ("Color", Color) = (1,1,1,1)
_Color - 属性的名字,简单说就是变量名,在之后整个Shader代码中将使用这个名字来获取该属性的内容
“Color”-这个字符串将显示在Unity的材质编辑器中作为Shader的使用者可读的内容
type-这个属性的类型,可以的type所表示的内容有以下几种:
Color - 一种颜色,由RGBA(红绿蓝和透明度)四个量来定义;
2D - 一张2的阶数大小(256,512之类)的贴图。这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终被显示出来;
2D - 一张2的阶数大小(256,512之类)的贴图。这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终被显示出来;
Rect - 一个非2阶数大小的贴图;
Cube - 即Cube map texture(立方体纹理),简单说就是6张有联系的2D贴图的组合,主要用来做反射效果,也会被转换
为对应点的采样;
Range(min, max) - 一个介于最小值和最大值之间的浮点数,一般用来当作调整Shader某些特性的参数(比如透明度渲染
的截止值可以是从0至1的值等);
Float - 任意一个浮点数;
Vector - 一个四维数;
Vector - 一个四维数;
Tag
表面着色器可以被若干的标签(tags)所修饰,而硬件将通过判定这些标签来决定什么时候调用该着色器。比如我们的例子
中
SubShader的第一句
Tags { "RenderType"="Opaque" }
告诉了系统应该在渲染非透明物体时调用我们。Unity定义了一些列这样的渲染过程,与RenderType是Opaque相对应的显而易
告诉了系统应该在渲染非透明物体时调用我们。Unity定义了一些列这样的渲染过程,与RenderType是Opaque相对应的显而易
见的
是"RenderType" = "Transparent",表示渲染含有透明效果的物体时调用。在这里Tags其实暗示了你的Shader输出的是什么,如
果输
出中都是非透明物体,那写在Opaque里;如果想渲染透明或者半透明的像素,那应该写在Transparent中。
另外比较有用的标签还有"IgnoreProjector"="True"(不被Projectors影响),"ForceNoShadowCasting"="True"(从不产 生 阴 影
)以及"Queue"="xxx"(指定渲染顺序队列)。这里想要着重说一下的是Queue这个标签,如果你使用Unity做过一些透明和不透
明
物
体的混合的话,很可能已经遇到过不透明物体无法呈现在透明物体之后的情况。这种情况很可能是由于Shader的渲染顺序不正
确导
致的。Queue指定了物体的渲染顺序,预定义的Queue有:
Background - 最早被调用的渲染,用来渲染天空盒或者背景
Geometry - 这是默认值,用来渲染非透明物体(普通情况下,场景中的绝大多数物体应该是非透明的)
AlphaTest - 用来渲染经过Alpha Test的像素,单独为AlphaTest设定一个Queue是出于对效率的考虑
Transparent - 以从后往前的顺序渲染透明物体
Overlay - 用来渲染叠加的效果,是渲染的最后阶段(比如镜头光晕等特效)
AlphaTest - 用来渲染经过Alpha Test的像素,单独为AlphaTest设定一个Queue是出于对效率的考虑
Transparent - 以从后往前的顺序渲染透明物体
Overlay - 用来渲染叠加的效果,是渲染的最后阶段(比如镜头光晕等特效)
这些预定义的值本质上是一组定义整数,
Background = 1000,
Geometry = 2000,
AlphaTest = 2450,
Transparent = 3000,
Overlay = 4000。
在我们实际设置Queue值时,不仅能使用上面的几个预定义值,我们也可以指定自己的Queue值
写成类似这样
:"Queue"="Transparent+100",表示一个在Transparent之后100的Queue上进行调用。通过调整Queue值,我
们
可以确保某些物体一定在另一些物体之前或者之后渲染,这个技巧有时候很有用处。