第1篇 基础篇

第1章 欢迎来到Shader的世界

第2章 渲染流水线

第3章 Unity Shader 基础

第4章 学习Shader所需的数学基础

第2篇 初级篇

第5章 开始Unity Shader的学习之旅

第6章 Unity中的基础光照

第7章 基础纹理

第8章 透明效果

第3篇 中级篇

第9章 更复杂的光照

第10章 高级纹理

第11章 让画面动起来

第4篇 高级篇

第12章 屏幕后处理效果

第13章 使用深度和法线纹理

第14章 非真实感渲染

第15章 使用噪声

第16章 Unity中的渲染优化技术

第5篇 扩展篇

第17章 Unity的表面着色器探秘

第18章 基于物理的渲染

第19章 Unity5更新了什么

第20章 还有更多内容吗

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第1篇 基础篇

第1章 欢迎来到Shader的世界

第2章 渲染流水线

表2.1  3种图像接口从固定管线向可编程管线进化的版本
3D API 最后支持固定管线的版本 第一个支持可编程管线的版本
OpenGL 1.5 2.0
OpenGL ES 1.1 2.0
DirectX 7.0 8.0

第3章 Unity Shader 基础

表3.1  Properties 语义块支持的属性类型
属性类型 默认值的定义语法  例子
Int number _Int("Int",Int)=2
Float number _Float("Float",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,6,1)
2D "defaulttexture" {} _2D("2D",2D)="" {}
Cube "defaulttexture" {} _Cube("Cube",Cube)="white" {}
3D "defaulttexture" {} _3D("3D",3D)="black" {}
表3.2  常见的渲染状态设置选项
状态名称 设置指令 解释
Cull Cull Back|Front|Off 设置剔除模式:剔除背面/正面/关闭剔除
ZTest ZTest Less Greater|LEqual|GEqual|Equal|NotEqual|Always 设置深度测试时使用的函数
ZWrite ZWrite On|Off 开启/关闭深度写入
Blend Blend SrcFactor DstFactor 开启并设置混合模式
表3.3  SubShader的标签类型
标签类型 说明 例子
Queue 控制渲染顺序,指定该物体属于哪一个渲染队列,通过这种方式可以保证所有的透明物体可以在所有不透明物体后面被渲染,我们也可以自定义使用的渲染队列来控制物体的渲染顺序 Tags {"Queue" = "Transparent"}
RenderType 对着色器进行分类,例如这是一个不透明的着色器,或是一个透明的着色器等.这可以被用于着色器替换(Shader Replacement)功能 Tags {"RenderType" = "Opaque"}
DisableBatching 一些SubShader在使用Unity的批处理功能时会出现问题,例如使用了模型空间下的坐标进行顶点动画.这时可以通过该标签来直接指明是否对该SubShader使用批处理 Tags {"DisableBatching" = "True"}
ForceNoShadowCasting 控制使用该SubShader的物体是否会投射阴影 Tags {"ForceNoShadowCasting" = "True"}
IgnoreProjector 如果该标签值为"True",那么使用该SubShader的物体将不会受Projector的影响.通常用于半透明物体 Tags {"IgnoreProjector" = "True"}
CanUseSpriteAtlas 当该SubShader是用于精灵(sprites)时,将该标签设为"False" Tags {"CanUseSpriteAtlas" = "False"}
PreviewType 指明材质面板将如何预览该材质.默认情况下,材质将显示为一个球形,我们可以通过把该标签的值设为"Plane""SkyBox"来改变预览类型 Tags {"PreviewType" = "Plane"}
表3.4  Pass的标签类型
标签类型 说明 例子
LightMode 定义该Pass在Unity的渲染流水线中的角色 Tags {"LightMode" = "ForwardBase"}
RequireOptions 用于指定当满足某些条件时才渲染该Pass,它的值是一个由空格分隔的字符串.目前,Unity支持的选项有:SoftVegetation.在后面的版本中,可能会增加更多的选项 Tags {"RequireOptions" = "SoftVegetation"}

第4章 学习Shader所需的数学基础

表4.1  常见的变换种类和它们的特性(N 表示不满足该特性,Y 表示满足该特性)
变换名称 是线性变换吗 是仿射变换吗 是可逆矩阵吗 是正交矩阵吗
平移矩阵 N Y Y N
绕坐标轴旋转的旋转矩阵 Y Y Y Y
绕任意轴旋转的旋转矩阵 Y Y Y Y
按坐标轴缩放的缩放矩阵 Y Y Y N
错切矩阵 Y Y Y N
镜像矩阵 Y Y Y Y
正交投影矩阵 Y Y N N
透视投影矩阵 N N N N
表4.2  Unity内置的变换矩阵
变量名 描述
UNITY_MATRIX_MVP 当前的模型观察投影矩阵,用于将顶点/方向矢量从模型空间变换到裁剪空间
UNITY_MATRIX_MV 当前的模型观察矩阵,用于将顶点/方向矢量从模型空间变换到观察空间
UNITY_MATRIX_V 当前的观察矩阵,用于将顶点/方向矢量从世界空间变换到观察空间
UNITY_MATRIX_P 当前的投影矩阵,用于将顶点/方向矢量从观察空间变换到裁剪空间
UNITY_MATRIX_VP 当前的观察投影矩阵,用于将顶点/方向矢量从世界空间变换到裁剪空间
UNITY_MATRIX_T_MV UNITY_MATRIX_MV的转置矩阵
UNITY_MATRIX_IT_MV UNITY_MATRIX_MV的逆转置矩阵,用于将法线从模型空间变换到观察空间,也可用于得到UNITY_MATRIX_MV的逆矩阵
_Object2World 当前的模型矩阵,用于将顶点/方向矢量从模型空间变换到世界空间
_World2Object _Object2World的逆矩阵,用于将顶点/方向矢量从世界空间变换到模型空间
表4.3  Unity内置的摄像机和屏幕参数
变量名 类型 描述
_WorldSpaceCameraPos float3 该摄像机在世界空间中的位置
_ProjectionParams float4 x=1.0(或-1.0,如果正在使用一个翻转的投影矩阵进行渲染),y=Near,z=Far,w=1.0+1.0/Far,其中Near和Far分别是近裁剪平面和远裁剪平面和摄像机的距离
_ScreenParams float4 x=width,y=height,z=1.0+1.0/width,w=1.0+1.0/height,其中width和height分别是该摄像机
_ZBufferParams float4 x=1-Far/Near,y=Far/Near,z=x/Far,w=y/Far,该变量用于线性化Z缓存中的深度值
unity_OrthoParams float4 x=width,y=height,z没有定义,w=1.0(该摄像机是正交摄像机)或w=0.0(该摄像机是透视摄像机),其中width和height是正交投影摄像机的宽度和高度
unity_CameraProjection float4x4 该摄像机的投影矩阵
unity_CameraInvProjection float4x4 该摄像机的投影矩阵的逆矩阵
unity_CameraWorldClipPlanes[6] float4 该摄像机的6个裁剪平面在世界空间下的等式,按如下顺序:左,右,下,上,近,远裁剪平面

第2篇 初级篇

第5章 开始Unity Shader的学习之旅

表5.1  ShaderLab属性类型和Cg变量类型的匹配关系
ShaderLab属性类型 Cg变量类型
Color,Vector float4,half4,fixed4
Range,Float float,half,fixed
2D sampler2D
Cube samplerCube
3D sampler3D
表5.2  Unity中一些常用的包含文件
文件名 描述
UnityCG.cginc 包含了最常使用的帮助函数,宏和结构体等
UnityShaderVariables.cginc 在编译UnityShader时,会被自动包含进来.包含了许多内置的全局变量,如UNITY_MATRIX_MVP等
Lighting.cginc 包含了各种内置的光照模型,如果编写的是SurfaceShader的话,会自动包含进来
HLSLSupport.cginc 在编译UnityShader时,会被自动包含进来.声明了很多用于跨平台编译的宏和定义
表5.3  UnityCG.cginc中一些常用的结构体
名称 描述 包含的变量
appdata_base 可用于顶点着色器的输入 顶点位置,顶点法线,第一组纹理坐标
appdata_tan 可用于顶点着色器的输入 顶点位置,顶点切线,顶点法线,第一组纹理坐标
appdata_full 可用于顶点着色器的输入 顶点位置,顶点切线,顶点法线,四组(或更多)纹理坐标
appdata_img 可用于顶点着色器的输入 顶点位置,第一组纹理坐标
v2f_img 可用于顶点着色器的输出 裁剪空间中的位置,纹理坐标
表5.4  UnityCG.cginc中一些常用的帮助函数
函数名 描述
float3 WorldSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向
float3 ObjSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向
float3 WorldSpaceLightDir(float4 v) 仅可用于前向渲染中.输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向.没有被归一化
float3 ObjSpaceLightDir(float4 v) 仅可用于前向渲染中.输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向.没有被归一化
float3 UnityObjectToWorldNormal(float3 norm) 把法线方向从模型空间转换到世界空间中
float3 UnityObjectToWorldDir(float3 dir) 把方向矢量从模型空间变换到世界空间中
float3 UnityWorldToObjectDir(float3 dir) 把方向矢量从世界空间变换到模型空间中
表5.5  从应用阶段传递模型数据给顶点着色器时Unity支持的常用语义
语义 描述
POSITION 模型空间中的顶点位置,通常是float4类型
NORMAL 顶点法线,通常是float3类型
TANGENT 顶点切线,通常是float4类型
TEXCOORDn,如TEXCOORD0,TEXCOORD1 该顶点的纹理坐标,TEXCOORD0表示第一组纹理坐标,依次类推.通常是float2或float4类型
COLOR 顶点颜色,通常是fixed4或float4类型
表5.6  从顶点着色器传递数据给片元着色器时Unity使用的常用语义
语义  描述
SV_POSITION 裁剪空间的顶点坐标,结构体中必须包含一个用该语义修饰的变量.等同于DirectX9中的POSITION,但最好使用SV_POSITION
COLOR0 通常用于输出第一组顶点颜色,但不是必需的
COLOR1 通常用于输出第二组顶点颜色,但不是必需的
TEXCOORD0~TEXCOORD7 通常用于输出纹理坐标,但不是必需的
表5.7  片元着色器输出时Unity支持的常用语义
语义 描述
SV_Target 输出值将会存储到渲染目标(render target)中.等同于DirectX9中的COLOR语义,但最好使用SV_Target
表5.8  Cg/HLSL中3种精度的数值类型
类型 精度
float 最高精度的浮点值.通常使用32位来存储
half 中等精度的浮点值.通常使用16位来存储,精度范围是-60000~+60000
fixed 最低精度的浮点值.通常使用11位来存储,精度范围是-2.0~+2.0
表5.9  Unity支持的Shader Target
指令 描述
#pragma target 2.0 默认的Shader Target等级.相当于Direct3D 9上的Shader Model2.0,不支持对顶点纹理的采样,不支持显式的LOD纹理采样等
#pragma target 3.0 相当于Direct3D 9上的Shader Model 3.0,支持对顶点纹理的采样等
#pragma target 4.0 相当于Direct3D 10上的Shader Model 4.0,支持几何着色器等
#pragma target 5.0 相当于Direct3D 11上的Shader Model 5.0

 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

 Shader "Unity Shaders Book/Chapter 5/Simple Shader"{
     Properties{
         _Color("Color",Color)=(1.0,1.0,1.0,1.0)
     }
     SubShader{
         Pass{
             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             // 在Cg代码中,我们需要定义一个与属性名称和类型都匹配的变量
             fixed4 _Color;

             // 使用一个结构体来定义顶点着色器的输入
             struct a2v{
                 // POSITION语义告诉Unity,用模型空间的顶点坐标填充vertex变量
                 float4 vertex:POSITION;
                 // NORMAL语义告诉Unity,用模型空间的法线方向填充normal变量
                 float3 normal:NORMAL;
                 // TEXCOORD0语义告诉Unity,用模型的第一套纹理坐标填充texcoord变量
                 float4 texcoord:TEXCOORD0;
             };
             // 使用一个结构体来定义顶点着色器的输出
             struct v2f{
                 // SV_POSITION语义告诉Unity,pos里包含了顶点在裁剪空间种的位置信息
                 float4 pos:SV_POSITION;
                 // COLOR0语义可以用于存储颜色信息
                 fixed3 color:COLOR0;
             };

             v2f vert(a2v v):POSITION{
                 // 声明输出结构
                 v2f f;
                 f.pos = UnityObjectToClipPos(v.vertex);
                 // v.normal包含了顶点的法线方向,其分量范围在[-1.0,1.0]
                 // 下面的代码把分量范围映射到了[0.0,1.0]
                 // 存储到f.color中传递给片元着色器
                 f.color = v.normal * 0.5 + fixed3(0.5,0.5,0.5);
                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 fixed3 c = f.color;
                 // 使用_Color属性来控制输出颜色
                 c *= _Color.rgb;
                 // 将插值后的f.color显示到屏幕上
                 return fixed4(c,1.0);
             }

             ENDCG
         }
     }
 }

Simple Shader

第6章 Unity中的基础光照

表6.1  UnityCG.cginc中给一些常用的帮助函数
函数名 描述
float3 WorldSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向.内部实现使用了UnityWorldSpaceViewDir函数
float3 UnityWorldSpaceViewDir(float4 v) 输入一个世界空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向
float3 ObjSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向
float3 WorldSpaceLightDir(float4 v) 仅可用于前向渲染中.输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向.内部实现使用了UnityWorldSpaceLightDir函数.没有被归一化
float3 UnityWorldSpaceLightDir(float4 v) 仅可用于前向渲染中.输入一个世界空间中的顶点位置,返回世界空间中从该点到光源的光照方向.没有被归一化
float3 ObjSpaceLightDir(float4 v) 仅可用于前向渲染中.输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向.没有被归一化
float3 UnityObjectToWorldNormal(float3 norm) 把法线方向从模型空间转换到世界空间中
float3 UnityObjectToWorldDir(float3 dir) 把方向矢量从模型空间变换到世界空间中
float3 UnityWorldToObjectDir(float3 dir) 把方向矢量从世界空间变换到模型空间中

 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

 Shader "Unity Shader Book/Chapter 6/Diffuse Vertex-Level" {
     Properties{
         _Diffuse("Diffuse",Color)=(1.0,1.0,1.0,1.0)
     }
     SubShader{
         Pass{
             Tags { "LightMode" = "ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Diffuse;

             struct a2v{
                 float4 pos:POSITION;
                 float3 normal:NORMAL;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 fixed3 color:COLOR;
             };

             v2f vert(a2v v){
                 v2f f;
                 // Transform the vertex from object space to projection space
                 f.pos = UnityObjectToClipPos(v.pos);

                 // Get ambient term
                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                 // Transform the normal from object space to world sapce
                 fixed3 worldNormal = mul(UNITY_MATRIX_M,v.normal);
                 // Get the light direction in worldSpace
                 fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                 // Compute diffuse term
                 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));

                 f.color = ambient + diffuse;

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 return fixed4(f.color,1.0);
             }

             ENDCG
         }
     }

     Fallback "Diffuse"
 }

