1、反射效果
在Unity Shader中,反射效果模拟了物体表面反射环境光的特性,使得物体看起来像镜子或金属表面,能够反射周围环境的图像。
2、反射效果的原理
反射效果的原理就是利用 立方体纹理(CubeMap)进行环境映射,我们利用摄像机看向物体表面顶点的方向向量作为入射光,结合顶点法线向量可以算出反射向量,然后利用反射方向向量在立方体纹理中进行采样,得到最终反射的颜色。
光路可逆原则:
如果光在某一路径上从点A传播到点B,那么光在同一路径上可以从点B传播回点A。换句话说,
光的传播路径在没有任何变化的情况下可以被反向利用。
3、反射的基础实现
(1)属性声明: 我们将声明2个关键属性,立方体纹理,反射率(0~1)之间
(2)顶点着色器
- 顶点坐标转裁剪坐标
- 顶点法线转世界坐标
- 顶点坐标转世界坐标
- 世界空间下 视角方向计算
- 视角反向逆向得到反射方向
(3)片元着色器
- 立方体纹理采样(利用texCUBE函数)
- 结合反射程度返回最终颜色
Shader "ShaderProj/5/RefelectBase"
{
Properties
{
_Cube ("CubeMap", Cube) = ""{} // 立方体纹理
_Refectivity ("Refelctivity", Range(0, 1)) = 1 // 反射率
}
SubShader
{
Tags {
"RenderType"="Opaque"
"Queue" ="Geometry"
}
Pass
{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
samplerCUBE _Cube;
float _Refectivity;
struct v2f
{
float4 pos:SV_POSITION;
float3 worldRefl:TEXCOORD0; //世界空间下的反射向量
};
v2f vert (appdata_base v)
{
v2f data;
data.pos = UnityObjectToClipPos(v.vertex);
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
// 计算视角方向
fixed3 worldViewDir = UnityWorldSpaceViewDir(worldPos);
data.worldRefl = reflect(-worldViewDir, worldNormal);
return data;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 cubemapColor = texCUBE(_Cube, i.worldRefl);
return cubemapColor * _Refectivity;
}
ENDCG
}
}
}
4、反射结合漫反射及阴影
(1)属性声明:我们将加入2个关键属性,漫反射颜色,反射颜色
(2)v2f结构体
因为要在片元着色器中处理光和阴影,需要加入:世界空间法线,世界空间顶点位置,阴影宏
(3)顶点着色器
- 顶点坐标转裁剪坐标
- 顶点法线转世界坐标
- 顶点坐标转世界坐标
- 世界空间下 视角方向计算
- 视角反向逆向得到反射方向
- 阴影相关计算
(4)片元着色器
- 得到光的方向
- 兰伯特漫反射颜色计算
- 立方体纹理采样(利用texCUBE函数)
- 衰减计算
- 最终颜色计算(利用lerp函数)
(5)FallBack "Reflective/VertexLit"
Shader "ShaderProj/5/Refelect"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_ReflectColor ("ReflectColor", Color) = (1,1,1,1)
_Cube ("CubeMap", Cube) = ""{} // 立方体纹理
_Reflectivity ("Refelctivity", Range(0, 1)) = 1 // 反射率
}
SubShader
{
Tags {
"RenderType"="Opaque"
"Queue" ="Geometry"
}
Pass
{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
fixed4 _ReflectColor;
samplerCUBE _Cube;
float _Reflectivity;
struct v2f
{
float4 pos:SV_POSITION;
fixed3 worldNormal:NORMAL;
float3 worldPos:TEXCOORD0;
float3 worldRefl:TEXCOORD1;
SHADOW_COORDS(2)
};
v2f vert (appdata_base v)
{
v2f data;
data.pos = UnityObjectToClipPos(v.vertex);
data.worldNormal = UnityObjectToWorldNormal(v.normal);
data.worldPos = mul(unity_ObjectToWorld, v.vertex);
// 计算视角方向
fixed3 worldViewDir = UnityWorldSpaceViewDir(data.worldPos);
data.worldRefl = reflect(-worldViewDir, data.worldNormal);
TRANSFER_SHADOW(data);
return data;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 diffuse = _LightColor0 * _Color * max(0, dot(normalize(i.worldNormal), worldLightDir));
fixed3 cubemapColor = texCUBE(_Cube, i.worldRefl) * _ReflectColor.rgb;;
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
fixed3 color = UNITY_LIGHTMODEL_AMBIENT + lerp(diffuse, cubemapColor, _Reflectivity) * atten;
return fixed4(color, 1.0);
}
ENDCG
}
}
FallBack "Reflective/VertexLit"
}