最简shader模板
Shader "AP1/L03/FlatCol" {
Properties {
//材质面板
}
SubShader {
Tags {
"RenderType"="Opaque"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase" //Pass标签
}
CGPROGRAM //包围CG代码
#pragma vertex vert //定义顶点和片元着色器
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
// 输入结构
struct VertexInput {
float4 vertex : POSITION; // 将模型的顶点信息输入进来
};
// 输出结构
struct VertexOutput {
float4 pos : SV_POSITION; // 由模型顶点信息换算而来的顶点屏幕位置
};
// 输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0; // 新建一个输出结构
o.pos = UnityObjectToClipPos( v.vertex ); //变换顶点信息并将其塞给输出结构
return o; // 将输出结构 输出
}
// 输出结构>>>像素
float4 frag(VertexOutput i) : COLOR {
return float4(0.0, 1.0, 0.0, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
各种向量
- nDir:normal 法线方向,点乘操作时简称n;
- lDir: light 光照方向,点乘操作时简称l;
- vDir:view 观察方向,点乘操作时简称v;
- rDir:reflect 光反射方向,点乘操作时简称r;
- hDir:half 半角方向(即lDir和vDir的中间角方向),点乘操作时简称h;
- OS:ObjectSpace 物体空间,本地空间
- WS:WorldSpace 世界空间;
- VS: ViewSpace 观察空间;
- CS:HomogenousClipSpace 齐次剪裁空间;
- TS:TangentSpace 切线空间;
- TXS:TextureSpace 纹理空间;
光照构成
光照模型
一、Lambert 和 Half Lambert 漫反射光照模型
- Lambert:
float4 frag(VertexOutput i) : COLOR
{
float3 nDir = i.nDirWS;
float3 lDir = _WorldSpaceLightPos0.xyz;
float nDotl = dot(nDir,lDir); //
float lambert = max(0.0,nDotl);
return float4(lambert,lambert,lambert,1.0);
}
- Half Lambert:
float lambert = nDotl*0.5+0.5;
- 作业:
思路: 以半兰伯特模型构造uv坐标采样Ramptex(Ramptex贴图:1. 3阶明度,过渡卡硬 2.暗部色相变化,少明度变化)
- 点评案例:
1. 玉石效果
2. 像素点效果
3. SSSLut效果
二、Phong/Blinn-Phong高光模型
- Phong:
float3 rDir = reflect(-lDir,nDir);
float rDotv = dot(rDir,vDir);
float phong = pow(max(0.0,rDotv),_SpecularPow);
float3 finaRGB = _MainCol * lambert + phong;
- Blinn-Phong:
float3 hDir = normalize( vDir + lDir );
float nDoth = dot(nDir,hDir);
float blinnphong = pow(max(0.0,nDoth),_SpecularPow);
三、OldSchoolPlus
- Lambert + Phong + Shadow + 3ColAmbient + AO (忽略镜面反射cubemap)
shader forge:
代码:
Shader "Unlit/13_OldSchoolPlus"
{
Properties
{
_BaseCol ("BaseCol",color) = (1.0, 1.0, 1.0, 1.0)
_SpecularPow ("SpecularPow", range(1,90)) = 30
_LightCol ("LightCol",color) = (1.0, 1.0, 1.0, 1.0)
_Occlusion ("Occlusion", 2D) = "white" {}
_EnvUpCol ("EnvUpCol",color) = (1.0, 1.0, 1.0, 1.0)
_EnvSideCol ("EnvSideCol",color) = (1.0, 1.0, 1.0, 1.0)
_EnvDownCol ("EnvDownCol",color) = (1.0, 1.0, 1.0, 1.0)
_EnvColPow ("EnvColPow", range(0,1)) = 0.2
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "AutoLight.cginc"//投影头文件
#include "Lighting.cginc"
#include "UnityCG.cginc"
//输入参数
uniform float3 _BaseCol;
uniform float _SpecularPow;
uniform float _EnvColPow;
uniform float3 _LightCol;
uniform float3 _EnvUpCol;
uniform float3 _EnvSideCol;
uniform float3 _EnvDownCol;
uniform sampler2D _Occlusion;
//输入结构
struct VertexInput{
float4 vertex : POSITION;
float4 normal : NORMAL;
float2 texcoord0: TEXCOORD0; //将模型uv信息输入进0通道
};
//输出结构
struct VertexOutput{
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0;
float4 posWorld : TEXCOORD1;
float3 normalDir : TEXCOORD2;//追加uv信息用于像素shader采样贴图
LIGHTING_COORDS(3,4)//投影
};
//输入结构>>>顶点shader>>>输出结构
VertexOutput vert (VertexInput v){
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos(v.vertex);
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
o.uv0 = v.texcoord0;
o.normalDir = UnityObjectToWorldNormal(v.normal);
TRANSFER_VERTEX_TO_FRAGMENT(o)//投影
return o;
}
//输出结构>>>像素
float4 frag(VertexOutput i) : color{
//环境光
//准备向量
float3 nDir = i.normalDir;
//计算各部分遮罩
float upMask = max(0.0, nDir.g);
float downMask = max(0.0, -nDir.g);
float sideMask = 1.0 - upMask - downMask;
//混合环境色
float3 envCol = _EnvColPow*(_EnvUpCol*upMask + _EnvSideCol*sideMask + _EnvDownCol*downMask);
//采样AO贴图
float occlusion = tex2D(_Occlusion , i.uv0);
//计算环境光照
float3 envLighting = envCol * occlusion;
//兰伯特光照模型
float3 lDir = _WorldSpaceLightPos0.xyz;
float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
float3 vRDir = reflect( -vDir, nDir );
float nDotl = dot(nDir,lDir);
float vRDotl = dot(lDir,vRDir); //点积得到的是标量
//光照模型
float lambert = max(0.0,nDotl);
float phong = pow(max(0.0,vRDotl),_SpecularPow);
//投影
float attenuation = LIGHT_ATTENUATION(i);
float3 finaRGB = attenuation*(_LightCol*(_BaseCol * lambert + phong))+envLighting;
return float4(finaRGB,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
四、TBN矩阵转换NormalMap
因为法线贴图里面是切向空间的法线信息,而我们实际需要的是世界空间的法线信息,为此我们需要一个桥梁来将切向空间的法线信息转化会世界空间的法线信息,这个桥梁就是TBN矩阵。
https://zhuanlan.zhihu.com/p/412555049
代码:
Shader "14_NormalMap"
{
Properties
{
_normalMap ("normalMap",2D) = "bump" {} //默认为bump
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
uniform sampler2D _normalMap;
struct VertexInput
{
float4 vertex: POSITION;
float4 normal: NORMAL;
float4 tangent: TANGENT; //
float2 uv0: TEXCOORD0;
};
struct VertexOutput
{
float4 pos: SV_POSITION;
float2 uv0: TEXCOORD0;
float3 nDirWS: TEXCOORD1;
float3 tDirWS : TEXCOORD2;
float3 bDirWS : TEXCOORD3;
};
VertexOutput vert (VertexInput v)
{
VertexOutput o = (VertexOutput)0; //新建一个输出结构
o.pos = UnityObjectToClipPos( v.vertex ); //变换顶点信息,从物体变换成世界坐标系
o.uv0 = v.uv0;
o.nDirWS = UnityObjectToWorldNormal( v.normal ); //变换法线信息,同上
o.tDirWS = normalize(mul(unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 )).xyz);
o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS)* v.tangent.w); //w确定方向
return o;
}
float4 frag(VertexOutput i) : COLOR
{
float3 nDirTS = UnpackNormal(tex2D(_normalMap, i.uv0));
float3x3 TBN = float3x3(i.tDirWS,i.bDirWS,i.nDirWS);
float3 nDir = normalize(mul(nDirTS, TBN));
float3 lDir = _WorldSpaceLightPos0.xyz;
float nDotl = dot(nDir,lDir);
float lambert = max(0.0,nDotl);
return float4(lambert,lambert,lambert,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
五、菲涅尔
视线垂直于表面时,反射较弱,而当视线非垂直表面时,夹角越小,反射越明显。如果你看向一个圆球,那圆球中心的反射较弱,靠近边缘较强。不过这种过度关系被折射率影响。
在真实世界中,除了金属之外,其它物质均有不同程度的“菲涅尔效应”。
Fresnel = pow(1-ndotv,powVal)
• ldotv:理解为光从眼睛发出时的Lambert; 中间亮,边缘暗;
• 1-ldotv:黑白反相,中间暗,边缘亮;
• power:套一个power控制边缘亮的范围;
六、Matcap 和 CubeMap
- Matcap:
Material Capture(材质捕捉),将光源、材质信息离线烘焙成一张材质球放在贴图上,渲染时候直接拿来用,通过计算将MatCap的纹理信息映射到模型上。
代码:
Shader "Unlit/15_MatCap"
{
Properties
{
_NormalMap ("法线贴图", 2D) = "bump" {}
_MatCap ("MatCap",2D) = "grey" {}
_FresnelPow ("菲涅尔次幂", Range(0,10)) = 1
_EnvSpecInt ("环境镜面反射强度", Range(0,5))=1
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "AutoLight.cginc"//投影头文件
#include "Lighting.cginc"
#include "UnityCG.cginc"
//输入参数
uniform sampler2D _NormalMap;
uniform sampler2D _MatCap;
uniform float _FresnelPow;
uniform float _EnvSpecInt;
//输入结构
struct VertexInput{
float4 vertex : POSITION;
float4 normal : NORMAL;
float4 tangent: TANGENT;
float2 uv0: TEXCOORD0; //将模型uv信息输入进0通道
};
//输出结构
struct VertexOutput{
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0;
float4 posWS : TEXCOORD1;
float3 nDirWS : TEXCOORD2;
float3 tDirWS : TEXCOORD3;
float3 bDirWS : TEXCOORD4;
};
//输入结构>>>顶点shader>>>输出结构
VertexOutput vert (VertexInput v){
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos(v.vertex);
o.posWS = mul(unity_ObjectToWorld, v.vertex);
o.uv0 = v.uv0;
o.nDirWS = UnityObjectToWorldNormal(v.normal);
o.tDirWS = normalize(mul(unity_ObjectToWorld, float4 (v.tangent.xyz,0.0)).xyz);
o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS) * v.tangent.w);
return o;
}
//输出结构>>>像素
float4 frag(VertexOutput i) : color{
//准备向量
float3 nDirTS =UnpackNormal(tex2D(_NormalMap, i.uv0)).rgb;
float3x3 TBN = float3x3(i.tDirWS,i.bDirWS,i.nDirWS);
float3 nDirWS = normalize(mul(nDirTS,TBN));
float3 nDirVS = mul(UNITY_MATRIX_V,nDirWS);
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
//中间变量
float vdotn = dot(vDirWS,nDirWS);//菲涅尔
float2 matcapUV = nDirVS.rg*0.5+0.5; //做uv用于采样Matcap
float3 matcap = tex2D(_MatCap, matcapUV);
float fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow);
float3 envSpecLighting = matcap*fresnel*_EnvSpecInt;
return float4(envSpecLighting,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
- Cubemap:
Cubemap是一个由六个独立的正方形纹理组成的集合,它将多个纹理组合起来映射到一个单一纹理。基本上说CubeMap包含6个2D纹理,这每个2D纹理是一个立方体(cube)的一个面,也就是说它是一个有贴图的立方体。
https://blog.csdn.net/v_xchen_v/article/details/79474193
代码:
Shader "Unlit/16_CubeMap"
{
Properties
{
_Cubemap ("环境球",Cube) = "_Skybox" {}
_NormalMap ("法线贴图", 2D) = "bump" {}
_CubemapMip ("环境球Mip", Range(0,7)) = 0
_FresnelPow ("菲涅尔次幂", Range(0,10)) = 1
_EnvSpecInt ("环境镜面反射强度", Range(0,5))=0.2
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "AutoLight.cginc" //投影头文件
#include "Lighting.cginc"
#include "UnityCG.cginc"
//输入参数
uniform samplerCUBE _Cubemap;
uniform sampler2D _NormalMap;
uniform float _CubemapMip;
uniform float _FresnelPow;
uniform float _EnvSpecInt;
//输入结构
struct VertexInput{
float4 vertex : POSITION;
float4 normal : NORMAL;
float4 tangent: TANGENT;
float2 uv0: TEXCOORD0; //将模型uv信息输入进0通道
};
//输出结构
struct VertexOutput{
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0;
float4 posWS : TEXCOORD1;
float3 nDirWS : TEXCOORD2;
float3 tDirWS : TEXCOORD3;
float3 bDirWS : TEXCOORD4;
};
//输入结构>>>顶点shader>>>输出结构
VertexOutput vert (VertexInput v){
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos(v.vertex);
o.posWS = mul(unity_ObjectToWorld, v.vertex);
o.uv0 = v.uv0;
o.nDirWS = UnityObjectToWorldNormal(v.normal);
o.tDirWS = normalize(mul(unity_ObjectToWorld, float4 (v.tangent.xyz,0.0)).xyz);
o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS) * v.tangent.w);
return o;
}
//输出结构>>>像素
float4 frag(VertexOutput i) : color{
// 准备向量
float3 nDirTS = UnpackNormal(tex2D(_NormalMap, i.uv0)).rgb;
float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);
float3 nDirWS = normalize(mul(nDirTS, TBN)); // 计算Fresnel 计算vrDirWS
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz); // 计算Fresnel
float3 vrDirWS = reflect(-vDirWS, nDirWS);
// 准备中间变量
float vdotn = dot(vDirWS, nDirWS);
// 光照模型
float3 var_Cubemap = texCUBElod(_Cubemap, float4(vrDirWS, _CubemapMip)).rgb;// 采样Cubemap
float fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow);
float3 envSpecLighting = var_Cubemap * fresnel * _EnvSpecInt;
// 返回值
return float4(envSpecLighting, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
七、OldSchoolPro
代码:
Shader "Unlit/17_OldSchoolPro"
{
Properties
{
[Header(Texture)]
_MainTex ("RGB:基础颜色 A:环境遮罩", 2D) = "white" {}
_NormTex ("RGB:法线贴图", 2D) = "bump" {}
_SpecTex ("RGB:高光颜色 A:高光次幂", 2D) = "gray" {}
_EmitTex ("RGB:自发光贴图", 2d) = "black" {}
_Cubemap ("RGB:环境贴图", cube) = "_Skybox" {}
[Header(Diffuse)]
_MainCol ("基本色", Color) = (0.5, 0.5, 0.5, 1.0)
_EnvDiffInt ("环境漫反射强度", Range(0, 1)) = 0.2
_EnvUpCol ("环境天顶颜色", Color) = (1.0, 1.0, 1.0, 1.0)
_EnvSideCol ("环境水平颜色", Color) = (0.5, 0.5, 0.5, 1.0)
_EnvDownCol ("环境地表颜色", Color) = (0.0, 0.0, 0.0, 0.0)
[Header(Specular)]
_SpecPow ("高光次幂", Range(1, 90)) = 30
_EnvSpecInt ("环境镜面反射强度", Range(0, 5)) = 0.2
_FresnelPow ("菲涅尔次幂", Range(0, 5)) = 1
_CubemapMip ("环境球Mip", Range(0, 7)) = 0
[Header(Emission)]
_EmitInt ("自发光强度", range(1, 10)) = 1
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "AutoLight.cginc"//投影头文件
#include "Lighting.cginc"
#include "UnityCG.cginc"
//输入参数
// Texture
uniform sampler2D _MainTex;
uniform sampler2D _NormTex;
uniform sampler2D _SpecTex;
uniform sampler2D _EmitTex;
uniform samplerCUBE _Cubemap;
// Diffuse
uniform float3 _MainCol;
uniform float _EnvDiffInt;
uniform float3 _EnvUpCol;
uniform float3 _EnvSideCol;
uniform float3 _EnvDownCol;
// Specular
uniform float _SpecPow;
uniform float _FresnelPow;
uniform float _EnvSpecInt;
uniform float _CubemapMip;
// Emission
uniform float _EmitInt;
//输入结构
struct VertexInput{
float4 vertex : POSITION; // 顶点信息
float2 uv0 : TEXCOORD0; // UV信息
float4 normal : NORMAL; // 法线信息
float4 tangent : TANGENT; // 切线信息
};
//输出结构
struct VertexOutput{
float4 pos : SV_POSITION; // 屏幕顶点位置
float2 uv0 : TEXCOORD0; // UV0
float4 posWS : TEXCOORD1; // 世界空间顶点位置
float3 nDirWS : TEXCOORD2; // 世界空间法线方向
float3 tDirWS : TEXCOORD3; // 世界空间切线方向
float3 bDirWS : TEXCOORD4; // 世界空间副切线方向
LIGHTING_COORDS(5,6) // 投影相关
};
//输入结构>>>顶点shader>>>输出结构
VertexOutput vert (VertexInput v){
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos(v.vertex);
o.posWS = mul(unity_ObjectToWorld, v.vertex);
o.uv0 = v.uv0;
o.nDirWS = UnityObjectToWorldNormal(v.normal);
o.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); // 切线方向 OS>WS
o.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w); // 副切线方向
TRANSFER_VERTEX_TO_FRAGMENT(o)//投影
return o;
}
//输出结构>>>像素
float4 frag(VertexOutput i) : color{
//准备向量
float3 nDirTS = UnpackNormal(tex2D(_NormTex, i.uv0)).rgb;
float3x3 TBN = float3x3(i.tDirWS,i.bDirWS,i.nDirWS);
float3 nDirWS = normalize(mul(nDirTS,TBN));
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz-i.posWS.xyz);
float3 vrDirWS = reflect(-vDirWS,nDirWS);
float3 lDirWS = _WorldSpaceLightPos0.xyz;
float3 lrDirWS = reflect(-lDirWS,nDirWS);
//准备中间向量
float ndotl = dot(nDirWS,lDirWS);
float vdotr = dot(vDirWS,lrDirWS);
float vdotn = dot(vDirWS,nDirWS);
//采样纹理
float4 var_MainTex = tex2D(_MainTex, i.uv0);
float4 var_SpecTex = tex2D(_SpecTex, i.uv0);
float3 var_EmitTex = tex2D(_EmitTex, i.uv0).rbg;
float3 var_Cubemap = texCUBElod(_Cubemap, float4(vrDirWS,lerp(_CubemapMip,0.0,var_SpecTex.a))).rgb;//youwenti
//光照模型(直接光照)
float3 baseCol = var_MainTex.rgb*_MainCol;
float lambert = max(0.0,ndotl);
float phong = pow(max(0.0,vdotr), _SpecPow);
float specCol = var_SpecTex.rgb;
float specPow = lerp(1,_SpecPow, var_SpecTex.a);//budong!!!
float shadow = LIGHT_ATTENUATION(i);
float3 dirLighting = (baseCol * lambert + specCol * phong)* _LightColor0 * shadow;
//光照模型(环境光照)
//计算各部分遮罩
float upMask = max(0.0, nDirWS.g);
float downMask = max(0.0, -nDirWS.g);
float sideMask = 1.0 - upMask - downMask;
//混合环境色
float3 envCol = _EnvUpCol*upMask +
_EnvSideCol*sideMask +
_EnvDownCol*downMask;
float fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow);
float occlusion = var_MainTex.a;
//计算环境光照
float3 envLighting = (baseCol* envCol* _EnvDiffInt +
var_Cubemap * fresnel * _EnvSpecInt * var_SpecTex.a) * occlusion;
//自发光部分
float3 emission = var_EmitTex * _EmitInt;
//返回结果
float3 finaRGB = dirLighting + envLighting + emission;
return float4(finaRGB,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
八、面板参数声明格式
常用顶点shader操作
方法归库
- 作业:
Shader "Unlit/18_dota2"
{
Properties
{
[Header(Texture)]
_MainTex ("RGB:基础颜色 A:透贴", 2D) = "white"{}
_MaskTex ("R:高光强度 G:边缘光强度 B:高光颜色 A:高光次幂", 2D) = "black" {}
_NormTex ("RGB:法线贴图", 2D) = "bump"{}
_MatelnessMask ("金属度遮罩",2D) = "black"{}
_EmissionMask ("自发光遮罩",2D) = "black"{}
_DiffWarpTex ("颜色Warp图",2D) = "gray"{}
_FresWarpTex ("菲涅尔Warp图",2D) = "gray"{}
_Cubemap ("环境球", cube) = "_Skybox" {}
_LightCol ("光颜色", color) = (1.0, 1.0, 1.0, 1.0)
_SpecPow ("高光次幂", range(0.0, 30.0)) = 5
_SpecInt ("高光强度", range(0.0, 10.0)) = 5
_EnvCol ("环境光颜色", color) = (1.0, 1.0, 1.0, 1.0)
_EnvDiffInt ("环境漫反射强度", range(0.0, 5.0)) = 0.5
_EnvSpecInt ("环境镜面反射强度", range(0.0, 10.0)) = 0.5
_RimCol ("轮廓光颜色", color) = (1.0, 1.0, 1.0, 1.0)
_RimInt ("轮廓光强度", range(0.0, 3.0)) = 1.0
_EmitInt ("自发光强度", range(0.0, 10.0)) = 1.0
[HideInInspector]
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_Color ("Main Color", Color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
Name "FORWARD"
Tags { "LightMode"="ForwardBase" }
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"
#pragma multi_compile_fwdbase_fullshadows
//输入参数
uniform sampler2D _MainTex;
uniform sampler2D _MaskTex;
uniform sampler2D _NormTex;
uniform sampler2D _MatelnessMask;
uniform sampler2D _EmissionMask;
uniform sampler2D _DiffWarpTex;
uniform sampler2D _FresWarpTex;
uniform samplerCUBE _Cubemap;
uniform half3 _LightCol;
uniform half _SpecPow;
uniform half _SpecInt;
uniform half3 _EnvCol;
uniform half _EnvDiffInt;
uniform half _EnvSpecInt;
uniform half3 _RimCol;
uniform half _RimInt;
uniform half _EmitInt;
uniform half3 _Color;
uniform half _Cutoff;
//输入结构
struct VertexInput{
float4 vertex : POSITION; // 顶点信息
float2 uv : TEXCOORD0; // UV信息
float4 normal : NORMAL; // 法线信息
float4 tangent : TANGENT; // 切线信息
};
//输出结构
struct VertexOutput{
float4 pos : SV_POSITION; // 屏幕顶点位置
float4 posWS : TEXCOORD1; // 世界空间顶点位置
float2 uv : TEXCOORD0;
float3 nDirWS : TEXCOORD2; // 世界空间法线方向
float3 tDirWS : TEXCOORD3; // 世界空间切线方向
float3 bDirWS : TEXCOORD4; // 世界空间副切线方向
LIGHTING_COORDS(5,6) // 投影相关
};
//输入结构>>>顶点shader>>>输出结构
VertexOutput vert (VertexInput v){
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos(v.vertex);
o.posWS = mul(unity_ObjectToWorld, v.vertex);
o.uv = v.uv;
o.nDirWS = UnityObjectToWorldNormal(v.normal);
o.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); // 切线方向 OS>WS
o.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w); // 副切线方向
TRANSFER_VERTEX_TO_FRAGMENT(o)//投影
return o;
}
//输出结构>>>像素
float4 frag(VertexOutput i) : color{
//向量准备
half3 nDirTS = UnpackNormal(tex2D(_NormTex, i.uv)).rgb;
half3x3 TBN = half3x3(i.tDirWS,i.bDirWS,i.nDirWS);
half3 nDirWS = normalize(mul(nDirTS,TBN));
half3 vDirWS = normalize(_WorldSpaceCameraPos.xyz-i.posWS.xyz);
half3 vrDirWS = reflect(-vDirWS,nDirWS);
half3 lDirWS = _WorldSpaceLightPos0.xyz;
half3 lrDirWS = reflect(-lDirWS,nDirWS);
//准备中间向量
half ndotl = dot(nDirWS,lDirWS);
half vdotr = dot(vDirWS,lrDirWS);
half ndotv = dot(vDirWS,nDirWS);
//采样纹理
half4 var_MainTex = tex2D(_MainTex, i.uv);
half4 var_MaskTex = tex2D(_MaskTex, i.uv);
half var_MatelnessMask = tex2D(_MatelnessMask, i.uv).r;
half var_EmissionMask = tex2D(_EmissionMask, i.uv).r;
half3 var_FresWarpTex = tex2D(_FresWarpTex, ndotv).rgb; //ndotv不明白
half3 var_Cubemap = texCUBElod(_Cubemap, float4(vrDirWS,lerp(8.0,0.0,var_MaskTex.a))).rgb;
//提取信息
half3 baseCol = var_MainTex.rgb;
half opacity = var_MainTex.a;
half specInt = var_MaskTex.r;
half rimInt = var_MaskTex.g;
half specTint = var_MaskTex.b;
half specPow = var_MaskTex.a;
half matellic = var_MatelnessMask;
half emitInt = var_EmissionMask;
half3 envCube = var_Cubemap;
half shadow = LIGHT_ATTENUATION(i);
//光照模型
// 漫反射颜色 镜面反射颜色
half3 diffCol = lerp(baseCol, half3(0.0, 0.0, 0.0), matellic);
half3 specCol = lerp(baseCol, half3(0.3, 0.3, 0.3), specTint) * specInt;
//菲涅尔
half3 fresnel = lerp(var_FresWarpTex, 0.0, matellic);
half fresnelCol = fresnel.r; // 无实际用途
half fresnelRim = fresnel.g;
half fresnelSpec = fresnel.b;
//光源漫反射
half halfLambert = ndotl * 0.5 + 0.5;
half3 var_DiffWarpTex = tex2D(_DiffWarpTex, half2(halfLambert, 0.2));
half3 dirDiff = diffCol * var_DiffWarpTex * _LightCol;
// 光源镜面反射
half phong = pow(max(0.0, vdotr), specPow * _SpecPow);
half spec = phong * max(0.0, ndotl);
spec = max(spec, fresnelSpec);
spec = spec * _SpecInt;
half3 dirSpec = specCol * spec * _LightCol;
// 环境漫反射
half3 envDiff = diffCol * _EnvCol * _EnvDiffInt;
// 环境镜面反射
half reflectInt = max(fresnelSpec, matellic) * specInt;
half3 envSpec = specCol * reflectInt * envCube * _EnvSpecInt;
// 轮廓光
half3 rimLight = _RimCol * fresnelRim * rimInt * max(0.0, nDirWS.g) * _RimInt;
// 自发光
half3 emission = diffCol * emitInt * _EmitInt;
// 透明剪切
clip(opacity - _Cutoff);
// 混合
half3 finalRGB = (dirDiff + dirSpec) * shadow + envDiff + envSpec + rimLight + emission;
return float4(finalRGB,1.0);
}
ENDCG
}
}
FallBack "Legacy Shaders/Transparent/Cutout/VertexLit"
}
九、 透明度
Properties {
_MainTex ("RGB:颜色 A:透贴", 2d) = "gray"{}
_Cutoff ("透切阈值", range(0.0, 1.0)) = 0.5
}
half4 frag(VertexOutput i) : COLOR {
half4 var_MainTex = tex2D(_MainTex, i.uv); // 采样贴图 RGB颜色 A透贴
clip(var_MainTex.a - _Cutoff); // 透明剪切
return var_MainTex; // 返回值
}
Properties {
_MainTex ("RGB:颜色 A:透贴", 2d) = "gray"{}
}
Blend One OneMinusSrcAlpha
half4 frag(VertexOutput i) : COLOR {
half4 var_MainTex = tex2D(_MainTex, i.uv); // 采样贴图 RGB颜色 A透贴
return var_MainTex; // 返回值
}
Properties {
_MainTex ("RGB:颜色", 2d) = "gray"{}
}
Blend One One
half4 frag(VertexOutput i): COLOR{
half3 var_MainTex = tex2D(_MainTex, i.uv).rgb; // 采样贴图 RGB颜色A透贴不必须
return half4(var_MainTex, 1.0); // 返回值
}
Shader "Unlit/19_BlendEnum"
{
Properties
{
_MainTex ("RGB:颜色 A:透贴", 2D) = "gray" {}
[Enum(UnityEngine.Rendering.BlendMode)]
_BlendSrc ("混合源乘子",int) = 0
[Enum(UnityEngine.Rendering.BlendMode)]
_BlendDst ("混合目标乘子",int) = 0
[Enum(UnityEngine.Rendering.BlendOp)]
_BlendOp ("混合符",int) = 0
}
SubShader
{
Tags {
"Queue"="Transparent" // 控制渲染队列,使Unity能够先渲染不透明物体,再渲染带透明度的物体
"RenderType"="Transparent" //对应改为Cutout
"ForceNoShadowCasting"="True" //关闭阴影投射
"IgnoreProjector"="True" //不响应投射器
}
Pass
{
Name "FORWARD"
Tags {
"LightMode" = "ForwardBase"
}
BlendOp [_BlendOp] // 可自定义混合算符
Blend [_BlendSrc] [_BlendDst] // 可自定义混合模式
// Cull Off AB涉及到了透明度混合,因此想要渲染双面显示,不能直接简单地写 Cull Off ,应该用2个Pass来分别渲染前后面
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
//输入参数
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
//输入结构
struct VertexInput{
float4 vertex : POSITION; //顶点位置
float2 uv : TEXCOORD0; //uv信息 采样贴图
};
//输出结构
struct VertexOutput{
float4 pos : SV_POSITION; //顶点位置
float2 uv : TEXCOORD0; //uv信息
};
VertexOutput vert (VertexInput v){
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex); //uv信息 支持Tiling Offset
return o;
}
half4 frag (VertexOutput i) : COLOR{
half4 var_MainTex = tex2D(_MainTex, i.uv); //采样贴图 RGB颜色 A透贴
return var_MainTex;
}
ENDCG
}
}
}