根据之前的学习,ForwardPath有两个Pass可以处理光照:
- ForwardBase通道会立即渲染环境光、光照贴图、主方向光和不重要的顶点光。
- ForwardAdd通道被用于增强逐像素光照,每个物体都被这样的光照亮。
Basepass用逐像素渲染的方向光以及所有SH和逐顶点光,可以实现效果:注意:需要开启multi_compile_fwbase计算光照衰减;
- 光照贴图,但不会接受SH光
- 环境光
- 自发光
- 可以有方向光阴影
Additional passes 计算其他影响物体的逐像素光照渲染物体,开启multi_compile_fwdadd 计算光照衰减。默认不支持绘制阴影,除非开启multi_compile_fwdadd _fullshadows指令。
简单实现的代码如下:
//ForwardBase-pass struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2)//内置宏,2是TEXCOORD下标 }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; TRANSFER_SHADOW(o);//内置宏计算阴影 return o; } fixed4 frag(v2f i) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _Kd * _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); //使用了纯反射计算公式2*N平方*L-L fixed3 ref_dir = normalize(2*dot(worldNormal,worldLightDir)*worldNormal - worldLightDir); fixed3 specular = _Ks *_LightColor0.rgb * _Specular.rgb * pow(max(0, dot(ref_dir, viewDir)), _n); UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); return fixed4(ambient + (diffuse + specular) * atten, 1.0); } //ForwardAdd-pass //如果开启了#pragma multi_compile_fwdadd_fullshadows,就可以计算点光源和聚光源产生的阴影 struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2) }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; TRANSFER_SHADOW(o); return o; } fixed4 frag(v2f i) : SV_Target { ffixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); //内置函数UnityWorldSpaceLightDir /*#ifdef USING_DIRECTIONAL_LIGHT fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); #else fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz); endif*/ fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));//normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz); fixed3 ref_dir = normalize(2 * dot(worldNormal, worldLightDir) * worldNormal - worldLightDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(ref_dir,viewDir)), _n); //光照衰减 /*#ifdef USING_DIRECTIONAL_LIGHT fixed atten = 1.0; #else #if defined (POINT) float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;//把顶点所在世界坐标转换到光照空间 fixed atten = tex2D(_LightTexture0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;//dot模拟平方取结果两次组成采样uv坐标 #elif defined (SPOT) float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)); fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL; #else fixed atten = 1.0; #endif #endif*/ //内置函数UNITY_LIGHT_ATTENUATION计算了光照衰减和阴影 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); return fixed4((diffuse + specular) * atten, 1.0); }