Diffuse Vertex-Level

 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

 Shader"Unity Shader Book/Chapter 6/Diffuse Pixel-Level" {
     Properties{
         _Diffuse(,,,)
     }
     SubShader{
         Pass{
             Tags { "LightMode" = "ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             struct a2v{
                 float4 pos:POSITION;
                 float3 normal:NORMAL;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float3 worldNormal:TEXCOORD0;
             };

             uniform fixed4 _Diffuse;

             v2f vert(a2v v){
                 v2f f;
                 // Transform the vertex from object space to projection space
                 f.pos = UnityObjectToClipPos(v.pos);
                 // Transform the normal from object space to world space
                 f.worldNormal = mul(UNITY_MATRIX_M,v.normal);

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 // Get ambient term
                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                 // Get the normal in world space
                 fixed3 worldNormalDir = normalize(f.worldNormal);
                 // Get the light direction in world space
                 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                 // Compute diffuse term
                 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormalDir,worldLightDir));

                 fixed3 color = ambient + diffuse;

                 return fixed4(color,1.0);
             }

             ENDCG
         }
     }
     Fallback "Diffuse"
 }

Diffuse Pixel-Level

 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

 Shader"Unity Shader Book/Chapter 6/Diffuse Half-Lambert" {
     Properties{
         _Diffuse(,,,)
     }
     SubShader{
         Pass{
             Tags { "LightMode" = "ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             struct a2v{
                 float4 pos:POSITION;
                 float3 normal:NORMAL;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float3 worldNormal:TEXCOORD0;
             };

             uniform fixed4 _Diffuse;

             v2f vert(a2v v){
                 v2f f;
                 // Transform the vertex from object space to projection space
                 f.pos = UnityObjectToClipPos(v.pos);
                 // Transform the normal from object space to world space
                 f.worldNormal = mul(UNITY_MATRIX_M,v.normal);

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 // Get ambient term
                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                 // Get the normal in world space
                 fixed3 worldNormalDir = normalize(f.worldNormal);
                 // Get the light direction in world space
                 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                 // Compute diffuse term
                 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldNormalDir,worldLightDir) * 0.5 + 0.5);

                 fixed3 color = ambient + diffuse;

                 return fixed4(color,1.0);
             }

             ENDCG
         }
     }
     Fallback "Diffuse"
 }

Diffuse Half-Lambert

 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

 Shader "Unity Shader Book/Chapter 6/Specular Vertex-Level" {
     Properties {
         _Diffuse("Diffuse",Color)=(1.0,1.0,1.0,1.0)
         _Specular("Specular",Color)=(1.0,1.0,1.0,1.0)
         _Gloss("Gloss",Range(8.0,256.0))=20.0
     }
     SubShader{
         Pass{
             Tags{"LightMode"="ForwardBase"}

             CGPROGRAM

             #include "Lighting.cginc"

             fixed4 _Diffuse;
             fixed4 _Specular;
             float _Gloss;

             #pragma vertex vert
             #pragma fragment frag

             struct a2v{
                 float4 pos:POSITION;
                 float3 normal:NORMAL;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float3 color:COLOR;
             };

             v2f vert(a2v v){
                 v2f f;

                 // Transform the vertex from object space to projection space
                 f.pos = UnityObjectToClipPos(v.pos);

                 // Get ambient term
                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                 // Transform the normal from object space to world space
                 float3 worldNormalDir = normalize(mul(UNITY_MATRIX_M,v.normal));
                 // Get the light direction in world space
                 float3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); 

                 // Compute diffuse term
                 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormalDir,worldLightDir));

                 // Get the reflect direction in world space
                 fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormalDir));
                 // Get the view direction in world space
                 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(UNITY_MATRIX_M,v.pos).xyz);

                 // Compute specular term
                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);

                 f.color = ambient + diffuse + specular;

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 );
             }

             ENDCG
         }
     }

     Fallback "Specular"
 }

Specular Vertex-Level

 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

 Shader "Unity Shader Book/Chapter 6/Specular Pixel-Level" {
     Properties {
         _Diffuse("Diffuse",Color)=(1.0,1.0,1.0,1.0)
         _Specular("Specular",Color)=(1.0,1.0,1.0,1.0)
         _Gloss(,))=
     }
     SubShader{
         Pass{
             Tags {"LightMode"="ForwardBase"}

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Diffuse;
             fixed4 _Specular;
             float _Gloss;

             struct a2v{
                 float4 pos:POSITION;
                 float3 normal:NORMAL;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float3 worldNormal:TEXCOORD0;
                 float3 worldPos:TEXCOORD1;
             };

             v2f vert(a2v v){
                 v2f f;
                 // Transform the vertex from object space to projection space
                 f.pos = UnityObjectToClipPos(v.pos);
                 // Transform the normal from object space to world space
                 f.worldNormal = mul(UNITY_MATRIX_M,v.normal);
                 // Transform the vertex from object space to world space
                 f.worldPos = mul(UNITY_MATRIX_M,v.pos).xyz;

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 // Get ambient term
                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                 fixed3 worldNormalDir = normalize(f.worldNormal);
                 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

                 // Compute diffuse term
                 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormalDir,worldLightDir));

                 // Get the reflect direction in world space
                 fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormalDir));
                 // Get the view direction in world space
                 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldPos.xyz);

                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);

                 return fixed4(ambient + diffuse + specular,1.0);
             }

             ENDCG
         }
     }

     Fallback "Specular"
 }

Specular Pixel-Level

 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

 Shader "Unity Shader Book/Chapter 6/Specular BlinnPhong" {
     Properties {
         _Diffuse("Diffuse",Color)=(1.0,1.0,1.0,1.0)
         _Specular("Specular",Color)=(1.0,1.0,1.0,1.0)
         _Gloss(,))=
     }
     SubShader{
         Pass{
             Tags {"LightMode"="ForwardBase"}

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Diffuse;
             fixed4 _Specular;
             float _Gloss;

             struct a2v{
                 float4 pos:POSITION;
                 float3 normal:NORMAL;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float3 worldNormal:TEXCOORD0;
                 float3 worldPos:TEXCOORD1;
             };

             v2f vert(a2v v){
                 v2f f;
                 // Transform the vertex from object space to projection space
                 f.pos = UnityObjectToClipPos(v.pos);
                 // Transform the normal from object space to world space
                 f.worldNormal = mul(UNITY_MATRIX_M,v.normal);
                 // Transform the vertex from object space to world space
                 f.worldPos = mul(UNITY_MATRIX_M,v.pos).xyz;

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 // Get ambient term
                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                 fixed3 worldNormalDir = normalize(f.worldNormal);
                 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

                 // Compute diffuse term
                 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormalDir,worldLightDir));

                 // Get the reflect direction in world space
                 fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormalDir));
                 // Get the view direction in world space
                 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldPos.xyz);
                 // Get the half direction in world space
                 fixed3 halfDir = normalize(worldLightDir + viewDir);
                 // Compute specular term
                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(,dot(worldNormalDir,halfDir)),_Gloss);

                 return fixed4(ambient + diffuse + specular,1.0);
             }

             ENDCG
         }
     }

     Fallback "Specular"
 }

Specular BlinnPhong

第7章 基础纹理

 Shader "Unity Shader Book/Chapter 7/Simplest Texture" {
     Properties{
         _MainTex("MainTex",2D) = "white"{}
     }
     SubShader{
         Pass{
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             sampler2D _MainTex;

             struct a2v{
                 float4 vertex:POSITION;
                 float4 uv:TEXCOORD0;
             };

             struct v2f{
                 float4 pos:SV_POSITION;
                 float4 uv:TEXCOORD0;
             };

             v2f vert(a2v v){
                 v2f f;

                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.uv = v.uv;

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{

                 float4 albedo = tex2D(_MainTex,f.uv);

                 return albedo;
             }

             ENDCG
         }
     }

     Fallback "Specular"
 }

Simplest Texture

 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

 Shader "Unity Shader Book/Chapter 7/Single Texture" {
     Properties {
         _Color (, , , )
         _MainTex ("Main Tex", 2D) = "white" {}
         _Specular (, , , )
         _Gloss ()) =
     }
     SubShader {
         Pass{
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             float4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             float4 _Specular;
             float _Gloss;

             struct a2v{
                 float4 vertex:POSITION;
                 float3 normal:NORMAL;
                 float4 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float3 worldNormal:TEXCOORD1;
                 float3 worldPos:TEXCOORD2;
                 float2 uv:TEXCOORD3;

             };

             v2f vert(a2v v){
                 v2f f;

                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.worldNormal = mul(UNITY_MATRIX_M,v.normal);
                 f.worldPos = mul(UNITY_MATRIX_M, v.vertex).xyz;

                 f.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                 // Or just call the built-in function
                 // Transform 2D UV by scale/bias property
                 // #define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
                 // f.uv = TRANSFORM_TEX(v.texcoord,_MainTex);

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 fixed3 worldNormalDir = normalize(f.worldNormal);
                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(f.worldPos));

                 // Use the texture to sample the diffuse color
                 fixed3 albedo = tex2D(_MainTex,f.uv).rgb * _Color.rgb;

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                 fixed3 diffuse = _LightColor0.rgb * albedo * max(,dot(worldNormalDir,worldLightDir));

                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldPos));
                 fixed3 halfDir = normalize(worldLightDir + viewDir);
                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(, dot(worldNormalDir, halfDir)), _Gloss);

                 return fixed4(ambient + diffuse + specular, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Specular"
 }

SingleTexture

 Shader "Unity Shader Book/Chapter 7/Simplest NormalMap" {
     Properties{
         _BumpMap("Bump Map",2D) = "bump"{}
         _BumpScale("Bump Scale",Float) = 1.0
     }
     SubShader{
         Pass{
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             sampler2D _BumpMap;
             float _BumpScale;

             struct a2v{
                 float4 vertex:POSITION;
                 float3 normal:NORMAL;
                 float4 tangent:TANGENT;
                 float4 uv:TEXCOORD0;
             };

             struct v2f{
                 float4 pos:SV_POSITION;
                 float4 uv:TEXCOORD0;
                 float3 lightDir:TEXCOORD1;
             };

             v2f vert(a2v v){
                 v2f f;

                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.uv = v.uv;

                 TANGENT_SPACE_ROTATION;

                 f.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex)).xyz;

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 fixed3 tangentLightDir = normalize(f.lightDir);

                 fixed4 packedNormal = tex2D(_BumpMap, f.uv);

                 fixed3 tangentNormal;
                 tangentNormal = UnpackNormal(packedNormal);
                 tangentNormal.xy *= _BumpScale;
                 tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));

                 fixed3 diffuse = max(,dot(tangentNormal,tangentLightDir));

                 );
             }

             ENDCG
         }
     }

     Fallback "Specular"
 }

Simplest NormalMap

 Shader "Unity Shader Book/Chapter 7/Normal Map In Tangent Space" {
     Properties {
         _Color (, , , )
         _MainTex ("Main Tex", 2D) = "white" {}
         _BumpMap ("Normal Map", 2D) = "bump" {}
         _BumpScale ("Bump Scale", Float) = 1.0
         _Specular (, , , )
         _Gloss ()) =
     }
     SubShader {
         Pass {
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             sampler2D _BumpMap;
             float4 _BumpMap_ST;
             float _BumpScale;
             fixed4 _Specular;
             float _Gloss;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 tangent : TANGENT;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float4 uv : TEXCOORD0;
                 float3 lightDir: TEXCOORD1;
                 float3 viewDir : TEXCOORD2;
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                 o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;

                 // Compute the binormal
 //                float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w;
 //                // Construct a matrix which transform vectors from object space to tangent space
 //                float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);
                 // Or just use the built-in macro
                 TANGENT_SPACE_ROTATION;

                 // Transform the light direction from object space to tangent space
                 o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
                 // Transform the view direction from object space to tangent space
                 o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 tangentLightDir = normalize(i.lightDir);
                 fixed3 tangentViewDir = normalize(i.viewDir);

                 // Get the texel in the normal map
                 fixed4 packedNormal = tex2D(_BumpMap, i.uv.zw);
                 fixed3 tangentNormal;
                 // If the texture is not marked as "Normal map"
 //                tangentNormal.xy = (packedNormal.xy * 2 - 1) * _BumpScale;
 //                tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));

                 // Or mark the texture as "Normal map", and use the built-in funciton
                 tangentNormal = UnpackNormal(packedNormal);
                 tangentNormal.xy *= _BumpScale;
                 tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));

                 fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                 fixed3 diffuse = _LightColor0.rgb * albedo * max(, dot(tangentNormal, tangentLightDir));

                 fixed3 halfDir = normalize(tangentLightDir + tangentViewDir);
                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(, dot(tangentNormal, halfDir)), _Gloss);

                 return fixed4(ambient + diffuse + specular, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Specular"
 }

Normal Map In Tangent Space

 Shader "Unity Shader Book/Chapter 7/Normal Map In World Space" {
     Properties {
         _Color (, , , )
         _MainTex ("Main Tex", 2D) = "white" {}
         _BumpMap ("Normal Map", 2D) = "bump" {}
         _BumpScale ("Bump Scale", Float) = 1.0
         _Specular (, , , )
         _Gloss ()) =
     }
     SubShader {
         Pass {
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             sampler2D _BumpMap;
             float4 _BumpMap_ST;
             float _BumpScale;
             fixed4 _Specular;
             float _Gloss;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 tangent : TANGENT;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float4 uv : TEXCOORD0;
                 float4 TtoW0 : TEXCOORD1;
                 float4 TtoW1 : TEXCOORD2;
                 float4 TtoW2 : TEXCOORD3;
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                 o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;

                 float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                 fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                 fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                 fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 

                 // Compute the matrix that transform directions from tangent space to world space
                 // Put the world position in w component for optimization
                 o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                 o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                 o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 // Get the position in world space
                 float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
                 // Compute the light and view dir in world space
                 fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));

                 // Get the normal in tangent space
                 fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
                 bump.xy *= _BumpScale;
                 bump.z = sqrt(1.0 - saturate(dot(bump.xy, bump.xy)));
                 // Transform the narmal from tangent space to world space
                 bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));

                 fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                 fixed3 diffuse = _LightColor0.rgb * albedo * max(, dot(bump, lightDir));

                 fixed3 halfDir = normalize(lightDir + viewDir);
                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(, dot(bump, halfDir)), _Gloss);

                 return fixed4(ambient + diffuse + specular, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Specular"
 }

Normal Map In World Space

 Shader "Unity Shader Book/Chapter 7/Ramp Texture" {
     Properties {
         _Color (, , , )
         _RampTex ("Ramp Tex", 2D) = "white" {}
         _Specular (, , , )
         _Gloss ()) =
     }
     SubShader {
         Pass {
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Color;
             sampler2D _RampTex;
             float4 _RampTex_ST;
             fixed4 _Specular;
             float _Gloss;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float3 worldNormal : TEXCOORD0;
                 float3 worldPos : TEXCOORD1;
                 float2 uv : TEXCOORD2;
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.worldNormal = UnityObjectToWorldNormal(v.normal);

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                 o.uv = TRANSFORM_TEX(v.texcoord, _RampTex);

                 return o;
             }

             fixed4 frag(v2f f) : SV_Target {
                 fixed3 worldNormal = normalize(f.worldNormal);
                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(f.worldPos));

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                 // Use the texture to sample the diffuse color
                 fixed halfLambert  = 0.5 * dot(worldNormal, worldLightDir) + 0.5;
                 fixed3 diffuseColor = tex2D(_RampTex, fixed2(halfLambert, halfLambert)).rgb * _Color.rgb;

                 fixed3 diffuse = _LightColor0.rgb * diffuseColor;

                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldPos));
                 fixed3 halfDir = normalize(worldLightDir + viewDir);
                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(, dot(worldNormal, halfDir)), _Gloss);

                 return fixed4(ambient + diffuse + specular, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Specular"
 }

