渲染透明物体
深度测试和深度写入带来的好处
有了深度测试和深度写入让我们不需要关心不透明物体的渲染顺序
比如
一个物体A 挡住了 物体B
即使A的渲染顺序小于B(先渲染A,后渲染B)我们也不用担心 B的颜色会把A覆盖
因为在进行深度测试时,远处的B的深度值无法通过深度测试
因为它的深度会比已经写入深度缓冲中A的深度值大
重合处的片元会被丢弃,颜色自然就不会写入,最终重叠处渲染出来的会是A的颜色
透明混合为什么需要关闭深度写入
深度测试默认小于判断(深度值小于缓冲区的深度值 则通过测试)
深度写入默认开启(通过深度测试后 写入深度缓冲区)
混合模式默认不混合
渲染队列(默认几何Geometry队列)
对于不透明的物体来说,使用默认设置就能够得到正确的渲染效果
处理透明混合时,需要关闭深度写入
在图形学中模拟出 现实世界的半透明效果是通过将 多个颜色进行混合计算呈现出来的
如果不关闭深度写入 透明物体的深度信息 会被存入深度缓冲区
当有多个透明物体重叠显示时 后渲染的物体 如果无法通过深度测试 片元会被舍弃无法进行颜色混合(即透明物体后面的透明物体不会被显示出来)
关闭深度写入带来的问题
若关闭深度写入,那么物体的渲染顺序就会变得非常的重要
谁先被渲染,谁后被渲染都会影响最终的呈现效果
事例1:
两个物体 A为半透明物体 B为不透明物体

先渲染B,再渲染A,可以得到正确的半透明效果
先渲染A,再渲染B,只会看到B的颜色(因为A没有写入深度缓冲 B通过深度测试会被显示在A前)
通常不透明的物体 渲染顺序都在透明物体的前面
事例2:
两个物体 A为半透明物体 B为透明物体

先渲染B,再渲染A,可以得到正确的半透明效果
先渲染A,再渲染B,只会看到B的颜色(因为A没有写入深度缓冲 B因为后渲染 通过深度测试会被显示在A前)
可以认为 关闭深度写入后 在同时渲染多个透明物体时 谁显示在前 取决于谁最后被渲染
通过这两个事例我们知道
当关闭了深度写入后带来的最大问题是
不透明物体的渲染顺序会直接影响最终的渲染效果
如何解决渲染顺序带来的问题
大部分的渲染引擎采取的方式都是先对场景上的物体进行排序,然后再渲染
常规方法为:
- 先渲染所有不透明物体,开启深度测试和深度写入
- 将半透明物体按照离摄像机的远近进行排序,然后从后往前的顺序渲染它们,开启深度测试关闭深度写入
特殊情况

