第1篇 基础篇
第2篇 初级篇
第3篇 中级篇
第4篇 高级篇
第5篇 扩展篇
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第1篇 基础篇
第1章 欢迎来到Shader的世界
第2章 渲染流水线
3D API | 最后支持固定管线的版本 | 第一个支持可编程管线的版本 |
OpenGL | 1.5 | 2.0 |
OpenGL ES | 1.1 | 2.0 |
DirectX | 7.0 | 8.0 |
第3章 Unity Shader 基础
属性类型 | 默认值的定义语法 | 例子 |
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" {} |
状态名称 | 设置指令 | 解释 |
Cull | Cull Back|Front|Off | 设置剔除模式:剔除背面/正面/关闭剔除 |
ZTest | ZTest Less Greater|LEqual|GEqual|Equal|NotEqual|Always | 设置深度测试时使用的函数 |
ZWrite | ZWrite On|Off | 开启/关闭深度写入 |
Blend | Blend SrcFactor DstFactor | 开启并设置混合模式 |
标签类型 | 说明 | 例子 |
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"} |
标签类型 | 说明 | 例子 |
LightMode | 定义该Pass在Unity的渲染流水线中的角色 | Tags {"LightMode" = "ForwardBase"} |
RequireOptions | 用于指定当满足某些条件时才渲染该Pass,它的值是一个由空格分隔的字符串.目前,Unity支持的选项有:SoftVegetation.在后面的版本中,可能会增加更多的选项 | Tags {"RequireOptions" = "SoftVegetation"} |
第4章 学习Shader所需的数学基础
变换名称 | 是线性变换吗 | 是仿射变换吗 | 是可逆矩阵吗 | 是正交矩阵吗 |
平移矩阵 | 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 |
变量名 | 描述 |
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的逆矩阵,用于将顶点/方向矢量从世界空间变换到模型空间 |
变量名 | 类型 | 描述 |
_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的学习之旅
ShaderLab属性类型 | Cg变量类型 |
Color,Vector | float4,half4,fixed4 |
Range,Float | float,half,fixed |
2D | sampler2D |
Cube | samplerCube |
3D | sampler3D |
文件名 | 描述 |
UnityCG.cginc | 包含了最常使用的帮助函数,宏和结构体等 |
UnityShaderVariables.cginc | 在编译UnityShader时,会被自动包含进来.包含了许多内置的全局变量,如UNITY_MATRIX_MVP等 |
Lighting.cginc | 包含了各种内置的光照模型,如果编写的是SurfaceShader的话,会自动包含进来 |
HLSLSupport.cginc | 在编译UnityShader时,会被自动包含进来.声明了很多用于跨平台编译的宏和定义 |
名称 | 描述 | 包含的变量 |
appdata_base | 可用于顶点着色器的输入 | 顶点位置,顶点法线,第一组纹理坐标 |
appdata_tan | 可用于顶点着色器的输入 | 顶点位置,顶点切线,顶点法线,第一组纹理坐标 |
appdata_full | 可用于顶点着色器的输入 | 顶点位置,顶点切线,顶点法线,四组(或更多)纹理坐标 |
appdata_img | 可用于顶点着色器的输入 | 顶点位置,第一组纹理坐标 |
v2f_img | 可用于顶点着色器的输出 | 裁剪空间中的位置,纹理坐标 |
函数名 | 描述 |
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) | 把方向矢量从世界空间变换到模型空间中 |
语义 | 描述 |
POSITION | 模型空间中的顶点位置,通常是float4类型 |
NORMAL | 顶点法线,通常是float3类型 |
TANGENT | 顶点切线,通常是float4类型 |
TEXCOORDn,如TEXCOORD0,TEXCOORD1 | 该顶点的纹理坐标,TEXCOORD0表示第一组纹理坐标,依次类推.通常是float2或float4类型 |
COLOR | 顶点颜色,通常是fixed4或float4类型 |
语义 | 描述 |
SV_POSITION | 裁剪空间的顶点坐标,结构体中必须包含一个用该语义修饰的变量.等同于DirectX9中的POSITION,但最好使用SV_POSITION |
COLOR0 | 通常用于输出第一组顶点颜色,但不是必需的 |
COLOR1 | 通常用于输出第二组顶点颜色,但不是必需的 |
TEXCOORD0~TEXCOORD7 | 通常用于输出纹理坐标,但不是必需的 |
语义 | 描述 |
SV_Target | 输出值将会存储到渲染目标(render target)中.等同于DirectX9中的COLOR语义,但最好使用SV_Target |
类型 | 精度 |
float | 最高精度的浮点值.通常使用32位来存储 |
half | 中等精度的浮点值.通常使用16位来存储,精度范围是-60000~+60000 |
fixed | 最低精度的浮点值.通常使用11位来存储,精度范围是-2.0~+2.0 |
指令 | 描述 |
#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中的基础光照
函数名 | 描述 |
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章 透明效果
名称 | 队列索引号 | 描述 |
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
语义 | 描述 |
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
命令 | 描述 |
Blend SrcFactor DstFactor | 开启混合,并设置混合因子.源颜色(该片元产生的颜色)会乘以SrcFactor,而目标颜色(已经存在于颜色缓存的颜色)会乘以DstFactor,然后把两者相加后再存入颜色缓冲中 |
Blend SrcFactor DstFactor,SrcFactorA DstFactorA | 和上面几乎一样,只是使用不同的因子来混合透明通道 |
参数 | 描述 |
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-目标颜色的透明度值) |
操作 | 描述 |
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章 更复杂的光照
标签名 | 描述 |
Always | 不管使用那种渲染路径,该Pass总是会被渲染,但不会计算任何光照 |
ForwardBase | 用于前向渲染.该Pass会计算环境光,最重要的平行光,逐顶点/SH光源和Lightmaps |
ForwardAdd | 用于前向渲染.该Pass会计算额外的逐像素光源,每个Pass对应一个光源 |
Deferred | 用于延迟渲染.该Pass会渲染G缓冲(G-buffer) |
ShadowCaster | 把物体的深度信息渲染到阴影映射纹理(shadowmap)或一张深度纹理中 |
PrepassBase | 用于遗留的延迟渲染.该Pass会渲染法线和高光反射的指数部分 |
PrepassFinal | 用于遗留的延迟渲染.该Pass通过合并纹理,光照和自发光来渲染得到最后的颜色 |
Vertex,VertexLMRGBM和VertexLM | 用于遗留的顶点照明渲染 |
名称 | 类型 | 描述 |
_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个非重要的点光源的颜色 |
函数名 | 描述 |
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等.前向渲染通常会使用这个函数来计算逐顶点光照 |
名称 | 类型 | 描述 |
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) |
函数名 | 描述 |
float3 ShadeVertexLights(float4 vertex,float3 normal) | 输入模型空间中的顶点位置和法线,计算四个逐顶点光源的光照以及环境光.内部实现实际上调用了ShadeVertexLightsFull函数 |
float3 ShadeVertexLightsFull(float4 vertex,float3 normal,int lightCount,bool spotLight) | 输入模型空间中的顶点位置和法线,计算lightCount个光源的光照以及环境光.如果spotLight值为true,那么这些光源会被当成聚光灯来处理,虽然结果更精确,但计算更加耗时;否则,按点光源处理 |
名称 | 类型 | 描述 |
_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章 让画面动起来
名称 | 类型 | 描述 |
_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中的渲染优化技术
信息名称 | 描述 |
每帧的时间和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的表面着色器探秘
变量 | 描述 |
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章 基于物理的渲染
文件 | 描述 |
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章 还有更多内容吗