RampTexture

第8章 透明效果

表8.1  Unity提前定义的5个渲染队列
名称 队列索引号 描述
Background 1000 这个渲染队列会在任何其他队列之前被渲染,我们通常使用该队列来渲染那些需要绘制在背景上的物体
Geometry 2000 默认的渲染队列,大多数物体都使用这个队列.不透明物体使用这个队列
AlphaTest 2450 需要透明度测试的物体使用这个队列.在Unity5中它从Geometry队列中被单独分出来,这是因为在所有不透明物体渲染之后再渲染它们会更加高效
Transparent 3000 这个队列中的物体会在所有Geometry和AlphaTest物体渲染后,再按从后往前的顺序进行渲染.任何使用了透明度混合(例如关闭了深度写入的Shader)的物体都应该使用该队列
Overlay 4000 该队列用于实现一些叠加效果.任何需要在最后渲染的物体都应该使用该队列

 Shader "Unity Shader Book/Chapter 8/Alpha Test" {
     Properties{
         _Color(,,,)
         _MainTex("Main Tex",2D) = "white"{}
         _Cutoff(,)) = 0.5
     }
     SubShader{

         Tags { "Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout" }

         Pass{
             Tags { "LightMode" = "ForwardBase" }    

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             fixed _Cutoff;

             struct a2v{
                 float4 vertex:POSITION;
                 float4 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float2 uv:TEXCOORD2;
             };

             v2f vert(a2v v){
                 v2f f;
                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.uv = v.texcoord;

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 fixed4 texColor = tex2D(_MainTex,f.uv);

                 // Alpha test
                 clip(texColor.a - _Cutoff);
                 // Equal to
                 //if((texColor.a - _Cutoff) < 0.0){
                 //discard;
                 //}

                 return texColor;
             }

             ENDCG
         }
     }
     Fallback "Transparent/Cutout/VertexLit"
 }

Alpha Test

表8.2  ShaderLab的Blend命令
语义 描述
Blend Off 关闭混合
Blend SrcFactor DstFactor 开启混合,并设置混合因子.源颜色(该片元产生的颜色)会乘以SrcFactor,而目标颜色(已经存在于颜色缓存的颜色)会乘以DstFactor,然后把两者相加后再存入颜色缓冲中
Blend SrcFactor DstFactor,SrcFactorA DstFactorA 和上面几乎一样,只是使用不同的因子来混合透明通道
BlendOp BlendOperation 并非是把源颜色和目标颜色简单相加后混合,而是使用BlendOperation对它们进行其他操作

 Shader "Unity Shader Book/Chapter 8/Alpha Blend" {
     Properties{
         _Color(,,,)
         _MainTex("Main Tex",2D)="white"{}
         _AlphaScale(,))=
     }
     SubShader{
         Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
         Pass{
             Tags { "LightMode"="ForwardBase" }

             ZWrite off
             Blend SrcAlpha OneMinusSrcAlpha

             //Blend Off

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             float4 _Color;
             sampler2D _MainTex;
             float _AlphaScale;

             struct a2v{
                 float4 vertex:POSITION;
                 float3 normal:NORMAL;
                 float4 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float3 worldNormal:TEXCOORD0;
                 float3 worldPos:TEXCOORD1;
                 float2 uv:TEXCOORD2;
             };

             v2f vert(a2v v){
                 v2f f;
                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.worldNormal = mul(UNITY_MATRIX_M,v.normal);
                 f.worldPos = mul(UNITY_MATRIX_M,v.vertex);
                 f.uv = v.texcoord;
                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 //float3 worldNormalDir = normalize(f.worldNormal);
                 //float3 worldLightDir = normalize(UnityWorldSpaceLightDir(f.worldPos));

                 float4 texColor = tex2D(_MainTex,f.uv);
                 //float3 albedo = _LightColor0.xyz * _Color.xyz * texColor.xyz * max(0,dot(worldNormalDir,worldLightDir));

                 float3 albedo = texColor.xyz;

                 return fixed4(albedo,0.5);
             }

             ENDCG
         }

     }
     Fallback "Transparent/VertexLit"
 }

Alpha Blend

 Shader "Unity Shader Book/Chapter 8/Alpha Blending ZWrite" {
     Properties{
         _Color(,,,)
         _MainTex("Main Tex",2D)="white"{}
         _AlphaScale(,))=
     }
     SubShader{
         Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
         Pass {
             ZWrite On
             ColorMask
         }
         Pass{
             Tags { "LightMode"="ForwardBase" }

             ZWrite off
             Blend SrcAlpha OneMinusSrcAlpha

             //Blend Off

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             float4 _Color;
             sampler2D _MainTex;
             float _AlphaScale;

             struct a2v{
                 float4 vertex:POSITION;
                 float3 normal:NORMAL;
                 float4 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float3 worldNormal:TEXCOORD0;
                 float3 worldPos:TEXCOORD1;
                 float2 uv:TEXCOORD2;
             };

             v2f vert(a2v v){
                 v2f f;
                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.worldNormal = mul(UNITY_MATRIX_M,v.normal);
                 f.worldPos = mul(UNITY_MATRIX_M,v.vertex);
                 f.uv = v.texcoord;
                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 float3 worldNormalDir = normalize(f.worldNormal);
                 float3 worldLightDir = normalize(UnityWorldSpaceLightDir(f.worldPos));

                 float4 texColor = tex2D(_MainTex,f.uv);
                 //float3 albedo = _LightColor0.xyz * _Color.xyz * texColor.xyz * max(0,dot(worldNormalDir,worldLightDir));

                 float3 albedo = _Color.xyz * texColor.xyz * max(,dot(worldNormalDir,worldLightDir));

                 return fixed4(albedo,0.5);
             }

             ENDCG
         }

     }
     Fallback "Transparent/VertexLit"
 }

Alpha Blending ZWrite

表8.3  ShaderLab中设置混合因子的命令
命令 描述
Blend SrcFactor DstFactor 开启混合,并设置混合因子.源颜色(该片元产生的颜色)会乘以SrcFactor,而目标颜色(已经存在于颜色缓存的颜色)会乘以DstFactor,然后把两者相加后再存入颜色缓冲中
Blend SrcFactor DstFactor,SrcFactorA DstFactorA 和上面几乎一样,只是使用不同的因子来混合透明通道
表8.4  ShaderLab中的混合因子
参数 描述
One 因子为1
Zero 因子为0
SrcColor 因子为源颜色值.当用于混合RGB的混合等式时,使用SrcColor的RGB分量作为混合因子;当用于混合A的混合等式时,使用SrcColor的A分量作为混合因子
SrcAlpha 因子为源颜色的透明度值(A通道)
DstColor 因子为目标颜色值.当用于混合RGB通道的混合等式时,使用DstColor的RGB分量作为混合因子;当用于混合A通道的混合等式时,使用DstColor的A分量作为混合因子
DstAlpha 因子为目标颜色的透明度值(A通道)
OneMinusSrcColor 因子为(1-源颜色).当用于混合RGB的混合等式时,使用结果的RGB分量作为混合因子;当用于混合A的混合等式时,使用结果的A分量作为混合因子
OneMinusSrcAlpha 因子为(1-源颜色的透明度值)
OneMinusDstColor 因子为(1-目标颜色).当用于混合RGB的混合等式时,使用结果的RGB分量作为混合因子;当用于混合A的混合等式时,使用结果的A分量作为混合因子
OneMinusDstAlpha 因子为(1-目标颜色的透明度值)
表8.5  ShaderLab中的混合操作
操作 描述
Add

将混合后的源颜色和目标颜色相加.默认的混合操作.使用的混合等式是:

Orgb = SrcFactor x Srgb + DstFactor x Drgb

Oa = SrcFactorA x Sa + DstFactorA x Da

Sub

用混合后的源颜色减去混合后的目标颜色.使用的混合等式是:

Orgb = SrcFactor x Srgb - DstFactor x Drgb

Oa = SrcFactorA x Sa - DstFactorA x Da

RevSub

用混合后的目标颜色减去混合后的源颜色.使用的混合等式是:

Orgb = DstFactor x Drgb - SrcFactor x Srgb

Oa = DstFactorA x Da - SrcFactorA x Sa

Min

使用源颜色和目标颜色中较小的值,是逐分量比较的.使用的混合等式是:

Orgba = (min(Sr,Dr),min(Sg,Dg),min(Sb,Db),min(Sa,Da))

Max

使用源颜色和目标颜色中较大的值,是逐分量比较的.使用的混合等式是:

Orgba = (max(Sr,Dr),max(Sg,Dg),max(Sb,Db),max(Sa,Da))

其他逻辑操作 仅再DirectX 11.1中支持
 Shader "Unity Shader Book/Chapter 8/Alpha Blend Operations" {
     Properties{
         _Color(,,,)
         _MainTex("MainTex",2D)="white"{}
         _AlphaScale(,))=
     }
     SubShader{
         Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
         Pass{
             Tags { "LightMode"="ForwardBase" }
             ZWrite Off

             // Normal
             Blend SrcAlpha OneMinusSrcAlpha

             // Soft Additive
             //Blend OneMinusDstColor One

             // Multiply
             //Blend DstColor Zero

             // 2x Multiply
             //Blend DstColor SrcColor

             // Darken
             //BlendOp Min
             //Blend One One    // When using Min operation,these factors are ignored

             // Lighten
             //BlendOp Max
             //Blend One One // When using Max operation,these factors are ignored

             // Screen
             //Blend OneMinusDstColor One
             // Or
             //Blend One OneMinusSrcColor

             // Linear Dodge
             //Blend One One

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             fixed _AlphaScale;

             struct a2v{
                 float4 vertex:POSITION;
                 float3 normal:NORMAL;
                 float4 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float2 uv:TEXCOORD0;
             };

             v2f vert(a2v v){
                 v2f f;
                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.uv = v.texcoord;
                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 fixed4 texColor = tex2D(_MainTex,f.uv);
                 return fixed4(texColor.xyz * _Color.rgb,texColor.a * _AlphaScale);
             }

             ENDCG
         }
     }
     Fallback "Transparent/VertexLit"
 }

Alpha Blend Operations

 Shader "Unity Shader Book/Chapter 8/Alpha Test With Both Side" {
     Properties{
         _Color(,,,)
         _MainTex("MainTex",2D)="white"{}
     }
     SubShader{
         Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
         Pass{
             Tags { "LightMode"="ForwardBase" }

             Cull Off

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             float4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;

             struct a2v{
                 float4 vertex:POSITION;
                 float4 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float2 uv:TEXCOORD0;
             };

             v2f vert(a2v v){
                 v2f f;
                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.uv = v.texcoord;
                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 float4 texColor = tex2D(_MainTex,f.uv);

                 if(texColor.a <0.6){
                     discard;
                 }

                 return texColor;
             }

             ENDCG
         }
     }
     Fallback "Transparent/Cutout/VertexLit"
 }

Alpha Test With Both Side

 Shader "Unity Shader Book/Chapter 8/Alpha Blend With Both Side" {
     Properties {
         _Color (, , , )
         _MainTex ("Main Tex", 2D) = "white" {}
         _AlphaScale (, )) =
     }
     SubShader {
         Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}

         Pass {
             Tags { "LightMode"="ForwardBase" }

             // First pass renders only back faces
             Cull Front

             ZWrite Off
             Blend SrcAlpha OneMinusSrcAlpha

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             fixed _AlphaScale;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float3 worldNormal : TEXCOORD0;
                 float3 worldPos : TEXCOORD1;
                 float2 uv : TEXCOORD2;
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.worldNormal = UnityObjectToWorldNormal(v.normal);

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

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

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 worldNormal = normalize(i.worldNormal);
                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

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

                 fixed3 albedo = texColor.rgb * _Color.rgb;

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                 fixed3 diffuse = _LightColor0.rgb * albedo * max(, dot(worldNormal, worldLightDir));

                 return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
             }

             ENDCG
         }

         Pass {
             Tags { "LightMode"="ForwardBase" }

             // Second pass renders only front faces
             Cull Back

             ZWrite Off
             Blend SrcAlpha OneMinusSrcAlpha

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             fixed _AlphaScale;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float3 worldNormal : TEXCOORD0;
                 float3 worldPos : TEXCOORD1;
                 float2 uv : TEXCOORD2;
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.worldNormal = UnityObjectToWorldNormal(v.normal);

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

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

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 worldNormal = normalize(i.worldNormal);
                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

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

                 fixed3 albedo = texColor.rgb * _Color.rgb;

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                 fixed3 diffuse = _LightColor0.rgb * albedo * max(, dot(worldNormal, worldLightDir));

                 return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
             }

             ENDCG
         }
     }
     FallBack "Transparent/VertexLit"
 }

Alpha Blend With Both Side

第3篇 中级篇

第9章 更复杂的光照

表9.1  LightMode标签支持的渲染路径设置选项
标签名 描述
Always 不管使用那种渲染路径,该Pass总是会被渲染,但不会计算任何光照
ForwardBase 用于前向渲染.该Pass会计算环境光,最重要的平行光,逐顶点/SH光源和Lightmaps
ForwardAdd 用于前向渲染.该Pass会计算额外的逐像素光源,每个Pass对应一个光源
Deferred 用于延迟渲染.该Pass会渲染G缓冲(G-buffer)
ShadowCaster 把物体的深度信息渲染到阴影映射纹理(shadowmap)或一张深度纹理中
PrepassBase 用于遗留的延迟渲染.该Pass会渲染法线和高光反射的指数部分
PrepassFinal 用于遗留的延迟渲染.该Pass通过合并纹理,光照和自发光来渲染得到最后的颜色
Vertex,VertexLMRGBM和VertexLM 用于遗留的顶点照明渲染
表9.2  前向渲染可以使用的内置光照变量
名称 类型 描述
_LightColor0 float4 该Pass处理的逐像素光源的颜色
_WorldSpaceLightPos0 float4 _WorldSpaceLightPos0.xyz 是该Pass处理的逐像素光源的位置.如果该光源是平行光,那么_WorldSpaceLightPos0.w是0,其他光源类型w值为1
_LightMatrix0 float4x4 从世界空间到光源空间的变换矩阵.可以用于采样cookie和光强衰减(attenuation)纹理

unity_4LightPosX0,

unity_4LightPosY0,

unity_4LightPosZ0

float4 仅用于Base Pass.前4个非重要的点光源在世界空间中的位置
unity_4LightAtten0 float4 仅用于Base Pass.存储了前4个非重要的点光源的衰减因子
unity_LightColor half[4] 仅用于Base Pass.存储了前4个非重要的点光源的颜色
表9.3  前向渲染可以使用的内置光照函数
函数名 描述
float3 WorldSpaceLightDir(float4 v) 仅可用于前向渲染中.输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向.内部实现使用了UnityWorldSpaceLightDir函数.没有被归一化
float3 UnityWorldSpaceLightDir(float4 v) 仅可用于前向渲染中.输入一个世界空间中的顶点位置,返回世界空间中从该点到光源的光照方向.没有被归一化
float3 ObjSpaceLightDir(float4 v) 仅可用于前向渲染中.输入一个模型空间的顶点位置,返回模型空间中从该点到光源的光照方向.没有被归一化
float3 Shade4PointLights(...)

