反射效果
反射效果,是一个渲染中很重要的一个效果。在表现光滑表面(金属,光滑地面),水面(湖面,地面积水)等材质的时候,加上反射,都可以画面效果有很大的提升。
反射,应该属于间接光照的范畴,而非直接光照。我们正常计算光的dot(N,L)或者dot(H,N)时计算的均为直接光照,光源出发经过物体表面该像素点反射进入眼睛的光照。然而这只是一部分,该点还可以接受来自场景中所有其他点反射的光照,如果表面光滑,则表面就可以反射周围的环境(如镜面,金属),到那时这个计算相当复杂,相当于需要在该点法线方向对应的半球空间上做积分运算才可能计算完全的间接光照,而且光线与物体碰撞后并不会消亡,而是经过反射或折射,改变方向后继续传递,相当于无限递归。实时计算现在来看应该还是不太可能的。
各种性能友好的反射方法有好几种。最常见的就是环境贴图的方案,目前使用最多的应该是cube map,将对象周围环境烘焙到贴图上进行采样,进阶版其实就是功能更强大的Reflection Probe了。另外平面反射(Planar Reflection)可以用一个反转的相机再渲染一次场景模拟,更复杂一些的是屏幕空间反射Screen Space Reflection(SSR)。
这里使用的是Cubemap
shader代码如下:
Shader "MyShader/007"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_ReflectionColor("ReflectionColor",Color)=(1,1,1,1)
_ReflectionAmount("ReflectionAmount",Range(0,1))=1
_Cubemap("Cubemap",Cube)="_Skybox"{}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal:NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
float3 worldPos:TEXCOORD2;
float3 worldNormal:TEXCOORD3;
float3 worldViewDir:TEXCOORD4;
float3 worldReflection:TEXCOORD5;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _ReflectionColor;
half _ReflectionAmount;
samplerCUBE _Cubemap;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);
o.worldReflection = reflect(-o.worldViewDir, o.worldNormal);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 worldNormal = normalize(i.worldNormal);
float3 worldLightDir = normalize(UnityWorldSpaceLightDir(worldNormal));
float3 worldViewDir = normalize(i.worldViewDir);
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 diffuse = tex2D(_MainTex, i.uv).rgb*_LightColor0.rgb*saturate(dot(worldNormal, worldLightDir));
fixed3 reflection = texCUBE(_Cubemap, i.worldReflection).rgb*_ReflectionColor.rgb;
fixed3 color = ambient + lerp(diffuse, reflection, _ReflectionAmount);
UNITY_APPLY_FOG(i.fogCoord, color);
return fixed4(color, 1);
}
ENDCG
}
}
}
没有Cubemap的可以看看Cubemap是如何创建的
折射效果
折射率为0.5时的效果图:
折射率为1时的效果图:
代码:
Shader "MyShader/008"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_RefractionColor("ReflectionColor",Color)=(1,1,1,1)
_RefractionAmount("ReflectionAmount",Range(0,1))=1
_Cubemap("Cubemap",Cube)="_Skybox"{}
_RefractionRatio("RefractionRatio",Range(0,1))=0.5//折射率
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal:NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
float3 worldPos:TEXCOORD2;
float3 worldNormal:TEXCOORD3;
float3 worldViewDir:TEXCOORD4;
float3 worldRefraction:TEXCOORD5;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _RefractionColor;
half _RefractionAmount;
half _RefractionRatio;
samplerCUBE _Cubemap;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);
o.worldRefraction = refract(-normalize(o.worldViewDir), normalize(o.worldNormal), _RefractionRatio);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 worldNormal = normalize(i.worldNormal);
float3 worldLightDir = normalize(UnityWorldSpaceLightDir(worldNormal));
float3 worldViewDir = normalize(i.worldViewDir);
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 diffuse = tex2D(_MainTex, i.uv).rgb*_LightColor0.rgb*saturate(dot(worldNormal, worldLightDir));
fixed3 refraction = texCUBE(_Cubemap, i.worldRefraction).rgb*_RefractionColor.rgb;
fixed3 color = ambient + lerp(diffuse, refraction, _RefractionAmount);
UNITY_APPLY_FOG(i.fogCoord, color);
return fixed4(color, 1);
}
ENDCG
}
}
}