反射
一、反射效果在 UnityShader 中是什么
在 UnityShader 中,反射效果模拟了物体表面反射环境光的特性 使得物体看起来像是镜子或者金属表面,能够反射周围环境的图像
二、基本原理
反射的基本原理就是 利用立方体纹理进行环境映射
利用摄像机看向物体表面顶点的方向作为入射光,结合顶点法线向量可以计算出反射向量,然后利用反射方向向量在立方体纹理中进行采样 
三、基础实现
1.实现思路
- 属性声明 两个关键属性
- 顶点着色器 关键步骤
- 顶点坐标转裁剪坐标
- 顶点法线转世界坐标
- 顶点坐标转世界坐标
- 世界空间下 视角的计算
- 计算反射坐标
- 片元着色器 关键步骤
- 立方体纹理采样(利用 texCUBE 函数)
- 结合反射率返回最终的颜色
2.实现示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| Shader "Unlit/ReflectBase" { Properties { _Cube("Cubemap",Cube) = ""{} _Reflectivity("Reflectivity",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 _Reflectivity;
struct v2f { float4 pos:SV_POSITION; float3 worldRefl:TEXCOORD0; }; v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); float3 worldNormal = UnityObjectToWorldNormal(v.normal); fixed3 worldPos = mul(unity_ObjectToWorld,v.vertex).xyz; fixed3 worldViewDir = -UnityWorldSpaceViewDir(worldPos); o.worldRefl = reflect(worldViewDir,worldNormal); return o; } fixed4 frag(v2f i):SV_TARGET { fixed4 cubemapColor = texCUBE(_Cube,i.worldRefl); return cubemapColor * _Reflectivity; } ENDCG } } }
|
四、反射结合漫反射
1.实现思路
在反射实现的基础之上
- 属性声明
- 漫反射的颜色
- 反射颜色
- v2f 结构体 因为要在片元着色器中处理光和阴影
- 世界空间的法线坐标
- 世界空间的顶点位置
- 阴影宏
- 顶点着色器
- 顶点坐标转换到裁剪空间下
- 顶点法线转世界坐标
- 顶点坐标转世界坐标
- 世界空间下 计算视角的方向(要求从摄相机到顶点的方向)
- 计算得到反射向量
- 阴影计算相关
- 片元着色器
- 得到光的方向
- lambert 漫反射的计算
- 立方体纹理采样
- 利用宏计算阴影衰减和光衰减系数
- 使用 lerp 函数 控制颜色叠加
- 添加阴影投射 SubShader(FallBack "Reflective/VertexLit")
2.实现示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| Shader "Unlit/Reflection" { Properties { _Cube("Cubemap",Cube) = ""{} _Reflectivity("Reflectivity",Range(0,1)) = 1
_Color("Color",Color) = (1,1,1,1) _ReflectColor("ReflectColor",Color) = (1,1,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"
samplerCUBE _Cube; float _Reflectivity; fixed4 _Color; fixed4 _ReflectColor;
struct v2f { float4 pos:SV_POSITION; float3 worldNormal:NORMAL; float3 worldPos:TEXCOORD0; float3 worldRefl:TEXCOORD1;
SHADOW_COORDS(2)
}; v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz; fixed3 worldViewDir = -UnityWorldSpaceViewDir(o.worldPos); o.worldRefl = reflect(worldViewDir,o.worldNormal); TRANSFER_SHADOW(o) return o; } fixed4 frag(v2f i):SV_TARGET { fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0,dot(normalize(i.worldNormal),worldLightDir));
fixed3 cubemapColor = texCUBE(_Cube,i.worldRefl).rgb * _ReflectColor.rgb; UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos); fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb + lerp(diffuse,cubemapColor,_Reflectivity) * atten; return fixed4(color,1.0); } ENDCG } } Fallback "Reflective/VertexLit" }
|