仅可用于前向渲染中.计算四个点光源的光照,它的参数是已经打包进矢量的光照数据,通常就是表9.2中的内置变量,如unity_4LightPosX0,unity_4LightPosY0,

unity_4LightPosZ0,unity_LightColor和unity_4LightAtten0等.前向渲染通常会使用这个函数来计算逐顶点光照

表9.4  顶点照明渲染路径中可以使用的内置变量
名称 类型 描述
unity_LightColor half4[8] 光源颜色
unity_LightPosition float4[8] xyz分量是视角空间中的光源位置.如果光源是平行光,那么z分量值为0,其他光源类型z分量值为1
untiy_LightAtten half4[8]

光源衰减因子.如果光源是聚光灯,x分量是cos(spotAngle/2),y分量是1/cos(spotAngle/4);如果是其他类型的光源,x分量是-1,y分量是1.z分量是衰减的平方,

w分量是光源范围开根号的结果

untiy_SpotDirection float4[8] 如果光源是聚光灯的话,值为视角空间的聚光灯的位置;如果是其他类型的光源,值为(0,0,1,0)
表9.5  顶点照明渲染路径中可以使用的内置函数
函数名 描述
float3 ShadeVertexLights(float4 vertex,float3 normal) 输入模型空间中的顶点位置和法线,计算四个逐顶点光源的光照以及环境光.内部实现实际上调用了ShadeVertexLightsFull函数
float3 ShadeVertexLightsFull(float4 vertex,float3 normal,int lightCount,bool spotLight) 输入模型空间中的顶点位置和法线,计算lightCount个光源的光照以及环境光.如果spotLight值为true,那么这些光源会被当成聚光灯来处理,虽然结果更精确,但计算更加耗时;否则,按点光源处理
表9.6  延迟渲染路径中可以使用的内置变量
名称 类型 描述
_LightColor float4 光源颜色
_LightMatrix0 float4x4 从世界空间到光源空间的变换矩阵.可以用于采样cookie和光强衰减纹理

 Shader "Unity Shader Book/Chapter 9/Forward Rendering" {
     Properties {
         _Diffuse (, , , )
         _Specular (, , , )
         _Gloss ()) =
     }
     SubShader {
         Tags { "RenderType"="Opaque" }

         Pass {
             // Pass for ambient light & first pixel light (directional light)
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             // Apparently need to add this declaration
             #pragma multi_compile_fwdbase    

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Diffuse;
             fixed4 _Specular;
             float _Gloss;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float3 worldNormal : TEXCOORD0;
                 float3 worldPos : TEXCOORD1;
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.worldNormal = UnityObjectToWorldNormal(v.normal);

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 worldNormal = normalize(i.worldNormal);
                 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                  fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(, dot(worldNormal, worldLightDir));

                  fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                  fixed3 halfDir = normalize(worldLightDir + viewDir);
                  fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(, dot(worldNormal, halfDir)), _Gloss);

                 fixed atten = 1.0;

                 return fixed4(ambient + (diffuse + specular) * atten, 1.0);
             }

             ENDCG
         }

         Pass {
             // Pass for other pixel lights
             Tags { "LightMode"="ForwardAdd" }

             Blend One One

             CGPROGRAM

             // Apparently need to add this declaration
             #pragma multi_compile_fwdadd

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"
             #include "AutoLight.cginc"

             fixed4 _Diffuse;
             fixed4 _Specular;
             float _Gloss;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float3 worldNormal : TEXCOORD0;
                 float3 worldPos : TEXCOORD1;
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.worldNormal = UnityObjectToWorldNormal(v.normal);

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 worldNormal = normalize(i.worldNormal);

                 // 我们首先判断当前处理的逐像素光源的类型,这是通过使用#ifdef指令判断是否定义了
                 // USING_DIRECTIONAL_LIGHT来得到的.如果当前前向渲染Pass处理的光源类型是平行光,
                 // 那么Unity的底层渲染引擎就会定义USING_DIRECTIONAL_LIGHT.如果判断得知是平行光的话,
                 // 光源方向可以直接由_WorldSpaceLightPos0.xyz得到;如果是点光源或聚光灯,那么
                 // _WorldSpaceLightPos0.xyz表示的世界空间下的光源位置,而想要得到光源的方向的话,
                 // 我们就需要用这个位置减去世界空间下的顶点位置
                 #ifdef USING_DIRECTIONAL_LIGHT
                     fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                 #else
                     fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
                 #endif

                 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(, dot(worldNormal, worldLightDir));

                 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                 fixed3 halfDir = normalize(worldLightDir + viewDir);
                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(, dot(worldNormal, halfDir)), _Gloss);

                 // 我们同样通过判断是否定义了USING_DIRECTIONAL_LIGHT来决定当前处理的光源类型.
                 // 如果是平行光的话,衰减值为1.0.如果是其他光源类型,那么处理更复杂一些.尽管我们
                 // 可以使用数学表达式来计算给定点相对于点光源和聚光灯的衰减,但这些计算往往涉及开根号
                 // 除法等计算量相对较大的操作,因此Unity选择了使用一张纹理作为查找表(Lookup Table,LUT)
                 // 以在片元着色器中得到光源的衰减.我们首先得到光源空间下的坐标,然后使用该坐标对衰减纹理进行采样得到衰减值
                 #ifdef USING_DIRECTIONAL_LIGHT
                     fixed atten = 1.0;
                 #else
                     #if defined (POINT)
                         float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, )).xyz;
                         fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
                     #elif defined (SPOT)
                         float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, ));
                         ) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
                     #else
                         fixed atten = 1.0;
                     #endif
                 #endif

                 return fixed4((diffuse + specular) * atten, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Specular"
 }

ForwardRendering

 Shader "Unity Shader Book/Chapter 9/SimplestShadow" {
     SubShader{
         Pass{
             Tags { "LightMode"="ShadowCaster" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag
             #pragma multi_compile_shadowcaster
             #include "UnityCG.cginc"

             struct v2f{
                 V2F_SHADOW_CASTER;
             };

             v2f vert(appdata_base v){
                 v2f o;
                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
                 return o;
             }

             float4 frag(v2f i):SV_Target{
                 SHADOW_CASTER_FRAGMENT(i)
             }

             ENDCG
         }
     }
 }

SimplestShadow

第10章 高级纹理

 Shader "Unity Shader Book/Chapter 10/Reflection" {
     Properties {
         _Color (, , , )
         _ReflectColor (, , , )
         _ReflectAmount (, )) =
         _Cubemap ("Reflection Cubemap", Cube) = "_Skybox" {}
     }
     SubShader {
         Tags { "RenderType"="Opaque" "Queue"="Geometry"}

         Pass {
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma multi_compile_fwdbase

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"
             #include "AutoLight.cginc"

             fixed4 _Color;
             fixed4 _ReflectColor;
             fixed _ReflectAmount;
             samplerCUBE _Cubemap;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float3 worldPos : TEXCOORD0;
                 fixed3 worldNormal : TEXCOORD1;
                 fixed3 worldViewDir : TEXCOORD2;
                 fixed3 worldRefl : TEXCOORD3;
                 SHADOW_COORDS()
             };

             v2f vert(a2v v) {
                 v2f o;

                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.worldNormal = UnityObjectToWorldNormal(v.normal);

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                 o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);

                 // Compute the reflect dir in world space
                 o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);

                 TRANSFER_SHADOW(o);

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 worldNormal = normalize(i.worldNormal);
                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                 fixed3 worldViewDir = normalize(i.worldViewDir);        

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                 fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(, dot(worldNormal, worldLightDir));

                 // Use the reflect dir in world space to access the cubemap
                 fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb * _ReflectColor.rgb;

                 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

                 // Mix the diffuse color with the reflected color
                 fixed3 color = ambient + lerp(diffuse, reflection, _ReflectAmount) * atten;

                 return fixed4(color, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Reflective/VertexLit"
 }

Reflection

 Shader "Unity Shader Book/Chapter 10/Refraction" {
     Properties {
         _Color (, , , )
         _RefractColor (, , , )
         _RefractAmount (, )) =
         _RefractRatio ()) = 0.5
         _Cubemap ("Refraction Cubemap", Cube) = "_Skybox" {}
     }
     SubShader {
         Tags { "RenderType"="Opaque" "Queue"="Geometry"}

         Pass {
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma multi_compile_fwdbase    

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"
             #include "AutoLight.cginc"

             fixed4 _Color;
             fixed4 _RefractColor;
             float _RefractAmount;
             fixed _RefractRatio;
             samplerCUBE _Cubemap;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float3 worldPos : TEXCOORD0;
                 fixed3 worldNormal : TEXCOORD1;
                 fixed3 worldViewDir : TEXCOORD2;
                 fixed3 worldRefr : TEXCOORD3;
                 SHADOW_COORDS()
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.worldNormal = UnityObjectToWorldNormal(v.normal);

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                 o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);

                 // Compute the refract dir in world space
                 o.worldRefr = refract(-normalize(o.worldViewDir), normalize(o.worldNormal), _RefractRatio);

                 TRANSFER_SHADOW(o);

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 worldNormal = normalize(i.worldNormal);
                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                 fixed3 worldViewDir = normalize(i.worldViewDir);

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                 fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(, dot(worldNormal, worldLightDir));

                 // Use the refract dir in world space to access the cubemap
                 fixed3 refraction = texCUBE(_Cubemap, i.worldRefr).rgb * _RefractColor.rgb;

                 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

                 // Mix the diffuse color with the refract color
                 fixed3 color = ambient + lerp(diffuse, refraction, _RefractAmount) * atten;

                 return fixed4(color, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Reflective/VertexLit"
 }

Refraction

 Shader "Unity Shader Book/Chapter 10/Fresnel" {
     Properties {
         _Color (, , , )
         _FresnelScale (, )) = 0.5
         _Cubemap ("Reflection Cubemap", Cube) = "_Skybox" {}
     }
     SubShader {
         Tags { "RenderType"="Opaque" "Queue"="Geometry"}

         Pass {
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma multi_compile_fwdbase

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"
             #include "AutoLight.cginc"

             fixed4 _Color;
             fixed _FresnelScale;
             samplerCUBE _Cubemap;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float3 worldPos : TEXCOORD0;
                   fixed3 worldNormal : TEXCOORD1;
                   fixed3 worldViewDir : TEXCOORD2;
                   fixed3 worldRefl : TEXCOORD3;
                   SHADOW_COORDS()
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.worldNormal = UnityObjectToWorldNormal(v.normal);

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                 o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);

                 o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);

                 TRANSFER_SHADOW(o);

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 worldNormal = normalize(i.worldNormal);
                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                 fixed3 worldViewDir = normalize(i.worldViewDir);

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

                 fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb;

                  - _FresnelScale) * pow( - dot(worldViewDir, worldNormal), );

                 fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(, dot(worldNormal, worldLightDir));

                 fixed3 color = ambient + lerp(diffuse, reflection, saturate(fresnel)) * atten;

                 return fixed4(color, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Reflective/VertexLit"
 }

Fresnel

 Shader "Unity Shader Book/Chapter 10/Mirror"{
     Properties{
         _MainTex("Main Tex",2D)="white"{}
     }
     SubShader{
         Tags { "RenderType"="Opaque" "Queue"="Geometry" }
         Pass{
             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             sampler2D _MainTex;

             struct a2v{
                 float4 vertex:POSITION;
                 float3 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float2 uv:TEXCOORD0;
             };

             v2f vert(a2v v){
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);
                 o.uv = v.texcoord;

                 // Mirror needs to flip x
                 o.uv.x =  - o.uv.x;

                 return o;
             }

             fixed4 frag(v2f i):SV_Target{
                 return tex2D(_MainTex,i.uv);
             }

             ENDCG
         }
     }
     Fallback Off
 }

Mirror

 Shader "Unity Shader Book/Chapter 10/Glass Refraction" {
     Properties {
         _MainTex ("Main Tex", 2D) = "white" {}
         _BumpMap ("Normal Map", 2D) = "bump" {}
         _Cubemap ("Environment Cubemap", Cube) = "_Skybox" {}
         _Distortion (, )) =
         _RefractAmount ("Refract Amount", Range(0.0, 1.0)) = 1.0
     }
     SubShader {
         // We must be transparent, so other objects are drawn before this one.
         Tags { "Queue"="Transparent" "RenderType"="Opaque" }

         // This pass grabs the screen behind the object into a texture.
         // We can access the result in the next pass as _RefractionTex
         GrabPass { "_RefractionTex" }

         Pass {
             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "UnityCG.cginc"

             sampler2D _MainTex;
             float4 _MainTex_ST;
             sampler2D _BumpMap;
             float4 _BumpMap_ST;
             samplerCUBE _Cubemap;
             float _Distortion;
             fixed _RefractAmount;
             sampler2D _RefractionTex;
             float4 _RefractionTex_TexelSize;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 tangent : TANGENT;
                 float2 texcoord: TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float4 scrPos : TEXCOORD0;
                 float4 uv : TEXCOORD1;
                 float4 TtoW0 : TEXCOORD2;
                 float4 TtoW1 : TEXCOORD3;
                 float4 TtoW2 : TEXCOORD4;
             };

             v2f vert (a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.scrPos = ComputeGrabScreenPos(o.pos);

                 o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                 o.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);

                 float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                 fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                 fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                 fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 

                 o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                 o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                 o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);  

                 return o;
             }

             fixed4 frag (v2f i) : SV_Target {
                 float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
                 fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));

                 // Get the normal in tangent space
                 fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));    

                 // Compute the offset in tangent space
                 float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;
                 i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;
                 fixed3 refrCol = tex2D(_RefractionTex, i.scrPos.xy/i.scrPos.w).rgb;

                 // Convert the normal to world space
                 bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
                 fixed3 reflDir = reflect(-worldViewDir, bump);
                 fixed4 texColor = tex2D(_MainTex, i.uv.xy);
                 fixed3 reflCol = texCUBE(_Cubemap, reflDir).rgb * texColor.rgb;

                 fixed3 finalColor = reflCol * ( - _RefractAmount) + refrCol * _RefractAmount;

                 );
             }

             ENDCG
         }
     }

     FallBack "Diffuse"
 }

