1.反射
//利用立方体纹理完成的反射
Shader "10"{
Properties{//属性
_Color("Color",Color) = (1,1,1,1)//颜色
_Specular("Specular",Color) = (1,1,1,1)//高光颜色
_Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
_MainTex("Main Tex",2D)="write"{}//贴图
_ReflectColor("ReflectColor",Color)=(1,1,1,1)
_ReflectAmount("Reflect Amount",Range(0,1))=1
_Cubemap("Reflection Cubemap",Cube)="_Skybox"{}
}
SubShader{
Tags {"RenderType" = "Opaque" }
pass {
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM //Begin
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
fixed4 _Specular;
float _Gloss;
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _ReflectColor;
float _ReflectAmount;
samplerCUBE _Cubemap;
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;//用于存储纹理坐标
//float3 WorldViewDir:TEXCOORD3;
//float3 WorldRefl:TEXCOORD4;
};
//顶点函数。如 #pragma vertex vert 所声明
v2f vert(a2v v) {
v2f f;
f.WorldNormal= UnityObjectToWorldNormal(v.normal);
f.WorldPos = mul(unity_ObjectToWorld, v.vertex);
f.pos = UnityObjectToClipPos(v.vertex);
f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
return f;
}
fixed4 frag(v2f f) :SV_TARGET0{
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(f.WorldPos));
fixed3 worldNormal=normalize(f.WorldNormal);
fixed3 albedo =tex2D(_MainTex,f.uv).rgb* _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo *( dot(worldNormal,lightDir)*0.5+0.5);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.WorldPos));
fixed3 halfDir = normalize(lightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);
//下面是逐片元计算反射
//float3 worldRefl=reflect(-viewDir,worldNormal);
//fixed3 reflection=texCUBE(_Cubemap,worldRefl).rgb*_ReflectColor.rgb*_ReflectAmount;
//用texCUBE函数对立方体纹理采样。无需对f。WorldRefl归一化。因为仅仅传入方向变量
//下面利用反射球计算反射并修正.不修正则反射对象与被反射对象距离较近时,出现错误(近处物体消失)
float3 reflectDir=reflect(-viewDir,worldNormal);
reflectDir = BoxProjectedCubemapDirection(reflectDir, f.WorldPos, unity_SpecCube0_ProbePosition,
unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);//通过BoxProjectedCubemapDirection函数修正reflectDir
half4 rgbm = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, reflectDir);
half3 reflection = DecodeHDR(rgbm, unity_SpecCube0_HDR);
return fixed4(ambient + diffuse+reflection, 1.0);
}
ENDCG //end
}
}
FallBack "Diffuse"//用来指定一个后备方案。
}
2.折射
//折射
Shader "zheshe"{
Properties{//属性
_Color("Color",Color) = (1,1,1,1)//颜色
_Specular("Specular",Color) = (1,1,1,1)//高光颜色
_Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
_MainTex("Main Tex",2D)="write"{}//贴图
_RefractColor("RefractColor",Color)=(1,1,1,1)
_RefractAmount("Refract Amount",Range(0,1))=1
_RefractRatio("Refraction Ratio",Range(0.1,1))=0.5//折射率
_Cubemap("Reflection Cubemap",Cube)="_Skybox"{}
}
SubShader{
Tags {"RenderType" = "Opaque" }
pass {
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM //Begin
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
fixed4 _Specular;
float _Gloss;
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _RefractColor;
float _RefractAmount;
float _RefractRatio;
samplerCUBE _Cubemap;
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;//用于存储纹理坐标
//float3 WorldViewDir:TEXCOORD3;
//float3 WorldRefl:TEXCOORD4;
};
//顶点函数。如 #pragma vertex vert 所声明
v2f vert(a2v v) {
v2f f;
f.WorldNormal= UnityObjectToWorldNormal(v.normal);
f.WorldPos = mul(unity_ObjectToWorld, v.vertex);
f.pos = UnityObjectToClipPos(v.vertex);
f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
return f;
}
fixed4 frag(v2f f) :SV_TARGET0{
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(f.WorldPos));
fixed3 worldNormal=normalize(f.WorldNormal);
fixed3 albedo =tex2D(_MainTex,f.uv).rgb* _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo *( dot(worldNormal,lightDir)*0.5+0.5);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.WorldPos));
fixed3 halfDir = normalize(lightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);
float3 worldRefr=refract(-viewDir,worldNormal,_RefractRatio);//计算折射方向
fixed3 refraction=texCUBE(_Cubemap,worldRefr).rgb*_RefractColor.rgb;
//第二种方法,默认使用利用反射探头
//float4 rgbm = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefr);
//refraction = DecodeHDR(rgbm, unity_SpecCube0_HDR);
return fixed4(ambient + diffuse+refraction, 1.0);
}
ENDCG //end
}
}
FallBack "Diffuse"//用来指定一个后备方案。
}
3.菲涅尔
(1)官方
//菲涅尔
Shader "10"{
Properties{//属性
_Color("Color",Color) = (1,1,1,1)//颜色
_Specular("Specular",Color) = (1,1,1,1)//高光颜色
_Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
_MainTex("Main Tex",2D)="write"{}//贴图
_ReflectColor("RefractColor",Color)=(1,1,1,1)
_ReflectAmount("Refract Amount",Range(0,1))=1
_ReflecRatio("Refraction Ratio",Range(0.1,1))=0.5//折射率
_Cubemap("Reflection Cubemap",Cube)="_Skybox"{}
_FresnelScale("Fresnel Scale",Range(0,1))=0.5
}
SubShader{
Tags {"RenderType" = "Opaque" }
pass {
Tags{"LightMode" = "ForwardBase"}
Cull Off
CGPROGRAM //Begin
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
fixed4 _Specular;
float _Gloss;
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _ReflectColor;
float _ReflectAmount;
float _ReflectRatio;
samplerCUBE _Cubemap;
float _FresnelScale;
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;//用于存储纹理坐标
//float3 WorldViewDir:TEXCOORD3;
//float3 WorldRefl:TEXCOORD4;
SHADOW_COORDS(3)
};
//顶点函数。如 #pragma vertex vert 所声明
v2f vert(a2v v) {
v2f f;
f.WorldNormal= UnityObjectToWorldNormal(v.normal);
f.WorldPos = mul(unity_ObjectToWorld, v.vertex);
f.pos = UnityObjectToClipPos(v.vertex);
f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
TRANSFER_SHADOW(f);
return f;
}
fixed4 frag(v2f f) :SV_TARGET0{
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(f.WorldPos));
fixed3 worldNormal=normalize(f.WorldNormal);
fixed3 albedo =tex2D(_MainTex,f.uv).rgb* _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo *( dot(worldNormal,lightDir)*0.5+0.5);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.WorldPos));
//fixed3 halfDir = normalize(lightDir + viewDir);
//fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);
fixed3 fresnel=_FresnelScale+(1-_FresnelScale)*pow(1-dot(viewDir,worldNormal),5);
//下面是逐片元计算反射
float3 worldRefl=reflect(-viewDir,worldNormal);
fixed3 reflection=texCUBE(_Cubemap,worldRefl).rgb*_ReflectColor.rgb*_ReflectAmount;
//用texCUBE函数对立方体纹理采样。无需对f。WorldRefl归一化。因为仅仅传入方向变量
//第二种方法,默认使用利用反射探头
float4 rgbm = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);
reflection = DecodeHDR(rgbm, unity_SpecCube0_HDR);
UNITY_LIGHT_ATTENUATION(atten, f, f.WorldPos);
return fixed4(ambient + lerp(diffuse, reflection,saturate(fresnel))* atten, 1.0);
//lerp(a,b,w) 根据w返回a到b之间的插值 a,b,w可以为标量也可以为向量,但是三者应该统一。
//且为向量时长度也需要统一。 相当于 float3 lerp(float3 a, float3 b, float w) { return a + w*(b-a); } 由此可见 当 w=0时返回a.当w = 1时 返回b.
}
ENDCG //end
}
}
FallBack "Diffuse"//用来指定一个后备方案。
}
(2)自悟
//菲涅尔自己
Shader "10"{
Properties{//属性
_Color("Color",Color) = (1,1,1,1)//颜色
//_Specular("Specular",Color) = (1,1,1,1)//高光颜色
//_Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
_MainTex("Main Tex",2D)="write"{}//贴图
_ReflectColor("RefractColor",Color)=(1,1,1,1)
//_ReflectAmount("Refract Amount",Range(0,1))=1
//_ReflecRatio("Refraction Ratio",Range(0.1,1))=0.5//折射率
//_Cubemap("Reflection Cubemap",Cube)="_Skybox"{}
_FresnelScale("Fresnel Scale",Range(0,2))=0.5
}
SubShader{
Tags {"RenderType" = "Opaque" }
pass {
Tags{"LightMode" = "ForwardBase"}
Cull Off
CGPROGRAM //Begin
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
fixed4 _Specular;
float _Gloss;
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _ReflectColor;
//float _ReflectAmount;
//float _ReflectRatio;
//samplerCUBE _Cubemap;
float _FresnelScale;
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;//用于存储纹理坐标
SHADOW_COORDS(3)
};
//顶点函数。如 #pragma vertex vert 所声明
v2f vert(a2v v) {
v2f f;
f.WorldNormal= UnityObjectToWorldNormal(v.normal);
f.WorldPos = mul(unity_ObjectToWorld, v.vertex);
f.pos = UnityObjectToClipPos(v.vertex);
f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
TRANSFER_SHADOW(f);
return f;
}
fixed4 frag(v2f f) :SV_TARGET0{
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(f.WorldPos));
fixed3 worldNormal=normalize(f.WorldNormal);
fixed3 albedo =tex2D(_MainTex,f.uv).rgb* _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo *( dot(worldNormal,lightDir)*0.5+0.5);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.WorldPos));
//fixed3 halfDir = normalize(lightDir + viewDir);
//fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);
fixed fresnel=_FresnelScale*0.5*saturate(length(UnityWorldSpaceViewDir(f.WorldPos)))*(1-dot(viewDir,worldNormal));
//自设的菲涅尔系数。考虑了以下两点:法线与视线夹角越大,点距离与视点越远,反射程度越高
float3 worldRefl=reflect(-viewDir,worldNormal);
float4 rgbm = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);
fixed3 reflection = DecodeHDR(rgbm, unity_SpecCube0_HDR)*_ReflectColor;
fixed3 DiffuseBlendFresnel=lerp(1.5*diffuse,reflection,1.5*saturate(fresnel));
//fixed3 DiffuseBlendFresnel=2*diffuse+reflection*saturate(fresnel);
UNITY_LIGHT_ATTENUATION(atten, f, f.WorldPos);
return fixed4(ambient + DiffuseBlendFresnel, 1.0);
}
ENDCG
}
}
}
4.渲染纹理
//渲染纹理(就是把图片渲染出来罢了)
Shader "11_0"{
properties{
_MainTex("Main Tex",2D)="white"{}
}
SubShader{
Pass {
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
sampler2D _MainTex;
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);//mul(UNITY_MATRIX_MVP,v.vertex);
f.uv=v.texcoord;//无需对渲染纹理进行缩放偏移
f.uv.y=1-f.uv.y;
return f;
}
fixed4 frag(v2f f) :SV_TARGET0{
return tex2D(_MainTex,f.uv);
}
ENDCG
}
}
}
5.镜子
Shader "测试/TestShader" {
SubShader {
Tags { "Queue"="Transparent" "RenderType"="Opaque" }
//"Queue"="Transparent"可以确保该物体渲染时其他所有不透明物体被渲染到屏幕上了,否则透过玻璃看到的物体可能会被漏掉
//"RenderType"="Opaque"为了另一点。。。
//抓取屏幕图像并存储在名为_GrabTex的纹理中
GrabPass { "_GrabTex" }//这句话定义了一个抓取图像的pass,该pass中决定了抓到的图像会被存入哪个纹理(可以省略声明)
// GrabPass { } 是每次Drawcall中的Shader的GrabPass使用时都会中屏幕内容抓取一次绘制的内容,并保存在默认的命为_GrabTexture的纹理中
//GrabPass { "TheGrabTextureName" } 是每一帧Drawcall中的Shader的GrabPass中,第一次调用该GrabPass抓取的内容,保存在TheGrabTextureName的纹理中,
//后面Drawcall或是pass调用的GrabPass { "TheGrabTextureName" }只要TheGrabTextureName纹理名字与之前的TheGrabTextureName相同,直接使用之前Grab好的纹理对象内容。
pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _GrabTex;
float4 _GrabTex_ST;
//对应了在Grabpass里指定的纹理名称。_RefractionTex_TexelSize可以得到纹理大小
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 = TRANSFORM_TEX(v.texcoord, _GrabTex);
return f;
}
fixed4 frag(v2f f) : SV_Target {
fixed3 color = tex2D(_GrabTex, f.uv).rgb;
return fixed4(color, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
6.毛玻璃效果
Shader "渲染纹理/GlassRefraction" {
Properties {
_MainTex ("Main Tex", 2D) = "white"{} //基础纹理
_BumpMap ("Normal Map", 2D) = "bump"{} //法线纹理
_Cubemap ("Environment Cubemap", Cube) = "_Skybox"{} //立方体纹理
_Distortion ("Distortion", Range(0, 1000)) = 100 //控制模拟折射时图像的扭曲程度(Distortion扭曲)
_RefractAmount ("Refraction Amount", Range(0, 1)) = 1 //控制折射程度
}
SubShader {
Tags { "Queue"="Transparent" "RenderType"="Opaque" }
// 1.队列设置成透明的可以保证渲染该物体的时候,其他所有不透明的物体都已经被渲染到屏幕上了
// 这样GrabPass保存屏幕图像的时候才能完整
// 2.渲染类型设置为不透明是为了使用着色器替换的时候,物体可以在被需要时正确的渲染
GrabPass { "_RefractionTex" }// 抓取屏幕图像并保存到纹理 _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;
// 可以得到系统保存的纹素的尺寸大小 1/256,1/512
// 对屏幕图像坐标采样进行偏移的时候需要使用该变量
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 texcoord : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float4 scrPos : TEXCOORD2;
float4 TtoW0 : TEXCOORD3;
float4 TtoW1 : TEXCOORD4;
float4 TtoW2 : TEXCOORD5;
};
v2f vert(a2v v) {
v2f f;
f.pos = UnityObjectToClipPos(v.vertex);
f.worldPos = mul(unity_ObjectToWorld, v.vertex);
f.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
f.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
f.scrPos = ComputeGrabScreenPos(f.pos);
//得到对应被抓取的屏幕图像的采样坐标。计算抓屏的位置,其中主要是将坐标从(-1,1)转化到(0,1)空间并处理DX和GL纹理反向的问题
float3 worldPos = f.worldPos;
fixed3 worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
fixed3 worldTangent = normalize(UnityObjectToWorldDir(v.tangent.xyz));
fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
//Binormal是垂直于Normal、Tangent平面的直线。
f.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
f.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
f.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
//切线空间到世界空间的变换矩阵.之所以要得到此矩阵,是为了要在片元着色器中把法线从切线空间转到世界空间,以对cubemap采样
//是世界转切线矩阵的转置
return f;
}
fixed4 frag(v2f f) : SV_Target {
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(f.worldPos));
fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, f.uv.zw));
// 使用Unity内置的方法,从颜色值得到法线在切线空间的方向
//基础纹理颜色
fixed3 texColor = tex2D(_MainTex, f.uv.xy).rgb;
//反射颜色
fixed3 worldNormal = normalize
(half3(dot(f.TtoW0.xyz, tangentNormal), dot(f.TtoW1.xyz, tangentNormal), dot(f.TtoW2.xyz, tangentNormal)));//世界法线
fixed3 reflDir = reflect(-worldViewDir,worldNormal);
fixed3 reflColor = texCUBE(_Cubemap, reflDir).rgb * texColor;
//玻璃立体纹路部分
fixed2 offset = tangentNormal * _Distortion * _RefractionTex_TexelSize;
//对屏幕图像的采样坐标进行偏移
//选择使用切线空间下的法线方向来进行偏移是因为该空间下的法线可以反映顶点局部空间下的法线方向
f.scrPos.xy = offset + f.scrPos.xy;//对scrPos偏移后再透视除法得到真正的屏幕坐标
//最终折射颜色(立体纹理偏移后的玻璃景象)
fixed3 refrColor = tex2D(_RefractionTex, f.scrPos.xy / f.scrPos.w).rgb;
//使用_RefractAmount混合反射颜色和折射颜色
fixed3 finalColor = lerp(reflColor, refrColor, _RefractAmount);
return fixed4(finalColor, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}