- 忍一忍,接受部分细节的小瑕疵
- 从模型入手:拆分模型
- 使用开启深度写入的半透明效果来模拟半透明(性能消耗较高)
Unity Shader中设置深度写入
深度写入默认是开启的
我们需要通过 渲染状态中的ZWrite off指令主动关闭深度写入
当我们把它写在Pass渲染通道中时,它只会影响该Pass
若我们把它写在SubShader语句块中,它将影响其中的所有Pass
Unity Shader中设置渲染队列
在Unity Shader中我们可以通过渲染标签主动的设置物体的渲染顺序
Tags{ "Queue" = "标签值" }Background(背景)(队列号:1000)最早被渲染的物体的队列,一般用来渲染天空盒或者背景Geometry(几何)(队列号:2000)不透明的几何体通常使用该队列,不设置时的默认队列AlphaTest(透明测试)(队列号:2450)需要透明度测试的物体使用的队列Transparent(透明的)(队列号:3000) 半透明物体的渲染队列,该队列中几何体按照由远到近的 顺序进行绘制,所有进行透明混合的几何体都应该使用该队列Overlay(覆盖)(队列号:4000)用是放在最后渲染的队列,于叠加渲染的效果- 自定义队列 基于Unity预先定义好的这些渲染队列标签来进行加减运算来 定义自己的渲染队列 如
Tags{ "Queue" = "Geometry+1" }代表的队列号就是 2001
渲染队列一般都定义在SubShader语句块中,影响之后的所有Pass渲染通道
在使用 渲染队列Queue 时,一般会搭配 忽视投影器IgnoreProjector 和 渲染类型RenderType 一起使用
忽视投影器 IgnoreProjector 标签:
投影器(Projector)是Unity中的一种特殊的光源,它用于在场景中投射纹理(Texture)或简单的几何形状(如圆形 或方形)来模拟光照、阴影或其他视觉效果。
渲染类型 RenderType 标签:
对着色器进行分类,用于着色器替换功能,摄像机上有对应API,可以指定渲染类型替换成别的着色器 Opaque(不透明的)、 Transparent(透明的)、 TransparentCutout(透明切割)、 Background(背景)、 Overlay(覆盖)
混合
混合默认是关闭的
当我们在使用了Blend混合命令时(除Blend off),Unity内部就会自动的帮助我们开启混合 我们在实现透明效果时,就需要设置混合方式这个渲染状态
混合的基本原理
当我们在进行渲染时,当片元通过了深度测试后,会进入到混合流程中。 在混合流程中:
- 当前片元的颜色被称为 源颜色
- 颜色缓冲区中的颜色被称为 目标颜色
混合就是将 源颜色 和 目标颜色 用对应的混合算法进行计算后 输出一个新的颜色 更新到颜色缓冲区中
混合因子
当前片元的颜色被称为 源颜色 = S (source)
颜色缓冲区中的颜色被称为 目标颜色 = D (destination)
混合后的 输出颜色 = O(out)
混合计算的规则就是需要构建两个混合等式
计算RGB通道的混合等式(默认add)
Orgb = 源因子 * Srgb + 目标因子 * Drgb
计算A通道的混合等式(默认add)
Oa = 源透明因子 * Sa + 目标透明因子 * Da
设置混合因子
//基本格式
Blend 源因子 目标因子, 源透明因子 目标透明因子
//省略格式 源因子和透明因子相同
Blend 源因子 目标因子在Unity当中ShaderLab为我们提供了很多设定好的混合因子
我们根据需求直接使用即可
| 混合因子 | 描述 |
|---|---|
| One | 因子为1 |
| Zero | 因子为0 |
| SrcColor | 因子为源颜色值,混合RGB时用它的RGB作因子;混合A时用它的A |
| SrcAlpha | 因子为源颜色的透明度值(A通道) |
| DstColor | 因子为目标颜色值,混合RGB时用它的RGB作因子;混合A时用它的A |
| DstAlpha | 因子为目标颜色的透明度值(A通道) |
| OneMinusSrcColor | 因子为(1-源颜色),混合RGB时用它的RGB作因子;混合A时用它的A |
| OneMinusSrcAlpha | 因子为(1-源颜色的透明度值)(A通道) |
| OneMinusDstColor | 因子为(1-目标颜色),混合RGB时用它的RGB作因子;混合A时用它的A |
| OneMinusDstAlpha | 因子为(1-目标颜色的透明度值)(A通道) |
混合操作
默认的混合计算规则当中,是使用对应混合因子和源颜色与目标颜色相乘后再相加
实Unity当中还可以选择其他的计算方式来进行混合计算
在ShaderLab当中除了可以使用 Blend 混合命令 来设定混合因子
还提供了一个 BlendOp 混合操作命令 来设定混合的计算方式
BlendOp 混合操作在Unity当中ShaderLab为我们提供了很多设定好的混合操作
| 混合操作 | 描述 |
|---|---|
| add(默认) | 用混合后的源颜色和目标颜色相加 Orgb = 源因子 * Srgb +目标因子 * Drgb Oa = 源透明因子 * Sa + 目标透明因子 * Da |
| Sub | 用混合后的源颜色和目标颜色相减 Orgb = 源因子 * Srgb -目标因子 * Drgb Oa = 源透明因子 * Sa - 目标透明因子 * Da |
| RevSub | 用混合后的目标颜色和混合后的源颜色相减 Orgb = 目标因子 * Drgb-源因子 * Srgb Oa = 目标透明因子 * Da-源透明因子 * 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) ) |
| 其他 | 无法全平台支持,仅支持Windows DX11以上 |
常见的混合类型
透明度混合
Blend SrcAlpha OneMinusSrcAlpha柔和相加
Blend OneMinusSrcColor One正片叠底
Blend DstColor Zero两倍相乘
Blend DstColor SrcColor变暗
BlendOp Min
Blend One One变亮
BlendOp Max
Blend One One滤色
Blend OneMinusDstColor One
//相当于
Blend One OneMinusSrcColor线性减淡
Blend One One透明度测试
在游戏开发中
对象的某些部位完全透明而其他部位完全不透明
这种透明需求往往不需要半透明效果
相对比较极端,只有看得见和看不见之分
比如树叶、草、栅栏等等
透明测试的基本原理
通过一个阈值来决定哪些像素应该被保留,哪些应该被丢弃
阈值判断使用的方法:
利用CG中的内置函数:clip(参数)
该函数有重载,参数类型可以是 float4 float3 float2 float 等等
如果传入的参数任何一个分量是负数就会舍弃当前片元
clip(texColor.a - _Cutoff);
//相当于
//if(texColor.a - _Cutoff < 0)
// discard;完整实现
Shader "Unlit/AlphaTestLearn"
{
Properties
{
_MainTex("MainTex",2D) = ""{} //主贴图
_NormalTex("NormalTex",2D) = ""{} //法线贴图
_BumpScale("BumpScale",range(0,1)) = 1 //凹凸度
_DiffuseColor("DiffuseColor",Color) = (1,1,1,1) //漫反射颜色
_RampTex("RampTex",2D) = ""{} //渐变贴图
_SpecularColor("SpecularColor", Color) = (1,1,1,1) //高光反射颜色
_SpecularNum("SpecularNum", Range(8, 256)) = 18 //光泽度
_SpecularTex("SpecularTex",2D) = ""{}//高光遮罩纹理
_SpecularScale("SpecularScale",Range(0,1)) = 1 //高光遮罩系数
_CutoOff("CutoOff",Range(0,1)) = 1
}
SubShader
{
Tags{"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
Pass
{
Tags { "LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 wpos : TEXCOORD1;
float3 viewDir:TEXCOORD2;
float3 lightDir:TEXCOORD3;
};
//漫反射
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _DiffuseColor;
sampler2D _RampTex;
//法线
sampler2D _NormalTex;
float4 _NormalTex_ST;
float _BumpScale;
//高光反射
fixed4 _SpecularColor;
float _SpecularNum;
sampler2D _SpecularTex;
float _SpecularScale;
//透明测试
fixed _CutoOff;
v2f vert (appdata_full v)
{
v2f data;
//坐标转换
data.pos = UnityObjectToClipPos(v.vertex);
data.wpos = mul(unity_ObjectToWorld,v.vertex);
//uv贴图
data.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
data.uv.zw = v.texcoord.xy * _NormalTex_ST.xy + _NormalTex_ST.zw;
//计算 切线空间 变换矩阵
float3 bitangent = cross(v.tangent.xyz,v.normal) * v.tangent.w;
float3x3 rotation = float3x3(v.tangent.xyz,bitangent,v.normal);
//切线空间下的 视角和灯光向量
data.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex));
data.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex));
return data;
}
fixed4 frag (v2f i) : SV_Target
{
//法线
float4 packedNoraml = tex2D(_NormalTex,i.uv.zw);
float3 unpackNormal = UnpackNormal(packedNoraml);
//凹凸度
unpackNormal.xy *= _BumpScale;
unpackNormal.z = sqrt(1 -saturate(dot(unpackNormal.xy,unpackNormal.xy)));
//漫反射
fixed4 uvColor = tex2D(_MainTex,i.uv.xy);
clip(uvColor.w - _CutoOff);
uvColor *= _DiffuseColor;
fixed halfLarbertNum = dot(i.lightDir,unpackNormal) * 0.5 + 0.5;//渐变贴图
fixed3 diffuseColor = _LightColor0 * uvColor * tex2D(_RampTex,fixed2(halfLarbertNum,halfLarbertNum));
//高光
fixed specularMask = tex2D(_SpecularTex,i.uv.xy).r * _SpecularScale;//高光遮罩
float3 halfDir = normalize(i.viewDir + i.lightDir);
fixed3 specularColor = _LightColor0 * _SpecularColor * pow(max(0,dot(halfDir,unpackNormal)),_SpecularNum) * specularMask;
//blinn-phong
fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT * uvColor + diffuseColor + specularColor;
return fixed4(blinnPhongColor,1);
}
ENDCG
}
}
}透明度混合
Shader "Unlit/AlphaTestLearn2"
{
Properties
{
_MainTex("MainTex",2D) = ""{} //主贴图
_NormalTex("NormalTex",2D) = ""{} //法线贴图
_BumpScale("BumpScale",range(0,1)) = 1 //凹凸度
_DiffuseColor("DiffuseColor",Color) = (1,1,1,1) //漫反射颜色
_RampTex("RampTex",2D) = ""{} //渐变贴图
_SpecularColor("SpecularColor", Color) = (1,1,1,1) //高光反射颜色
_SpecularNum("SpecularNum", Range(8, 256)) = 18 //光泽度
_SpecularTex("SpecularTex",2D) = ""{}//高光遮罩纹理
_SpecularScale("SpecularScale",Range(0,1)) = 1 //高光遮罩系数
_CutoOff("CutoOff",Range(0,1)) = 1 //透明测试
_AlphaScale("AlphaScale",Range(0,1)) = 1 //透明度
_Grayscale("Grayscale", Range(0, 1)) = 0 //黑白
}
SubShader
{
//设置透明
Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
//关闭深度写入
ZWrite Off
//设置混合
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
Tags { "LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 wpos : TEXCOORD1;
float3 viewDir:TEXCOORD2;
float3 lightDir:TEXCOORD3;
};
//漫反射
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _DiffuseColor;
sampler2D _RampTex;
//法线
sampler2D _NormalTex;
float4 _NormalTex_ST;
float _BumpScale;
//高光反射
fixed4 _SpecularColor;
float _SpecularNum;
sampler2D _SpecularTex;
float _SpecularScale;
//透明测试
fixed _CutoOff;
fixed _AlphaScale;
fixed _Grayscale;
v2f vert (appdata_full v)
{
v2f data;
//坐标转换
data.pos = UnityObjectToClipPos(v.vertex);
data.wpos = mul(unity_ObjectToWorld,v.vertex);
//uv
data.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
data.uv.zw = v.texcoord.xy * _NormalTex_ST.xy + _NormalTex_ST.zw;
//计算模型空间到切线空间的变换矩阵
float3 bitangent = cross(v.tangent.xyz,v.normal) * v.tangent.w;
float3x3 rotation = float3x3(v.tangent.xyz,bitangent,v.normal);
//切线空间下的视角和灯光向量
data.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex));
data.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex));
return data;
}
fixed4 frag (v2f i) : SV_Target
{
//法线
float4 packedNoraml = tex2D(_NormalTex,i.uv.zw);
float3 unpackNormal = UnpackNormal(packedNoraml);
unpackNormal.xy *= _BumpScale;//凹凸度
unpackNormal.z = sqrt(1 -saturate(dot(unpackNormal.xy,unpackNormal.xy)));
//漫反射
fixed4 uvColor = tex2D(_MainTex,i.uv.xy);
clip(uvColor.w - _CutoOff);//透明测试
uvColor *= _DiffuseColor;
fixed halfLarbertNum = dot(i.lightDir,unpackNormal) * 0.5 + 0.5;//渐变贴图
fixed4 diffuseColor = _LightColor0 * uvColor * tex2D(_RampTex,fixed2(halfLarbertNum,halfLarbertNum));
//高光
fixed specularMask = tex2D(_SpecularTex,i.uv.xy).r * _SpecularScale;//高光遮罩
float3 halfDir = normalize(i.viewDir + i.lightDir);//计算半角向量
fixed3 specularColor = _LightColor0 * _SpecularColor * pow(max(0,dot(halfDir,unpackNormal)),_SpecularNum) * specularMask;
//blinn-phong
fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT * uvColor + diffuseColor + specularColor;
//黑白效果
fixed3 grayColor = dot(blinnPhongColor,float3(0.299, 0.587, 0.114));
fixed3 color = lerp(blinnPhongColor,grayColor,_Grayscale);
return fixed4(color,uvColor.w *_AlphaScale);
}
ENDCG
}
}
}开启深度写入的半透明效果
使用之前的透明度混合Shader会由于关闭了深度写入会产生错误的渲染效果
对于多个透明模型 可以通过 先渲染不透明物体 再根据摄像机距离 按顺序渲染透明物体 来获得正确的效果
但对于单一复杂模型的半透明渲染 由于渲染队列是针对一整个物体的 而不是顶点 所以 开启深度测试 剔除被遮挡的片元 并且使用 ColorMask 0 颜色遮罩 渲染命令,不输出颜色
第一个Pass:开启深度写入,不输出颜色 目的是让该模型各片元的深度值能写入深度缓冲
第二个Pass:关闭深度写入,进行正常的透明度混合
实现
Shader "Unlit/Apphaearn3"
{
Properties
{
_MainTex("MainTex",2D) = ""{} //主贴图
_NormalTex("NormalTex",2D) = ""{} //法线贴图
_BumpScale("BumpScale",range(0,1)) = 1 //凹凸度
_DiffuseColor("DiffuseColor",Color) = (1,1,1,1) //漫反射颜色
_RampTex("RampTex",2D) = ""{} //渐变贴图
_SpecularColor("SpecularColor", Color) = (1,1,1,1) //高光反射颜色
_SpecularNum("SpecularNum", Range(8, 256)) = 18 //光泽度
_SpecularTex("SpecularTex",2D) = ""{}//高光遮罩纹理
_SpecularScale("SpecularScale",Range(0,1)) = 1 //高光遮罩系数
_CutoOff("CutoOff",Range(0,1)) = 1 //透明测试
_AlphaScale("AlphaScale",Range(0,1)) = 1 //透明度
_Grayscale("Grayscale", Range(0, 1)) = 0 //黑白
}
SubShader
{
//设置透明
Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
Pass
{
//开启深度写入
ZWrite On
ColorMask 0
}
Pass
{
//关闭深度写入
ZWrite Off
//设置混合
Blend SrcAlpha OneMinusSrcAlpha
Tags { "LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 wpos : TEXCOORD1;
float3 viewDir:TEXCOORD2;
float3 lightDir:TEXCOORD3;
};
//漫反射
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _DiffuseColor;
sampler2D _RampTex;
//法线
sampler2D _NormalTex;
float4 _NormalTex_ST;
float _BumpScale;
//高光反射
fixed4 _SpecularColor;
float _SpecularNum;
sampler2D _SpecularTex;
float _SpecularScale;
//透明测试
fixed _CutoOff;
fixed _AlphaScale;
fixed _Grayscale;
v2f vert (appdata_full v)
{
v2f data;
//坐标转换
data.pos = UnityObjectToClipPos(v.vertex);
data.wpos = mul(unity_ObjectToWorld,v.vertex);
//uv
data.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
data.uv.zw = v.texcoord.xy * _NormalTex_ST.xy + _NormalTex_ST.zw;
//计算模型空间到切线空间的变换矩阵
float3 bitangent = cross(v.tangent.xyz,v.normal) * v.tangent.w;
float3x3 rotation = float3x3(v.tangent.xyz,bitangent,v.normal);
//切线空间下的视角和灯光向量
data.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex));
data.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex));
return data;
}
fixed4 frag (v2f i) : SV_Target
{
//法线
float4 packedNoraml = tex2D(_NormalTex,i.uv.zw);
float3 unpackNormal = UnpackNormal(packedNoraml);
unpackNormal.xy *= _BumpScale;//凹凸度
unpackNormal.z = sqrt(1 -saturate(dot(unpackNormal.xy,unpackNormal.xy)));
//漫反射
fixed4 uvColor = tex2D(_MainTex,i.uv.xy);
clip(uvColor.w - _CutoOff);//透明测试
uvColor *= _DiffuseColor;
fixed halfLarbertNum = dot(i.lightDir,unpackNormal) * 0.5 + 0.5;//渐变贴图
fixed4 diffuseColor = _LightColor0 * uvColor * tex2D(_RampTex,fixed2(halfLarbertNum,halfLarbertNum));
//高光
fixed specularMask = tex2D(_SpecularTex,i.uv.xy).r * _SpecularScale;//高光遮罩
float3 halfDir = normalize(i.viewDir + i.lightDir);//计算半角向量
fixed3 specularColor = _LightColor0 * _SpecularColor * pow(max(0,dot(halfDir,unpackNormal)),_SpecularNum) * specularMask;
//blinn-phong
fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT * uvColor + diffuseColor + specularColor;
//黑白效果
fixed3 grayColor = dot(blinnPhongColor,float3(0.299, 0.587, 0.114));
fixed3 color = lerp(blinnPhongColor,grayColor,_Grayscale);
return fixed4(color,uvColor.w *_AlphaScale);
}
ENDCG
}
}
}双面渲染效果
默认情况下,Unity会自动剔除物体的背面,而只渲染物体的正面
双面渲染的基本原理就是使用 Cull 剔除指令来进行指定操作
- Cull Back背面剔除
- Cull Front正面剔除
- Cull Off不剔除
透明度测试Shader
由于它无需混合,所以直接关闭剔除即可
双面渲染的透明效果Shader
使用两个Pass渲染
在第一个Pass 剔除正面,在第二各Pass剔除背面
相当于先渲染背面 然后在渲染正面
实现
Shader "Unlit/AplhaLearn4"
{
Properties
{
_MainTex("MainTex",2D) = ""{} //主贴图
_NormalTex("NormalTex",2D) = ""{} //法线贴图
_BumpScale("BumpScale",range(0,1)) = 1 //凹凸度
_DiffuseColor("DiffuseColor",Color) = (1,1,1,1) //漫反射颜色
_RampTex("RampTex",2D) = ""{} //渐变贴图
_SpecularColor("SpecularColor", Color) = (1,1,1,1) //高光反射颜色
_SpecularNum("SpecularNum", Range(8, 256)) = 18 //光泽度
_SpecularTex("SpecularTex",2D) = ""{}//高光遮罩纹理
_SpecularScale("SpecularScale",Range(0,1)) = 1 //高光遮罩系数
_CutoOff("CutoOff",Range(0,1)) = 1 //透明测试
_AlphaScale("AlphaScale",Range(0,1)) = 1 //透明度
_Grayscale("Grayscale", Range(0, 1)) = 0 //黑白
}
SubShader
{
//设置透明
Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
Pass
{
Cull Front
//关闭深度写入
ZWrite Off
//设置混合
Blend SrcAlpha OneMinusSrcAlpha
Tags { "LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 wpos : TEXCOORD1;
float3 viewDir:TEXCOORD2;
float3 lightDir:TEXCOORD3;
};
//漫反射
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _DiffuseColor;
sampler2D _RampTex;
//法线
sampler2D _NormalTex;
float4 _NormalTex_ST;
float _BumpScale;
//高光反射
fixed4 _SpecularColor;
float _SpecularNum;
sampler2D _SpecularTex;
float _SpecularScale;
//透明测试
fixed _CutoOff;
fixed _AlphaScale;
fixed _Grayscale;
v2f vert (appdata_full v)
{
v2f data;
//坐标转换
data.pos = UnityObjectToClipPos(v.vertex);
data.wpos = mul(unity_ObjectToWorld,v.vertex);
//uv
data.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
data.uv.zw = v.texcoord.xy * _NormalTex_ST.xy + _NormalTex_ST.zw;
//计算模型空间到切线空间的变换矩阵
float3 bitangent = cross(v.tangent.xyz,v.normal) * v.tangent.w;
float3x3 rotation = float3x3(v.tangent.xyz,bitangent,v.normal);
//切线空间下的视角和灯光向量
data.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex));
data.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex));
return data;
}
fixed4 frag (v2f i) : SV_Target
{
//法线
float4 packedNoraml = tex2D(_NormalTex,i.uv.zw);
float3 unpackNormal = UnpackNormal(packedNoraml);
unpackNormal.xy *= _BumpScale;//凹凸度
unpackNormal.z = sqrt(1 -saturate(dot(unpackNormal.xy,unpackNormal.xy)));
//漫反射
fixed4 uvColor = tex2D(_MainTex,i.uv.xy);
clip(uvColor.w - _CutoOff);//透明测试
uvColor *= _DiffuseColor;
fixed halfLarbertNum = dot(i.lightDir,unpackNormal) * 0.5 + 0.5;//渐变贴图
fixed4 diffuseColor = _LightColor0 * uvColor * tex2D(_RampTex,fixed2(halfLarbertNum,halfLarbertNum));
//高光
fixed specularMask = tex2D(_SpecularTex,i.uv.xy).r * _SpecularScale;//高光遮罩
float3 halfDir = normalize(i.viewDir + i.lightDir);//计算半角向量
fixed3 specularColor = _LightColor0 * _SpecularColor * pow(max(0,dot(halfDir,unpackNormal)),_SpecularNum) * specularMask;
//blinn-phong
fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT * uvColor + diffuseColor + specularColor;
//黑白效果
fixed3 grayColor = dot(blinnPhongColor,float3(0.299, 0.587, 0.114));
fixed3 color = lerp(blinnPhongColor,grayColor,_Grayscale);
return fixed4(color,uvColor.w *_AlphaScale);
}
ENDCG
}
Pass
{
Cull Back
//关闭深度写入
ZWrite Off
//设置混合
Blend SrcAlpha OneMinusSrcAlpha
Tags { "LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 wpos : TEXCOORD1;
float3 viewDir:TEXCOORD2;
float3 lightDir:TEXCOORD3;
};
//漫反射
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _DiffuseColor;
sampler2D _RampTex;
//法线
sampler2D _NormalTex;
float4 _NormalTex_ST;
float _BumpScale;
//高光反射
fixed4 _SpecularColor;
float _SpecularNum;
sampler2D _SpecularTex;
float _SpecularScale;
//透明测试
fixed _CutoOff;
fixed _AlphaScale;
fixed _Grayscale;
v2f vert (appdata_full v)
{
v2f data;
//坐标转换
data.pos = UnityObjectToClipPos(v.vertex);
data.wpos = mul(unity_ObjectToWorld,v.vertex);
//uv
data.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
data.uv.zw = v.texcoord.xy * _NormalTex_ST.xy + _NormalTex_ST.zw;
//计算模型空间到切线空间的变换矩阵
float3 bitangent = cross(v.tangent.xyz,v.normal) * v.tangent.w;
float3x3 rotation = float3x3(v.tangent.xyz,bitangent,v.normal);
//切线空间下的视角和灯光向量
data.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex));
data.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex));
return data;
}
fixed4 frag (v2f i) : SV_Target
{
//法线
float4 packedNoraml = tex2D(_NormalTex,i.uv.zw);
float3 unpackNormal = UnpackNormal(packedNoraml);
unpackNormal.xy *= _BumpScale;//凹凸度
unpackNormal.z = sqrt(1 -saturate(dot(unpackNormal.xy,unpackNormal.xy)));
//漫反射
fixed4 uvColor = tex2D(_MainTex,i.uv.xy);
clip(uvColor.w - _CutoOff);//透明测试
uvColor *= _DiffuseColor;
fixed halfLarbertNum = dot(i.lightDir,unpackNormal) * 0.5 + 0.5;//渐变贴图
fixed4 diffuseColor = _LightColor0 * uvColor * tex2D(_RampTex,fixed2(halfLarbertNum,halfLarbertNum));
//高光
fixed specularMask = tex2D(_SpecularTex,i.uv.xy).r * _SpecularScale;//高光遮罩
float3 halfDir = normalize(i.viewDir + i.lightDir);//计算半角向量
fixed3 specularColor = _LightColor0 * _SpecularColor * pow(max(0,dot(halfDir,unpackNormal)),_SpecularNum) * specularMask;
//blinn-phong
fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT * uvColor + diffuseColor + specularColor;
//黑白效果
fixed3 grayColor = dot(blinnPhongColor,float3(0.299, 0.587, 0.114));
fixed3 color = lerp(blinnPhongColor,grayColor,_Grayscale);
return fixed4(color,uvColor.w *_AlphaScale);
}
ENDCG
}
}
}