Glass Refraction

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;

 [ExecuteInEditMode]
 public class ProceduralTextureGeneration : MonoBehaviour {

     public Material material = null;

     #region Material properties
     [SerializeField, SetProperty("textureWidth")]
     ;
     public int textureWidth {
         get {
             return m_textureWidth;
         }
         set {
             m_textureWidth = value;
             _UpdateMaterial();
         }
     }

     [SerializeField, SetProperty("backgroundColor")]
     private Color m_backgroundColor = Color.white;
     public Color backgroundColor {
         get {
             return m_backgroundColor;
         }
         set {
             m_backgroundColor = value;
             _UpdateMaterial();
         }
     }

     [SerializeField, SetProperty("circleColor")]
     private Color m_circleColor = Color.yellow;
     public Color circleColor {
         get {
             return m_circleColor;
         }
         set {
             m_circleColor = value;
             _UpdateMaterial();
         }
     }

     [SerializeField, SetProperty("blurFactor")]
     private float m_blurFactor = 2.0f;
     public float blurFactor {
         get {
             return m_blurFactor;
         }
         set {
             m_blurFactor = value;
             _UpdateMaterial();
         }
     }
     #endregion

     private Texture2D m_generatedTexture = null;

     // Use this for initialization
     void Start () {
         if (material == null) {
             Renderer renderer = gameObject.GetComponent<Renderer>();
             if (renderer == null) {
                 Debug.LogWarning("Cannot find a renderer.");
                 return;
             }

             material = renderer.sharedMaterial;
         }

         _UpdateMaterial();
     }

     private void _UpdateMaterial() {
         if (material != null) {
             m_generatedTexture = _GenerateProceduralTexture();
             material.SetTexture("_MainTex", m_generatedTexture);
         }
     }

     private Color _MixColor(Color color0, Color color1, float mixFactor) {
         Color mixColor = Color.white;
         mixColor.r = Mathf.Lerp(color0.r, color1.r, mixFactor);
         mixColor.g = Mathf.Lerp(color0.g, color1.g, mixFactor);
         mixColor.b = Mathf.Lerp(color0.b, color1.b, mixFactor);
         mixColor.a = Mathf.Lerp(color0.a, color1.a, mixFactor);
         return mixColor;
     }

     private Texture2D _GenerateProceduralTexture() {
         Texture2D proceduralTexture = new Texture2D(textureWidth, textureWidth);

         // The interval between circles
         float circleInterval = textureWidth / 4.0f;
         // The radius of circles
         float radius = textureWidth / 10.0f;
         // The blur factor
         float edgeBlur = 1.0f / blurFactor;

         ; w < textureWidth; w++) {
             ; h < textureWidth; h++) {
                 // Initalize the pixel with background color
                 Color pixel = backgroundColor;

                 // Draw nine circles one by one
                 ; i < ; i++) {
                     ; j < ; j++) {
                         // Compute the center of current circle
                         Vector2 circleCenter = ), circleInterval * (j + ));

                         // Compute the distance between the pixel and the center
                         float dist = Vector2.Distance(new Vector2(w, h), circleCenter) - radius;

                         // Blur the edge of the circle
                         Color color = _MixColor(circleColor, new Color(pixel.r, pixel.g, pixel.b, 0.0f), Mathf.SmoothStep(0f, 1.0f, dist * edgeBlur));

                         // Mix the current color with the previous color
                         pixel = _MixColor(pixel, color, color.a);
                     }
                 }

                 proceduralTexture.SetPixel(w, h, pixel);
             }
         }

         proceduralTexture.Apply();

         return proceduralTexture;
     }
 }

ProceduralTextureGeneration

 Shader "Unity Shader Book/Chapter 8/Single Texture" {
     Properties {
         _Color (, , , )
         _MainTex ("Main Tex", 2D) = "white" {}
         _Specular (, , , )
         _Gloss ()) =
     }
     SubShader {
         Pass {
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             fixed4 _Specular;
             float _Gloss;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float3 worldNormal : TEXCOORD0;
                 float3 worldPos : TEXCOORD1;
                 float2 uv : TEXCOORD2;
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.worldNormal = UnityObjectToWorldNormal(v.normal);

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                 o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                 // Or just call the built-in function
 //                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 worldNormal = normalize(i.worldNormal);
                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                 // Use the texture to sample the diffuse color
                 fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                 fixed3 diffuse = _LightColor0.rgb * albedo * max(, dot(worldNormal, worldLightDir));

                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                 fixed3 halfDir = normalize(worldLightDir + viewDir);
                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(, dot(worldNormal, halfDir)), _Gloss);

                 return fixed4(ambient + diffuse + specular, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Specular"
 }

Single Texture

第11章 让画面动起来

表11.1  Unity内置的时间变量
名称 类型 描述
_Time float4 t是自该场景加载开始所经过的时间,4个分量的值分别是(t/20,t,2t,3t)
_SinTime float4 t是时间的正弦值,4个分量的值分别是(t/8,t/4,t/2,t)
_CosTime float4 t是时间的余弦值,4个分量的值分别是(t/8,t/4,t/2,t)
unity_DeltaTime float4 dt是时间增量,4个分量的值分别是(dt,1/dt,smoothDt,1/smoothDt)

 Shader "Unity Shader Book/Chapter 11/ImageSequenceAnimation"{
     Properties{
         _Color(,,,)
         _MainTex("Main Tex",2D)="white"{}
         _HorizontalAmount(
         _VerticalAmount(
         _Speed(,))=
     }
     SubShader{
         Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }

         Pass{
             Tags { "LightMode"="ForwardBase" }

             ZWrite Off
             Blend SrcAlpha OneMinusSrcAlpha

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "UnityCG.cginc"

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             float _HorizontalAmount;
             float _VerticalAmount;
             float _Speed;

             struct a2v{
                 float4 vertex:POSITION;
                 float2 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float2 uv:TEXCOORD0;
             };

             v2f vert(a2v v){
                 v2f f;
                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 float time = floor(_Time.y * _Speed);
                 float row = floor(time / _HorizontalAmount);
                 float column = time - row * _HorizontalAmount;

                 //half2 uv = float2(f.uv.x / _HorizontalAmount,f.uv.y / _VerticalAmount);
                 //uv.x += column/_HorizontalAmount;
                 //uv.y -= row/_VerticalAmount;
                 half2 uv = f.uv + half2(column,-row);
                 uv.x /= _HorizontalAmount;
                 uv.y /= _VerticalAmount;

                 fixed4 c = tex2D(_MainTex,uv);
                 c.xyz *= _Color;

                 return c;
             }

             ENDCG
         }
     }
     Fallback "Transparent/VertexLit"
 }

ImageSequenceAnimation

 Shader "Unity Shader Book/Chapter 11/Scrolling Background"{
     Properties{
         _MainTex("Base Layer(RGB)",2D)="white"{}
         _DetailTex("2nd Layer(RGB)",2D)="white"{}
         _ScrollX(
         _Scroll2X(    }
     SubShader{
         Tags { "RenderType"="Opaque" "Queue"="Geometry" }
         Pass{
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "UnityCG.cginc"

             sampler2D _MainTex;
             float4 _MainTex_ST;
             sampler2D _DetailTex;
             float4 _DetailTex_ST;

             float _ScrollX;
             float _Scroll2X;
             float _Multiplier;

             struct a2v{
                 float4 vertex:POSITION;
                 float4 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float4 uv:TEXCOORD0;
             };

             v2f vert(a2v v){
                 v2f f;
                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.uv.xy = v.texcoord.xy + float2(_ScrollX,0.0) * _Time.y;
                 f.uv.zw = v.texcoord.xy + float2(_Scroll2X,0.0) * _Time.y;

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 fixed4 firstLayer = tex2D(_MainTex,f.uv.xy);
                 fixed4 secondLayer = tex2D(_DetailTex,f.uv.zw);

                 // 混合
                 fixed4 c = lerp(firstLayer,secondLayer,secondLayer.a);

                 return c;
             }

             ENDCG
         }
     }
     Fallback "VertexLit"
 }

Scrolling Background

 Shader "Unity Shader Book/Chapter 11/Water"{
     Properties{
         _MainTex("Main Tex",2D)="white"{}
         _Color(,,,)
         _Magnitude(
         _Frequency(
         _InvWaveLength(
         _Speed("Speed",Float)=0.5
     }
     SubShader{
         // Need to disable batching because of the vertex animation
         Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True" }

         Pass{
             Tags { "LightMode"="ForwardBase" }

             ZWrite Off
             Blend SrcAlpha OneMinusSrcAlpha
             Cull Off

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "UnityCG.cginc"

             sampler2D _MainTex;
             float4 _MainTex_ST;

             float4 _Color;
             float _Magnitude;
             float _Frequency;
             float _InvWaveLength;
             float _Speed;

             struct a2v{
                 float4 vertex:POSITION;
                 float4 texcoord:TEXCOORD0;
             };
             struct v2f{
                 float4 pos:SV_POSITION;
                 float2 uv:TEXCOORD0;
             };

             v2f vert(a2v v){
                 v2f f;

                 float4 offset;
                 offset.yzw = float3(0.0,0.0,0.0);
                 offset.x = sin(_Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;

                 f.pos = UnityObjectToClipPos(v.vertex + offset);

                 f.uv = v.texcoord.xy;
                 //f.uv += float2(0.0,_Time.y * _Speed);

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 fixed4 c = tex2D(_MainTex,f.uv);

                 //c.xyz *= _Color.xyz;

                 return c;
             }

             ENDCG
         }
     }
     Fallback "Transparent/VertexLit"
 }

Water

 Shader "Unity Shader Book/Chapter 11/Billboard" {
     Properties {
         _MainTex ("Main Tex", 2D) = "white" {}
         _Color (, , , )
         _VerticalBillboarding (, )) =
     }
     SubShader {
         // Need to disable batching because of the vertex animation
         Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}

         Pass {
             Tags { "LightMode"="ForwardBase" }

             ZWrite Off
             Blend SrcAlpha OneMinusSrcAlpha
             Cull Off

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "Lighting.cginc"

             sampler2D _MainTex;
             float4 _MainTex_ST;
             fixed4 _Color;
             fixed _VerticalBillboarding;

             struct a2v {
                 float4 vertex : POSITION;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float2 uv : TEXCOORD0;
             };

             v2f vert (a2v v) {
                 v2f o;

                 // Suppose the center in object space is fixed
                 float3 center = float3(, , );
                 float3 viewer = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, ));

                 float3 normalDir = viewer - center;
                 // If _VerticalBillboarding equals 1, we use the desired view dir as the normal dir
                 // Which means the normal dir is fixed
                 // Or if _VerticalBillboarding equals 0, the y of normal is 0
                 // Which means the up dir is fixed
                 normalDir.y =normalDir.y * _VerticalBillboarding;
                 normalDir = normalize(normalDir);
                 // Get the approximate up dir
                 // If normal dir is already towards up, then the up dir is towards front
                 float3 upDir = abs(normalDir.y) > , , ) : float3(, , );
                 float3 rightDir = normalize(cross(upDir, normalDir));
                 upDir = normalize(cross(normalDir, rightDir));

                 // Use the three vectors to rotate the quad
                 float3 centerOffs = v.vertex.xyz - center;
                 float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;

                 o.pos = UnityObjectToClipPos(float4(localPos, ));
                 o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);

                 return o;
             }

             fixed4 frag (v2f i) : SV_Target {
                 fixed4 c = tex2D (_MainTex, i.uv);
                 c.rgb *= _Color.rgb;

                 return c;
             }

             ENDCG
         }
     }
     FallBack "Transparent/VertexLit"
 }

Billboard

 Shader "Unity Shaders Book/Chapter 11/Vertex Animation With Shadow" {
     Properties {
         _MainTex ("Main Tex", 2D) = "white" {}
         _Color (, , , )
         _Magnitude (
          _Frequency (
          _InvWaveLength (
          _Speed ("Speed", Float) = 0.5
     }
     SubShader {
         // Need to disable batching because of the vertex animation
         Tags {"DisableBatching"="True"}

         Pass {
             Tags { "LightMode"="ForwardBase" }

             Cull Off

             CGPROGRAM
             #pragma vertex vert
             #pragma fragment frag

             #include "UnityCG.cginc" 

             sampler2D _MainTex;
             float4 _MainTex_ST;
             fixed4 _Color;
             float _Magnitude;
             float _Frequency;
             float _InvWaveLength;
             float _Speed;

             struct a2v {
                 float4 vertex : POSITION;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float2 uv : TEXCOORD0;
             };

             v2f vert(a2v v) {
                 v2f o;

                 float4 offset;
                 offset.yzw = float3(0.0, 0.0, 0.0);
                 offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
                 o.pos = UnityObjectToClipPos(v.vertex + offset);

                 o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                 o.uv +=  float2(0.0, _Time.y * _Speed);

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed4 c = tex2D(_MainTex, i.uv);
                 c.rgb *= _Color.rgb;

                 return c;
             } 

             ENDCG
         }

         // Pass to render object as a shadow caster
         Pass {
             Tags { "LightMode" = "ShadowCaster" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #pragma multi_compile_shadowcaster

             #include "UnityCG.cginc"

             float _Magnitude;
             float _Frequency;
             float _InvWaveLength;
             float _Speed;

             struct v2f {
                 V2F_SHADOW_CASTER;
             };

             v2f vert(appdata_base v) {
                 v2f o;

                 float4 offset;
                 offset.yzw = float3(0.0, 0.0, 0.0);
                 offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
                 v.vertex = v.vertex + offset;

                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 SHADOW_CASTER_FRAGMENT(i)
             }
             ENDCG
         }
     }
     FallBack "VertexLit"
 }

Vertex Animation With Shadow

第4篇 高级篇

第12章 屏幕后处理效果

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;

 [ExecuteInEditMode]
 [RequireComponent(typeof(Camera))]
 public class PostEffectsBase : MonoBehaviour {

     // Called when start
     protected void CheckResources() {
         bool isSupported = CheckSupport();

         if (isSupported == false) {
             NotSupported();
         }
     }

     // Called in CheckResources to check support on this platform
     protected bool CheckSupport() {
         if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false) {
             Debug.LogWarning("This platform does not support image effects or render textures.");
             return false;
         }

         return true;
     }

     // Called when the platform doesn't support this effect
     protected void NotSupported() {
         enabled = false;
     }

     protected void Start() {
         CheckResources();
     }

     // Called when need to create the material used by this effect
     protected Material CheckShaderAndCreateMaterial(Shader shader, Material material) {
         if (shader == null) {
             return null;
         }

         if (shader.isSupported && material && material.shader == shader)
             return material;

         if (!shader.isSupported) {
             return null;
         } else {
             material = new Material(shader);
             material.hideFlags = HideFlags.DontSave;
             if (material)
                 return material;
             else
                 return null;
         }
     }
 }

PostEffectsBase

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;

 public class BrightnessSaturationAndContrast : PostEffectsBase {

     public Shader m_bscShader;

     private Material m_bscMaterial;

     public Material Material {
         get {
             m_bscMaterial = CheckShaderAndCreateMaterial(m_bscShader, m_bscMaterial);
             return m_bscMaterial;
         }
     }

     [Range(0.0f,3.0f)]
     public float Brightness = 1.0f;
     [Range(0.0f,3.0f)]
     public float Saturation = 1.0f;
     [Range(0.0f,3.0f)]
     public float Contrast = 1.0f;

     private void OnRenderImage(RenderTexture source, RenderTexture destination) {
         if(Material != null) {
             Material.SetFloat("_Brightness", Brightness);
             Material.SetFloat("_Saturation", Saturation);
             Material.SetFloat("_Contrast", Contrast);

             Graphics.Blit(source, destination, Material);
         } else {
             Graphics.Blit(source, destination);
         }
     }
 }

BrightnessSaturationAndContrast

 Shader "Unity Shader Book/Chapter 12/Brightness Saturation And Contrast"{
     Properties{
         _MainTex("Base (RGB)",2D)="white"{}
         _Brightness(
         _Saturation(
         _Contrast(
     }
     SubShader{
         Pass{
             ZTest Always
             Cull Off
             ZWrite Off

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "UnityCG.cginc"

             sampler2D _MainTex;
             half _Brightness;
             half _Saturation;
             half _Contrast;

             struct v2f{
                 float4 pos:SV_POSITION;
                 half2 uv:TEXCOORD0;
             };

             v2f vert(appdata_img v){
                 v2f f;

                 f.pos = UnityObjectToClipPos(v.vertex);
                 f.uv = v.texcoord;

                 return f;
             }

             fixed4 frag(v2f f):SV_Target{
                 fixed4 renderTex = tex2D(_MainTex,f.uv);

                 // Apply birghtness
                 fixed3 finalColor = renderTex.xyz * _Brightness;

                 // Apply saturation
                 fixed luminance = 0.2125 * renderTex.x + 0.7154 * renderTex.y + 0.0721 * renderTex.z;
                 fixed3 luminanceColor = fixed3(luminance,luminance,luminance);
                 finalColor = lerp(luminanceColor,finalColor,_Saturation);

                 // Apply Contrast
                 fixed3 avgColor = fixed3(0.5,0.5,0.5);
                 finalColor = lerp(avgColor,finalColor,_Contrast);

                 return fixed4(finalColor,renderTex.w);
             }

             ENDCG
         }
     }
     Fallback Off
 }

BrightnessSaturationAndContrast

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;

 public class EdgeDetection : PostEffectsBase {

     public Shader edgeDetectShader;
     private Material edgeDetectMaterial = null;
     public Material Material {
         get {
             edgeDetectMaterial = CheckShaderAndCreateMaterial(edgeDetectShader, edgeDetectMaterial);
             return edgeDetectMaterial;
         }
     }

     [Range(0.0f,1.0f)]
     public float edgesOnly = 0.0f;

     public Color edgeColor = Color.black;

     public Color backgroundColor = Color.white;

     void OnRenderImage(RenderTexture src,RenderTexture dest) {
         if(Material != null) {
             Material.SetFloat("_EdgeOnly", edgesOnly);
             Material.SetColor("_EdgeColor", edgeColor);
             Material.SetColor("_BackgroundColor", backgroundColor);

             Graphics.Blit(src, dest, Material);
         } else {
             Graphics.Blit(src, dest);
         }
     }
 }

EdgeDetection

 Shader "Unity Shader Book/Chapter 12/Edge Detection"{
     Properties {
         _MainTex ("Base (RGB)", 2D) = "white" {}
         _EdgeOnly ("Edge Only", Float) = 1.0
         _EdgeColor (, , , )
         _BackgroundColor (, , , )
     }
     SubShader {
         Pass {
             ZTest Always Cull Off ZWrite Off

             CGPROGRAM

             #include "UnityCG.cginc"

             #pragma vertex vert
             #pragma fragment fragSobel

             sampler2D _MainTex;
             uniform half4 _MainTex_TexelSize;
             fixed _EdgeOnly;
             fixed4 _EdgeColor;
             fixed4 _BackgroundColor;

             struct v2f {
                 float4 pos : SV_POSITION;
                 half2 uv[] : TEXCOORD0;
             };

             v2f vert(appdata_img v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 half2 uv = v.texcoord;

                 o.uv[] = uv + _MainTex_TexelSize.xy * half2(-, -);
                 o.uv[] = uv + _MainTex_TexelSize.xy * half2(, -);
                 o.uv[] = uv + _MainTex_TexelSize.xy * half2(, -);
                 o.uv[] = uv + _MainTex_TexelSize.xy * half2(-, );
                 o.uv[] = uv + _MainTex_TexelSize.xy * half2(, );
                 o.uv[] = uv + _MainTex_TexelSize.xy * half2(, );
                 o.uv[] = uv + _MainTex_TexelSize.xy * half2(-, );
                 o.uv[] = uv + _MainTex_TexelSize.xy * half2(, );
                 o.uv[] = uv + _MainTex_TexelSize.xy * half2(, );

                 return o;
             }

             fixed luminance(fixed4 color) {
                 return  0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
             }

             half Sobel(v2f i) {
                 ] = {-,  ,  ,
                                         -,  ,  ,
                                         -,  ,  };
                 ] = {-, -, -,
                                         ,  ,  ,
                                         ,  ,  };        

                 half texColor;
                 half edgeX = ;
                 half edgeY = ;
                 ; it < ; it++) {
                     texColor = luminance(tex2D(_MainTex, i.uv[it]));
                     edgeX += texColor * Gx[it];
                     edgeY += texColor * Gy[it];
                 }

                 half edge =  - abs(edgeX) - abs(edgeY);

                 return edge;
             }

             fixed4 fragSobel(v2f i) : SV_Target {
                 half edge = Sobel(i);

                 fixed4 withEdgeColor = lerp(_EdgeColor, tex2D(_MainTex, i.uv[]), edge);
                 fixed4 onlyEdgeColor = lerp(_EdgeColor, _BackgroundColor, edge);
                 return lerp(withEdgeColor, onlyEdgeColor, _EdgeOnly);
              }

             ENDCG
         }
     }
     FallBack Off
 }

EdgeDetection

 using UnityEngine;
 using System.Collections;

 public class GaussianBlur : PostEffectsBase {

     public Shader gaussianBlurShader;
     private Material gaussianBlurMaterial = null;

     public Material material {
         get {
             gaussianBlurMaterial = CheckShaderAndCreateMaterial(gaussianBlurShader, gaussianBlurMaterial);
             return gaussianBlurMaterial;
         }
     }

     // Blur iterations - larger number means more blur.
     [Range(, )]
     ;

     // Blur spread for each iteration - larger value means more blur
     [Range(0.2f, 3.0f)]
     public float blurSpread = 0.6f;

     [Range(, )]
     ;

     /// 1st edition: just apply blur
 //    void OnRenderImage(RenderTexture src, RenderTexture dest) {
 //        if (material != null) {
 //            int rtW = src.width;
 //            int rtH = src.height;
 //            RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);
 //
 //            // Render the vertical pass
 //            Graphics.Blit(src, buffer, material, 0);
 //            // Render the horizontal pass
 //            Graphics.Blit(buffer, dest, material, 1);
 //
 //            RenderTexture.ReleaseTemporary(buffer);
 //        } else {
 //            Graphics.Blit(src, dest);
 //        }
 //    } 

     /// 2nd edition: scale the render texture
 //    void OnRenderImage (RenderTexture src, RenderTexture dest) {
 //        if (material != null) {
 //            int rtW = src.width/downSample;
 //            int rtH = src.height/downSample;
 //            RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);
 //            buffer.filterMode = FilterMode.Bilinear;
 //
 //            // Render the vertical pass
 //            Graphics.Blit(src, buffer, material, 0);
 //            // Render the horizontal pass
 //            Graphics.Blit(buffer, dest, material, 1);
 //
 //            RenderTexture.ReleaseTemporary(buffer);
 //        } else {
 //            Graphics.Blit(src, dest);
 //        }
 //    }

     /// 3rd edition: use iterations for larger blur
     void OnRenderImage (RenderTexture src, RenderTexture dest) {
         if (material != null) {
             int rtW = src.width/downSample;
             int rtH = src.height/downSample;

             RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, );
             buffer0.filterMode = FilterMode.Bilinear;

             Graphics.Blit(src, buffer0);

             ; i < iterations; i++) {
                 material.SetFloat("_BlurSize", 1.0f + i * blurSpread);

                 RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, );

                 // Render the vertical pass
                 Graphics.Blit(buffer0, buffer1, material, );

                 RenderTexture.ReleaseTemporary(buffer0);
                 buffer0 = buffer1;
                 buffer1 = RenderTexture.GetTemporary(rtW, rtH, );

                 // Render the horizontal pass
                 Graphics.Blit(buffer0, buffer1, material, );

                 RenderTexture.ReleaseTemporary(buffer0);
                 buffer0 = buffer1;
             }

             Graphics.Blit(buffer0, dest);
             RenderTexture.ReleaseTemporary(buffer0);
         } else {
             Graphics.Blit(src, dest);
         }
     }
 }

GaussianBlur

 Shader "Unity Shader Book/Chapter 12/Gaussian Blur" {
     Properties {
         _MainTex ("Base (RGB)", 2D) = "white" {}
         _BlurSize ("Blur Size", Float) = 1.0
     }
     SubShader {
         CGINCLUDE

         #include "UnityCG.cginc"

         sampler2D _MainTex;
         half4 _MainTex_TexelSize;
         float _BlurSize;

         struct v2f {
             float4 pos : SV_POSITION;
             half2 uv[]: TEXCOORD0;
         };

         v2f vertBlurVertical(appdata_img v) {
             v2f o;
             o.pos = UnityObjectToClipPos(v.vertex);

             half2 uv = v.texcoord;

             o.uv[] = uv;
             o.uv[] = uv + float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
             o.uv[] = uv - float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
             o.uv[] = uv + float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
             o.uv[] = uv - float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;

             return o;
         }

         v2f vertBlurHorizontal(appdata_img v) {
             v2f o;
             o.pos = UnityObjectToClipPos(v.vertex);

             half2 uv = v.texcoord;

             o.uv[] = uv;
             o.uv[] = uv + float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
             o.uv[] = uv - float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
             o.uv[] = uv + float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
             o.uv[] = uv - float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;

             return o;
         }

         fixed4 fragBlur(v2f i) : SV_Target {
             ] = {0.4026, 0.2442, 0.0545};

             fixed3 sum = tex2D(_MainTex, i.uv[]).rgb * weight[];

             ; it < ; it++) {
                 sum += tex2D(_MainTex, i.uv[it*-]).rgb * weight[it];
                 sum += tex2D(_MainTex, i.uv[it*]).rgb * weight[it];
             }

             return fixed4(sum, 1.0);
         }

         ENDCG

         ZTest Always Cull Off ZWrite Off

         Pass {
             NAME "GAUSSIAN_BLUR_VERTICAL"

             CGPROGRAM

             #pragma vertex vertBlurVertical
             #pragma fragment fragBlur

             ENDCG
         }

         Pass {
             NAME "GAUSSIAN_BLUR_HORIZONTAL"

             CGPROGRAM  

             #pragma vertex vertBlurHorizontal
             #pragma fragment fragBlur

             ENDCG
         }
     }
     FallBack "Diffuse"
 }

