反射:
如果不考虑反射效果的话,在场景中的问题的镜面表面的效果应该是用表面的法线对立方体纹理进行采样得到该点的颜色。
所以我们进行反射的计算的时候,只需要求得反射方向,再用反射的方向对立方体纹理进行采样即可。
效果:
代码:
Shader "Custom/Chapter10-Reflaction"
{
Properties
{
_Color("Color Tint",Color)=(1,1,1,1)
//反射颜色
_RefractColor("Reflection Color",Color)=(1,1,1,1)
//反射程度
_RefractAmount("Reflect Amount",Range(0,1))=1
//介质的比例
_RefractRatio("Refraction Ratio",Range(0.1,1))=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;
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(4)
};
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.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(0,dot(worldNormal,worldLightDir));
fixed3 Refraction=texCUBE(_Cubemap,i.worldRefr).rgb*_RefractColor.rgb;
UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);
fixed3 color=ambient +lerp(diffuse,Refraction,_RefractAmount)*atten;
return fixed4(color,1.0);
}
ENDCG
}
}
FallBack "Reflective/VertexLit"
}
折射
同理,求得折射的方向,对立方体纹理进行采样。
实现效果:
代码:
Shader "Custom/Chapter10-Reflaction"
{
Properties
{
_Color("Color Tint",Color)=(1,1,1,1)
//折射颜色
_RefractColor("Reflection Color",Color)=(1,1,1,1)
//折射程度
_RefractAmount("Reflect Amount",Range(0,1))=1
//介质的比例
_RefractRatio("Refraction Ratio",Range(0.1,1))=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;
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(4)
};
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.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(0,dot(worldNormal,worldLightDir));
fixed3 Refraction=texCUBE(_Cubemap,i.worldRefr).rgb*_RefractColor.rgb;
UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);
fixed3 color=ambient +lerp(diffuse,Refraction,_RefractAmount)*atten;
return fixed4(color,1.0);
}
ENDCG
}
}
FallBack "Reflective/VertexLit"
}
菲涅尔反射
通过菲涅尔反射来根据视角方向控制反射程度。比如说在现实生活中,我们在近处看湖边的水面,可以看到水下的石头鱼儿等等,但是当我们走远处再去看湖边的水面的时候我们却只能看到水面,而看不到水下的情景,这就是菲涅尔效果。
菲涅尔近似等式:
-
Schlick菲涅尔近似等式:
f是反射系数,控制菲涅尔反射的强度
-
Empricial菲涅尔近似等式:
效果:
代码:
Shader "Custom/Chapter10-Fresnel"
{
Properties
{
_Color("Color Tint",Color)=(1,1,1,1)
//F0
_FresnelScale("Fresnel Scale",Range(0,1))=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;
float _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(4)
};
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;
fixed3 diffuse = _LightColor0.rgb*_Color.rgb*max(0,dot(worldNormal,worldLightDir));
//计算得到菲涅尔近似
fixed3 Reflection =texCUBE(_Cubemap,i.worldRefl).rgb;
fixed fresnel =_FresnelScale+(1-_FresnelScale)*pow(1-dot(worldViewDir,worldNormal),5);
UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);
//用菲涅尔近似差值反射颜色和漫反射颜色
fixed3 color =ambient +lerp(diffuse,Reflection,saturate(fresnel))*atten;
return fixed4(color,1.0);
}
ENDCG
}
}
FallBack "Reflective/VertexLit"
}