GaussianBlur

 using UnityEngine;
 using System.Collections;

 public class Bloom : PostEffectsBase {

     public Shader bloomShader;
     private Material bloomMaterial = null;
     public Material material {
         get {
             bloomMaterial = CheckShaderAndCreateMaterial(bloomShader, bloomMaterial);
             return bloomMaterial;
         }
     }

     // Blur iterations - larger number means more blur.
     [Range(, )]
     ;

     // Blur spread for each iteration - larger value means more blur
     [Range(0.2f, 3.0f)]
     public float blurSpread = 0.6f;

     [Range(, )]
     ;

     [Range(0.0f, 4.0f)]
     public float luminanceThreshold = 0.6f;

     void OnRenderImage (RenderTexture src, RenderTexture dest) {
         if (material != null) {
             material.SetFloat("_LuminanceThreshold", luminanceThreshold);

             int rtW = src.width/downSample;
             int rtH = src.height/downSample;

             RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, );
             buffer0.filterMode = FilterMode.Bilinear;

             Graphics.Blit(src, buffer0, material, );

             ; i < iterations; i++) {
                 material.SetFloat("_BlurSize", 1.0f + i * blurSpread);

                 RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, );

                 // Render the vertical pass
                 Graphics.Blit(buffer0, buffer1, material, );

                 RenderTexture.ReleaseTemporary(buffer0);
                 buffer0 = buffer1;
                 buffer1 = RenderTexture.GetTemporary(rtW, rtH, );

                 // Render the horizontal pass
                 Graphics.Blit(buffer0, buffer1, material, );

                 RenderTexture.ReleaseTemporary(buffer0);
                 buffer0 = buffer1;
             }

             material.SetTexture ("_Bloom", buffer0);
             Graphics.Blit (src, dest, material, );  

             RenderTexture.ReleaseTemporary(buffer0);
         } else {
             Graphics.Blit(src, dest);
         }
     }
 }

Bloom

 Shader "Unity Shader Book/Chapter 12/Bloom" {
     Properties {
         _MainTex ("Base (RGB)", 2D) = "white" {}
         _Bloom ("Bloom (RGB)", 2D) = "black" {}
         _LuminanceThreshold ("Luminance Threshold", Float) = 0.5
         _BlurSize ("Blur Size", Float) = 1.0
     }
     SubShader {
         CGINCLUDE

         #include "UnityCG.cginc"

         sampler2D _MainTex;
         half4 _MainTex_TexelSize;
         sampler2D _Bloom;
         float _LuminanceThreshold;
         float _BlurSize;

         struct v2f {
             float4 pos : SV_POSITION;
             half2 uv : TEXCOORD0;
         };    

         v2f vertExtractBright(appdata_img v) {
             v2f o;

             o.pos = UnityObjectToClipPos(v.vertex);

             o.uv = v.texcoord;

             return o;
         }

         fixed luminance(fixed4 color) {
             return  0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
         }

         fixed4 fragExtractBright(v2f i) : SV_Target {
             fixed4 c = tex2D(_MainTex, i.uv);
             fixed val = clamp(luminance(c) - _LuminanceThreshold, 0.0, 1.0);

             return c * val;
         }

         struct v2fBloom {
             float4 pos : SV_POSITION;
             half4 uv : TEXCOORD0;
         };

         v2fBloom vertBloom(appdata_img v) {
             v2fBloom o;

             o.pos = UnityObjectToClipPos (v.vertex);
             o.uv.xy = v.texcoord;
             o.uv.zw = v.texcoord;

             #if UNITY_UV_STARTS_AT_TOP
             if (_MainTex_TexelSize.y < 0.0)
                 o.uv.w = 1.0 - o.uv.w;
             #endif

             return o;
         }

         fixed4 fragBloom(v2fBloom i) : SV_Target {
             return tex2D(_MainTex, i.uv.xy) + tex2D(_Bloom, i.uv.zw);
         } 

         ENDCG

         ZTest Always Cull Off ZWrite Off

         Pass {
             CGPROGRAM
             #pragma vertex vertExtractBright
             #pragma fragment fragExtractBright  

             ENDCG
         }

         UsePass "Unity Shader Book/Chapter 12/Gaussian Blur/GAUSSIAN_BLUR_VERTICAL"

         UsePass "Unity Shader Book/Chapter 12/Gaussian Blur/GAUSSIAN_BLUR_HORIZONTAL"

         Pass {
             CGPROGRAM
             #pragma vertex vertBloom
             #pragma fragment fragBloom  

             ENDCG
         }
     }
     FallBack Off
 }

Bloom

 using UnityEngine;
 using System.Collections;

 public class MotionBlur : PostEffectsBase {

     public Shader motionBlurShader;
     private Material motionBlurMaterial = null;

     public Material material {
         get {
             motionBlurMaterial = CheckShaderAndCreateMaterial(motionBlurShader, motionBlurMaterial);
             return motionBlurMaterial;
         }
     }

     [Range(0.0f, 0.9f)]
     public float blurAmount = 0.5f;

     private RenderTexture accumulationTexture;

     void OnDisable() {
         DestroyImmediate(accumulationTexture);
     }

     void OnRenderImage (RenderTexture src, RenderTexture dest) {
         if (material != null) {
             // Create the accumulation texture
             if (accumulationTexture == null || accumulationTexture.width != src.width || accumulationTexture.height != src.height) {
                 DestroyImmediate(accumulationTexture);
                 accumulationTexture = );
                 accumulationTexture.hideFlags = HideFlags.HideAndDontSave;
                 Graphics.Blit(src, accumulationTexture);
             }

             // We are accumulating motion over frames without clear/discard
             // by design, so silence any performance warnings from Unity
             accumulationTexture.MarkRestoreExpected();

             material.SetFloat("_BlurAmount", 1.0f - blurAmount);

             Graphics.Blit (src, accumulationTexture, material);
             Graphics.Blit (accumulationTexture, dest);
         } else {
             Graphics.Blit(src, dest);
         }
     }
 }

MotionBlur

 Shader "Unity Shader Book/Chapter 12/Motion Blur" {
     Properties {
         _MainTex ("Base (RGB)", 2D) = "white" {}
         _BlurAmount ("Blur Amount", Float) = 1.0
     }
     SubShader {
         CGINCLUDE

         #include "UnityCG.cginc"

         sampler2D _MainTex;
         fixed _BlurAmount;

         struct v2f {
             float4 pos : SV_POSITION;
             half2 uv : TEXCOORD0;
         };

         v2f vert(appdata_img v) {
             v2f o;

             o.pos = UnityObjectToClipPos(v.vertex);

             o.uv = v.texcoord;

             return o;
         }

         fixed4 fragRGB (v2f i) : SV_Target {
             return fixed4(tex2D(_MainTex, i.uv).rgb, _BlurAmount);
         }

         half4 fragA (v2f i) : SV_Target {
             return tex2D(_MainTex, i.uv);
         }

         ENDCG

         ZTest Always Cull Off ZWrite Off

         Pass {
             Blend SrcAlpha OneMinusSrcAlpha
             ColorMask RGB

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment fragRGB  

             ENDCG
         }

         Pass {
             Blend One Zero
             ColorMask A

             CGPROGRAM  

             #pragma vertex vert
             #pragma fragment fragA

             ENDCG
         }
     }
      FallBack Off
 }

MotionBlur

第13章 使用深度和法线纹理

第14章 非真实感渲染

 Shader "Unity Shader Book/Chapter 14/Toon Shading" {
     Properties {
         _Color (, , , )
         _MainTex ("Main Tex", 2D) = "white" {}
         _Ramp ("Ramp Texture", 2D) = "white" {}
         _Outline (, )) = 0.1
         _OutlineColor (, , , )
         _Specular (, , , )
         _SpecularScale (, 0.1)) = 0.01
     }
     SubShader {
         Tags { "RenderType"="Opaque" "Queue"="Geometry"}

         Pass {
             NAME "OUTLINE"

             Cull Front

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #include "UnityCG.cginc"

             float _Outline;
             fixed4 _OutlineColor;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
             }; 

             struct v2f {
                 float4 pos : SV_POSITION;
             };

             v2f vert (a2v v) {
                 v2f o;

                 float4 pos = mul(UNITY_MATRIX_MV, v.vertex);
                 float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
                 normal.z = -0.5;
                 pos = pos + float4(normalize(normal), ) * _Outline;
                 o.pos = mul(UNITY_MATRIX_P, pos);

                 return o;
             }

             float4 frag(v2f i) : SV_Target {
                 );
             }

             ENDCG
         }

         Pass {
             Tags { "LightMode"="ForwardBase" }

             Cull Back

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #pragma multi_compile_fwdbase

             #include "UnityCG.cginc"
             #include "Lighting.cginc"
             #include "AutoLight.cginc"
             #include "UnityShaderVariables.cginc"

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             sampler2D _Ramp;
             fixed4 _Specular;
             fixed _SpecularScale;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 texcoord : TEXCOORD0;
                 float4 tangent : TANGENT;
             }; 

             struct v2f {
                 float4 pos : POSITION;
                 float2 uv : TEXCOORD0;
                 float3 worldNormal : TEXCOORD1;
                 float3 worldPos : TEXCOORD2;
                 SHADOW_COORDS()
             };

             v2f vert (a2v v) {
                 v2f o;

                 o.pos = UnityObjectToClipPos( v.vertex);
                 o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
                 o.worldNormal  = UnityObjectToWorldNormal(v.normal);
                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                 TRANSFER_SHADOW(o);

                 return o;
             }

             float4 frag(v2f i) : SV_Target {
                 fixed3 worldNormal = normalize(i.worldNormal);
                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                 fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                 fixed3 worldHalfDir = normalize(worldLightDir + worldViewDir);

                 fixed4 c = tex2D (_MainTex, i.uv);
                 fixed3 albedo = c.rgb * _Color.rgb;

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

                 fixed diff =  dot(worldNormal, worldLightDir);
                 diff = (diff * 0.5 + 0.5) * atten;

                 fixed3 diffuse = _LightColor0.rgb * albedo * tex2D(_Ramp, float2(diff, diff)).rgb;

                 fixed spec = dot(worldNormal, worldHalfDir);
                 fixed w = fwidth(spec) * 2.0;
                 fixed3 specular = _Specular.rgb * lerp(, , smoothstep(-w, w, spec + _SpecularScale - )) * step(0.0001, _SpecularScale);

                 return fixed4(ambient + diffuse + specular, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Diffuse"
 }

ToonShading

 Shader "Unity Shader Book/Chapter 14/Hatching" {
     Properties {
         _Color (, , , )
         _TileFactor (
         _Outline (, )) = 0.1
         _Hatch0 ("Hatch 0", 2D) = "white" {}
         _Hatch1 ("Hatch 1", 2D) = "white" {}
         _Hatch2 ("Hatch 2", 2D) = "white" {}
         _Hatch3 ("Hatch 3", 2D) = "white" {}
         _Hatch4 ("Hatch 4", 2D) = "white" {}
         _Hatch5 ("Hatch 5", 2D) = "white" {}
     }

     SubShader {
         Tags { "RenderType"="Opaque" "Queue"="Geometry"}

         UsePass "Unity Shader Book/Chapter 14/Toon Shading/OUTLINE"

         Pass {
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag 

             #pragma multi_compile_fwdbase

             #include "UnityCG.cginc"
             #include "Lighting.cginc"
             #include "AutoLight.cginc"
             #include "UnityShaderVariables.cginc"

             fixed4 _Color;
             float _TileFactor;
             sampler2D _Hatch0;
             sampler2D _Hatch1;
             sampler2D _Hatch2;
             sampler2D _Hatch3;
             sampler2D _Hatch4;
             sampler2D _Hatch5;

             struct a2v {
                 float4 vertex : POSITION;
                 float4 tangent : TANGENT;
                 float3 normal : NORMAL;
                 float2 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float2 uv : TEXCOORD0;
                 fixed3 hatchWeights0 : TEXCOORD1;
                 fixed3 hatchWeights1 : TEXCOORD2;
                 float3 worldPos : TEXCOORD3;
                 SHADOW_COORDS()
             };

             v2f vert(a2v v) {
                 v2f o;

                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.uv = v.texcoord.xy * _TileFactor;

                 fixed3 worldLightDir = normalize(WorldSpaceLightDir(v.vertex));
                 fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                 , dot(worldLightDir, worldNormal));

                 o.hatchWeights0 = fixed3(, , );
                 o.hatchWeights1 = fixed3(, , );

                 float hatchFactor = diff * 7.0;

                 if (hatchFactor > 6.0) {
                     // Pure white, do nothing
                 } else if (hatchFactor > 5.0) {
                     o.hatchWeights0.x = hatchFactor - 5.0;
                 } else if (hatchFactor > 4.0) {
                     o.hatchWeights0.x = hatchFactor - 4.0;
                     o.hatchWeights0.y = 1.0 - o.hatchWeights0.x;
                 } else if (hatchFactor > 3.0) {
                     o.hatchWeights0.y = hatchFactor - 3.0;
                     o.hatchWeights0.z = 1.0 - o.hatchWeights0.y;
                 } else if (hatchFactor > 2.0) {
                     o.hatchWeights0.z = hatchFactor - 2.0;
                     o.hatchWeights1.x = 1.0 - o.hatchWeights0.z;
                 } else if (hatchFactor > 1.0) {
                     o.hatchWeights1.x = hatchFactor - 1.0;
                     o.hatchWeights1.y = 1.0 - o.hatchWeights1.x;
                 } else {
                     o.hatchWeights1.y = hatchFactor;
                     o.hatchWeights1.z = 1.0 - o.hatchWeights1.y;
                 }

                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                 TRANSFER_SHADOW(o);

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed4 hatchTex0 = tex2D(_Hatch0, i.uv) * i.hatchWeights0.x;
                 fixed4 hatchTex1 = tex2D(_Hatch1, i.uv) * i.hatchWeights0.y;
                 fixed4 hatchTex2 = tex2D(_Hatch2, i.uv) * i.hatchWeights0.z;
                 fixed4 hatchTex3 = tex2D(_Hatch3, i.uv) * i.hatchWeights1.x;
                 fixed4 hatchTex4 = tex2D(_Hatch4, i.uv) * i.hatchWeights1.y;
                 fixed4 hatchTex5 = tex2D(_Hatch5, i.uv) * i.hatchWeights1.z;
                 fixed4 whiteColor = fixed4(, , , ) * ( - i.hatchWeights0.x - i.hatchWeights0.y - i.hatchWeights0.z -
                             i.hatchWeights1.x - i.hatchWeights1.y - i.hatchWeights1.z);

                 fixed4 hatchColor = hatchTex0 + hatchTex1 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5 + whiteColor;

                 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

                 return fixed4(hatchColor.rgb * _Color.rgb * atten, 1.0);
             }

             ENDCG
         }
     }
     FallBack "Diffuse"
 }

Hatching

第15章 使用噪声

 Shader "Unity Shader Book/Chapter 15/Dissolve" {
     Properties {
         _BurnAmount ("Burn Amount", Range(0.0, 1.0)) = 0.0
         _LineWidth("Burn Line Width", Range(0.0, 0.2)) = 0.1
         _MainTex ("Base (RGB)", 2D) = "white" {}
         _BumpMap ("Normal Map", 2D) = "bump" {}
         _BurnFirstColor(, , , )
         _BurnSecondColor(, , , )
         _BurnMap("Burn Map", 2D) = "white"{}
     }
     SubShader {
         Tags { "RenderType"="Opaque" "Queue"="Geometry"}

         Pass {
             Tags { "LightMode"="ForwardBase" }

             Cull Off

             CGPROGRAM

             #include "Lighting.cginc"
             #include "AutoLight.cginc"

             #pragma multi_compile_fwdbase

             #pragma vertex vert
             #pragma fragment frag

             fixed _BurnAmount;
             fixed _LineWidth;
             sampler2D _MainTex;
             sampler2D _BumpMap;
             fixed4 _BurnFirstColor;
             fixed4 _BurnSecondColor;
             sampler2D _BurnMap;

             float4 _MainTex_ST;
             float4 _BumpMap_ST;
             float4 _BurnMap_ST;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 tangent : TANGENT;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float2 uvMainTex : TEXCOORD0;
                 float2 uvBumpMap : TEXCOORD1;
                 float2 uvBurnMap : TEXCOORD2;
                 float3 lightDir : TEXCOORD3;
                 float3 worldPos : TEXCOORD4;
                 SHADOW_COORDS()
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.uvMainTex = TRANSFORM_TEX(v.texcoord, _MainTex);
                 o.uvBumpMap = TRANSFORM_TEX(v.texcoord, _BumpMap);
                 o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);

                 TANGENT_SPACE_ROTATION;
                   o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;

                   o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                   TRANSFER_SHADOW(o);

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;

                 clip(burn.r - _BurnAmount);

                 float3 tangentLightDir = normalize(i.lightDir);
                 fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uvBumpMap));

                 fixed3 albedo = tex2D(_MainTex, i.uvMainTex).rgb;

                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                 fixed3 diffuse = _LightColor0.rgb * albedo * max(, dot(tangentNormal, tangentLightDir));

                  - smoothstep(0.0, _LineWidth, burn.r - _BurnAmount);
                 fixed3 burnColor = lerp(_BurnFirstColor, _BurnSecondColor, t);
                 burnColor = pow(burnColor, );

                 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
                 fixed3 finalColor = lerp(ambient + diffuse * atten, burnColor, t * step(0.0001, _BurnAmount));

                 );
             }

             ENDCG
         }

         // Pass to render object as a shadow caster
         Pass {
             Tags { "LightMode" = "ShadowCaster" }

             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag

             #pragma multi_compile_shadowcaster

             #include "UnityCG.cginc"

             fixed _BurnAmount;
             sampler2D _BurnMap;
             float4 _BurnMap_ST;

             struct v2f {
                 V2F_SHADOW_CASTER;
                 float2 uvBurnMap : TEXCOORD1;
             };

             v2f vert(appdata_base v) {
                 v2f o;

                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)

                 o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;

                 clip(burn.r - _BurnAmount);

                 SHADOW_CASTER_FRAGMENT(i)
             }
             ENDCG
         }
     }
     FallBack "Diffuse"
 }

Dissolve

 Shader "Unity Shader Book/Chapter 15/Water Wave" {
     Properties {
         _Color (, )
         _MainTex ("Base (RGB)", 2D) = "white" {}
         _WaveMap ("Wave Map", 2D) = "bump" {}
         _Cubemap ("Environment Cubemap", Cube) = "_Skybox" {}
         _WaveXSpeed ("Wave Horizontal Speed", Range(-0.1, 0.1)) = 0.01
         _WaveYSpeed ("Wave Vertical Speed", Range(-0.1, 0.1)) = 0.01
         _Distortion (, )) =
     }
     SubShader {
         // We must be transparent, so other objects are drawn before this one.
         Tags { "Queue"="Transparent" "RenderType"="Opaque" }

         // This pass grabs the screen behind the object into a texture.
         // We can access the result in the next pass as _RefractionTex
         GrabPass { "_RefractionTex" }

         Pass {
             Tags { "LightMode"="ForwardBase" }

             CGPROGRAM

             #include "UnityCG.cginc"
             #include "Lighting.cginc"

             #pragma multi_compile_fwdbase

             #pragma vertex vert
             #pragma fragment frag

             fixed4 _Color;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             sampler2D _WaveMap;
             float4 _WaveMap_ST;
             samplerCUBE _Cubemap;
             fixed _WaveXSpeed;
             fixed _WaveYSpeed;
             float _Distortion;
             sampler2D _RefractionTex;
             float4 _RefractionTex_TexelSize;

             struct a2v {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float4 tangent : TANGENT;
                 float4 texcoord : TEXCOORD0;
             };

             struct v2f {
                 float4 pos : SV_POSITION;
                 float4 scrPos : TEXCOORD0;
                 float4 uv : TEXCOORD1;
                 float4 TtoW0 : TEXCOORD2;
                 float4 TtoW1 : TEXCOORD3;
                 float4 TtoW2 : TEXCOORD4;
             };

             v2f vert(a2v v) {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);

                 o.scrPos = ComputeGrabScreenPos(o.pos);

                 o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                 o.uv.zw = TRANSFORM_TEX(v.texcoord, _WaveMap);

                 float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                 fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
                 fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                 fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 

                 o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                 o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                 o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);  

                 return o;
             }

             fixed4 frag(v2f i) : SV_Target {
                 float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
                 float2 speed = _Time.y * float2(_WaveXSpeed, _WaveYSpeed);

                 // Get the normal in tangent space
                 fixed3 bump1 = UnpackNormal(tex2D(_WaveMap, i.uv.zw + speed)).rgb;
                 fixed3 bump2 = UnpackNormal(tex2D(_WaveMap, i.uv.zw - speed)).rgb;
                 fixed3 bump = normalize(bump1 + bump2);

                 // Compute the offset in tangent space
                 float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;
                 i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;
                 fixed3 refrCol = tex2D( _RefractionTex, i.scrPos.xy/i.scrPos.w).rgb;

                 // Convert the normal to world space
                 bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
                 fixed4 texColor = tex2D(_MainTex, i.uv.xy + speed);
                 fixed3 reflDir = reflect(-viewDir, bump);
                 fixed3 reflCol = texCUBE(_Cubemap, reflDir).rgb * texColor.rgb * _Color.rgb;

                  - saturate(dot(viewDir, bump)), );
                 fixed3 finalColor = reflCol * fresnel + refrCol * ( - fresnel);

                 );
             }

             ENDCG
         }
     }
     // Do not cast shadow
     FallBack Off
 }

WaterWave

 using UnityEngine;
 using System.Collections;

 public class FogWithNoise : PostEffectsBase {

     public Shader fogShader;
     private Material fogMaterial = null;

     public Material material {
         get {
             fogMaterial = CheckShaderAndCreateMaterial(fogShader, fogMaterial);
             return fogMaterial;
         }
     }

     private Camera myCamera;
     public Camera camera {
         get {
             if (myCamera == null) {
                 myCamera = GetComponent<Camera>();
             }
             return myCamera;
         }
     }

     private Transform myCameraTransform;
     public Transform cameraTransform {
         get {
             if (myCameraTransform == null) {
                 myCameraTransform = camera.transform;
             }

             return myCameraTransform;
         }
     }

     [Range(0.1f, 3.0f)]
     public float fogDensity = 1.0f;

     public Color fogColor = Color.white;

     public float fogStart = 0.0f;
     public float fogEnd = 2.0f;

     public Texture noiseTexture;

     [Range(-0.5f, 0.5f)]
     public float fogXSpeed = 0.1f;

     [Range(-0.5f, 0.5f)]
     public float fogYSpeed = 0.1f;

     [Range(0.0f, 3.0f)]
     public float noiseAmount = 1.0f;

     void OnEnable() {
         GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
     }

     void OnRenderImage (RenderTexture src, RenderTexture dest) {
         if (material != null) {
             Matrix4x4 frustumCorners = Matrix4x4.identity;

             float fov = camera.fieldOfView;
             float near = camera.nearClipPlane;
             float aspect = camera.aspect;

             float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
             Vector3 toRight = cameraTransform.right * halfHeight * aspect;
             Vector3 toTop = cameraTransform.up * halfHeight;

             Vector3 topLeft = cameraTransform.forward * near + toTop - toRight;
             float scale = topLeft.magnitude / near;

             topLeft.Normalize();
             topLeft *= scale;

             Vector3 topRight = cameraTransform.forward * near + toRight + toTop;
             topRight.Normalize();
             topRight *= scale;

             Vector3 bottomLeft = cameraTransform.forward * near - toTop - toRight;
             bottomLeft.Normalize();
             bottomLeft *= scale;

             Vector3 bottomRight = cameraTransform.forward * near + toRight - toTop;
             bottomRight.Normalize();
             bottomRight *= scale;

             frustumCorners.SetRow(, bottomLeft);
             frustumCorners.SetRow(, bottomRight);
             frustumCorners.SetRow(, topRight);
             frustumCorners.SetRow(, topLeft);

             material.SetMatrix("_FrustumCornersRay", frustumCorners);

             material.SetFloat("_FogDensity", fogDensity);
             material.SetColor("_FogColor", fogColor);
             material.SetFloat("_FogStart", fogStart);
             material.SetFloat("_FogEnd", fogEnd);

             material.SetTexture("_NoiseTex", noiseTexture);
             material.SetFloat("_FogXSpeed", fogXSpeed);
             material.SetFloat("_FogYSpeed", fogYSpeed);
             material.SetFloat("_NoiseAmount", noiseAmount);

             Graphics.Blit (src, dest, material);
         } else {
             Graphics.Blit(src, dest);
         }
     }
 }

FogWithNoise

 Shader "Unity Shaders Book/Chapter 15/Fog With Noise" {
     Properties {
         _MainTex ("Base (RGB)", 2D) = "white" {}
         _FogDensity ("Fog Density", Float) = 1.0
         _FogColor (, , , )
         _FogStart ("Fog Start", Float) = 0.0
         _FogEnd ("Fog End", Float) = 1.0
         _NoiseTex ("Noise Texture", 2D) = "white" {}
         _FogXSpeed ("Fog Horizontal Speed", Float) = 0.1
         _FogYSpeed ("Fog Vertical Speed", Float) = 0.1
         _NoiseAmount (
     }
     SubShader {
         CGINCLUDE

         #include "UnityCG.cginc"

         float4x4 _FrustumCornersRay;

         sampler2D _MainTex;
         half4 _MainTex_TexelSize;
         sampler2D _CameraDepthTexture;
         half _FogDensity;
         fixed4 _FogColor;
         float _FogStart;
         float _FogEnd;
         sampler2D _NoiseTex;
         half _FogXSpeed;
         half _FogYSpeed;
         half _NoiseAmount;

         struct v2f {
             float4 pos : SV_POSITION;
             float2 uv : TEXCOORD0;
             float2 uv_depth : TEXCOORD1;
             float4 interpolatedRay : TEXCOORD2;
         };

         v2f vert(appdata_img v) {
             v2f o;
             o.pos = UnityObjectToClipPos(v.vertex);

             o.uv = v.texcoord;
             o.uv_depth = v.texcoord;

             #if UNITY_UV_STARTS_AT_TOP
             )
                 o.uv_depth.y =  - o.uv_depth.y;
             #endif

             ;
             if (v.texcoord.x < 0.5 && v.texcoord.y < 0.5) {
                 index = ;
             } else if (v.texcoord.x > 0.5 && v.texcoord.y < 0.5) {
                 index = ;
             } else if (v.texcoord.x > 0.5 && v.texcoord.y > 0.5) {
                 index = ;
             } else {
                 index = ;
             }
             #if UNITY_UV_STARTS_AT_TOP
             )
                 index =  - index;
             #endif

             o.interpolatedRay = _FrustumCornersRay[index];

             return o;
         }

         fixed4 frag(v2f i) : SV_Target {
             float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth));
             float3 worldPos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz;

             float2 speed = _Time.y * float2(_FogXSpeed, _FogYSpeed);
             float noise = (tex2D(_NoiseTex, i.uv + speed).r - 0.5) * _NoiseAmount;

             float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart);
             fogDensity = saturate(fogDensity * _FogDensity * ( + noise));

             fixed4 finalColor = tex2D(_MainTex, i.uv);
             finalColor.rgb = lerp(finalColor.rgb, _FogColor.rgb, fogDensity);

             return finalColor;
         }

         ENDCG

         Pass {
             CGPROGRAM  

             #pragma vertex vert
             #pragma fragment frag  

             ENDCG
         }
     }
     FallBack Off
 }

FogWithNoise

第16章 Unity中的渲染优化技术

表16.1
信息名称 描述
每帧的时间和FPS 在Graphic的右侧显示,给出了处理和渲染一帧所需的时间,以及FPS数目
Batches 一帧中需要进行的批处理数目
Saved by batching 合并的批处理数目,这个数字表明了批处理为我们节省了多少draw call
Tris 和 Verts 需要绘制的三角面片和顶点数目
Screen 屏幕的大小,以及它占用的内存大小
SetPass 渲染使用的Pass的数目,每个Pass都需要Unity的runtime来绑定一个新的Shader,这可能造成CPU的瓶颈
Visible Skinned Meshes 渲染的蒙皮网格的数目
Animations 播放的动画数目

第5篇 扩展篇

第17章 Unity的表面着色器探秘

表17.1
变量 描述
float3 viewDir 包含了视角方向,可用于计算边缘光照等
使用COLOR语义定义的float4变量 包含了插值后的逐顶点颜色
float4 screenPos 包含了屏幕空间的坐标,可以用于反射或屏幕特效
float3 worldPos 包含了世界空间下的位置
float3 worldRefl 包含了世界空间下的反射方向.前提是没有修改表面法线o.Normal
float3 worldRefl;INTERNAL_DATA

如果修改了表面法线o.Normal,需要使用该变量告诉Unity要基于修改后的法线计算世界空间下的反射方向.

在表面函数中,我们需要使用WorldReflectionVector(IN,o.Normal)来得到世界空间下的反射方向

float3 worldNormal 包含了世界空间的法线方向.前提是没有修改表面法线o.Normal

float3 worldNormal;INTERNAL_DATA

如果修改了表面法线o.Normal,需要使用该变量告诉Unity要基于修改后的法线计算世界空间下的法线方向.

在表面函数中,我们需要使用WorldNormalVector(IN,o.Normal)来得到世界空间下的法线方向

第18章 基于物理的渲染

表18.1
文件 描述
UnityPBSLighting.cginc 定义了表面着色器使用的标准光照函数和相关的结构体等,如LightingStandardSpecular函数和SurfaceOutputStandardSpecular结构体
UnityStandardCore.cginc

定义了Standard和Standard(Specular setup)Shader使用的顶点/片元着色器和相关的结构体,辅助函数等,如vertForwardBase,fragForwardBase,MetallicSetup,SpecularSetup

函数和VertexOutputForwardBase,FragmentCommonData结构体

UnityStandardBRDF.cginc 实现了Unity中基于物理的渲染技术,定义了BRDF1_Unity_PBS,BRDF2_Unity_PBS和BRDF3_Unity_PBS等函数,来实现不同平台下的BRDF
UnityStandardInput.cginc

声明了Standard Shader使用的相关输入,包括Shader使用的属性和顶点着色器的输入结构体VertexInput,并定义了基于这些输入的辅助函数,如TexCoords,Albedo,

Occlusion,SpecularGloss等函数

UnityStandardUtils.cginc Standard Shader 使用的一些辅助函数,将来可能会移到UnityCG.cginc文件中
UnityStandardConfig.cginc

对 Standard Shader 的相关配置,例如默认情况下关闭简化版的PBS实现(将UNITY_STANDARD_SIMPLE设为0),以及使用基于归一化的Blinn-Phong模型而非GGX模型来实现BRDF

(将UNITY_BRDF_GGX设为0)

UnityStandardMeta.cginc 定义了Standard Shader中"LightMode"为"Meta"的Pass(用于提取光照纹理和全局光照的相关信息)使用的顶点/片元着色器,以及它们使用的输入/输出结构体
UnityStandardShadow.cginc 定义了Standard Shader中"LightMode"为"ShadowCaster"的Pass(用于投射阴影)使用的顶点/片元着色器,以及它们使用的输入/输出结构体
UnityGlobalIllumination.cginc 定义了和全局光照相关的函数,如UnityGloballIllumination函数

第19章 Unity5更新了什么

第20章 还有更多内容吗

Unity Shader 入门精要学习 (冯乐乐 著)的更多相关文章

  1. Unity Shader入门精要学习笔记 - 第17章 Unity的表面着色器探秘

    转自 冯乐乐的<Unity Shader 入门精要> 2010年的Unity 3 中,Surface Shader 出现了. 表面着色器的一个例子. 我们先做如下准备工作. 1)新建一个场 ...

  2. Unity Shader入门精要学习笔记 - 第16章 Unity中的渲染优化技术

    转自冯乐乐的 <Unity Shader 入门精要> 移动平台的特点 为了尽可能一处那些隐藏的表面,减少overdraw(即一个像素被绘制多次),PowerVR芯片(通常用于ios设备和某 ...

  3. Unity Shader入门精要学习笔记 - 第15章 使用噪声

    转载自 冯乐乐的 <Unity Shader 入门精要> 消融效果 消融效果常见于游戏中的角色死亡.地图烧毁等效果.这这些效果中,消融往往从不同的区域开始,并向看似随机的方向扩张,最后整个 ...

  4. Unity Shader入门精要学习笔记 - 第14章非真实感渲染

    转载自 冯乐乐的 <Unity Shader 入门精要> 尽管游戏渲染一般都是以照相写实主义作为主要目标,但也有许多游戏使用了非真实感渲染(NPR)的方法来渲染游戏画面.非真实感渲染的一个 ...

  5. Unity Shader入门精要学习笔记 - 第11章 让画面动起来

    转自 冯乐乐的 <Unity Shader入门精要> Unity Shader 中的内置变量 动画效果往往都是把时间添加到一些变量的计算中,以便在时间变化时画面也可以随之变化.Unity ...

  6. Unity Shader入门精要学习笔记 - 第10章 高级纹理

    转载自 冯乐乐的 <Unity Shader入门精要> 立方体纹理 在图形学中,立方体纹理是环境映射的一种实现方法.环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了层 ...

  7. Unity Shader入门精要学习笔记 - 第9章 更复杂的光照

    转载自 冯乐乐的<Unity Shader入门精要> Unity 的渲染路径 在Unity里,渲染路径决定了光照是如何应该到Unity Shader 中的.因此,如果要和光源打交道,我们需 ...

  8. Unity Shader入门精要学习笔记 - 第8章 透明效果

    转载自 冯乐乐的 <Unity Shader入门精要> 透明是游戏中经常要使用的一种效果.在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道.当开启透明混合后,当一个物体被渲染 ...

  9. Unity Shader入门精要学习笔记 - 第7章 基础纹理

    转自 冯乐乐的 <Unity Shader 入门精要> 纹理最初的目的就是使用一张图片来控制模型的外观.使用纹理映射技术,我们可以把一张图“黏”在模型表面,逐纹素地控制模型的颜色. 在美术 ...

随机推荐

  1. VSTO - 使用Excel加载项生成表和图表

    此示例显示如何创建Excel的加载项,使用户可以在其工作表中选择库存符号,然后生成一个新工作表,显示库存的历史性能. 工作表包含数据表和图表. 介绍Excel加载项通常不知道工作表包含什么.典型的加载 ...

  2. 小程序设置apiBase

    App({ globalDate:{ g_isPlayMusic:false, g_currentMusicPostId:null, douBanBase:'http://t.yushu.im' }, ...

  3. Cracking The Coding Interview2.4

    删除前面的linklist,使用node来表示链表 // You have two numbers represented by a linked list, where each node cont ...

  4. 7.6 C++基本序列式容器效率比较

    参考:http://www.weixueyuan.net/view/6403.html 总结: 对于vector而言,它只是一个可以伸缩长度的数组 对于deque而言,它是一个可以操作头部和尾部的并且 ...

  5. capjoint conversations with Chenweiwen

    This event is quite small for teleseismic stations, which means it will be more strongly affected by ...

  6. Sample Credential Providers

        Windows Vista Sample Credential Providers Overview Contents Terms of Use Release Notes SampleCre ...

  7. 图片 100%显示. img 全部显示.

    让每个图片 都铺满 ,同样的大小;    只要给 img 设置 固定的高度, 宽度就可以 了. ----------------------- html: <div class="co ...

  8. apache .htacess

    htaccess 详解   .htaccess是什么 .htaccess文件(或者"分布式配置文件")提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多 ...

  9. MAVEN 阿里云中央仓库

    <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> <name>Nexu ...

  10. vuejs 1.x与2.x差异

    1.x与2.x区别 v-for列表查询中 当前下标:$index --> index 1.x 用法 v-for="v in myData" =>$index获取下标 / ...