前向渲染(ForwardAdd)

作者:追风剑情 发布于:2018-12-25 17:11 分类:Shader

这个示例Shader支持全局光照(GI),光照处理(Base Pass & Additional Pass)、阴影处理(投射&接收)、Lightmap、雾效


  1. // Upgrade NOTE: replaced '_LightMatrix0' with 'unity_WorldToLight'
  2.  
  3. Shader "Custom/ReceiveShadowsTest"
  4. {
  5. Properties
  6. {
  7. [Header(Main Texture)]
  8. _MainTex ("Base (RGB)", 2D) = "white" {}
  9.  
  10. [Space]
  11.  
  12. //对纹理调色
  13. _Color ("Color", Color) = (1,1,1,1)
  14. //高光颜色
  15. _Specular ("Specular", Color) = (1,1,1,1)
  16. //控制高光亮度(值越小越亮)
  17. //[PowerSlider(2)] //定义滑条的值以指数曲线变化,参数定义了底数
  18. _Gloss ("Specular Power", Range(0, 30)) = 1
  19.  
  20. //用个Toggle开关来控制是否显示光照图
  21. //[Toggle] //会隐式定义一个_USELIGHTMAP_ON开关 (大写属性名_ON)
  22. [Toggle(USE_LIGHTMAP)] //显示指定开关名称
  23. _UseLightmap ("Use Lightmap", Float) = 0
  24.  
  25. [Space(5)]
  26. [Header(More Settings)]
  27.  
  28. //枚举
  29. //渲染状态枚举只能使用UnityEngine.Rendering空间下的定义
  30. [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend Mode", Float) = 1
  31. [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend Mode", Float) = 1
  32. [Enum(Off, 0, On, 1)] _ZWrite ("ZWrite", Float) = 1
  33. [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest ("ZTest", Float) = 4
  34. [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull Mode", Float) = 2
  35.  
  36. //需要在SubShader中声明
  37. //#pragma multi_compile _OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY
  38. //keyword命名规则为: 大写属性名_枚举名
  39. //[KeywordEnum(None, Add, Multiply)] _Overlay ("Overlay mode", Float) = 0
  40. }
  41. SubShader
  42. {
  43. Tags { "RenderType" = "Opaque" }
  44. LOD 100
  45.  
  46. Blend [_SrcBlend] [_DstBlend]
  47. ZWrite [_ZWrite]
  48. ZTest [_ZTest]
  49. Cull [_Cull]
  50.  
  51. // 这个Pass同时处理未烘焙&已烘焙的物体显示
  52. Pass {
  53. //ForwardBase说明:
  54. //ambient, main directional light, vertex/SH lights and lightmaps are applied
  55. //只会接收环境光,最亮的平行光,逐顶点/球谐光以及光照图
  56. Tags { "LightMode"="ForwardBase" }
  57.  
  58. CGPROGRAM
  59. //确保可以正常访问光照变量的值
  60. #pragma multi_compile_fwdbase
  61. #pragma vertex vert
  62. #pragma fragment frag
  63. #include "UnityCG.cginc"
  64. #include "Lighting.cginc"
  65. //计算阴影所用到的宏都在Autolight.cginc文件中
  66. #include "Autolight.cginc"
  67.  
  68. //shader_feature这个定义的keyword无法通过脚本进行控制,只能通过Shader面板控制
  69. #pragma shader_feature USE_LIGHTMAP
  70. //multi_compile这个定义的keyword可以通过脚本设置开启或关闭
  71. //Material.EnableKeyword()、Material.DisableKeyword()
  72. //Shader.EnableKeyword()、Shader.DisableKeyword()
  73. //定义keyword,一个keyword会生成一个shader变种
  74. //#pragma multi_compile __ USE_LIGHTMAP
  75.  
  76. //开启雾效
  77. #pragma multi_compile_fog
  78. #define USING_FOG (defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2))
  79.  
  80. struct appdata
  81. {
  82. //模型空间坐标
  83. //TRANSFER_SHADOW宏用到了这个变量名
  84. float3 vertex : POSITION;
  85. //模型空间法线
  86. float3 normal : NORMAL;
  87. //主纹理uv坐标
  88. float2 uv : TEXCOORD0;
  89. //光照图uv坐标
  90. float2 uv1 : TEXCOORD1;
  91. };
  92.  
  93. struct v2f
  94. {
  95. //裁剪空间坐标
  96. float4 pos : SV_POSITION;
  97. //世界空间坐标
  98. float3 worldPosition : TEXCOORD0;
  99. //世界空间法线
  100. float3 worldNormal : TEXCOORD1;
  101. //为了节约寄存器,主纹理uv坐标放到xy上,光照图uv坐标放到zw上
  102. float4 uv : TEXCOORD2;
  103. //这个宏的作用很简单,就是声明一个用于对阴影纹理采样的坐标。
  104. //需要注意的是,这个宏的参数需要是下一个可用的插值寄存器的索引值
  105. SHADOW_COORDS(3)
  106.  
  107. //雾
  108. #if USING_FOG
  109. fixed fog : TEXCOORD5;
  110. #endif
  111. };
  112.  
  113. sampler2D _MainTex;
  114. float4 _MainTex_ST;
  115. fixed4 _Color;
  116. fixed4 _Specular;
  117. float _Gloss;
  118.  
  119. v2f vert (appdata v)
  120. {
  121. v2f o;
  122. //模型坐标转裁剪空间坐标
  123. o.pos = UnityObjectToClipPos(v.vertex);
  124. //模型空间坐标转到世界空间坐标
  125. o.worldPosition = mul(unity_ObjectToWorld, v.vertex).xyz;
  126. //将法线从模型空间转到世界空间
  127. o.worldNormal = UnityObjectToWorldNormal(v.normal);
  128. //计算主纹理的uv坐标(考虑 缩放&平移)
  129. o.uv.xy = v.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw;
  130.  
  131. #if USE_LIGHTMAP
  132. //计算光照图的uv坐标(考虑 缩放&平移)
  133. o.uv.zw = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
  134. #else
  135. //在顶点着色器返回之前添加这个宏.
  136. //这个宏用于在顶点着色器中计算上一步中声明的阴影纹理坐标
  137. TRANSFER_SHADOW(o);
  138. #endif
  139.  
  140. //雾
  141. #if USING_FOG
  142. float3 eyePos = UnityObjectToViewPos(v.vertex);
  143. float fogCoord = length(eyePos.xyz);
  144. UNITY_CALC_FOG_FACTOR_RAW(fogCoord);
  145. o.fog = saturate(unityFogFactor);
  146. #endif
  147.  
  148. return o;
  149. }
  150.  
  151. fixed4 frag (v2f i) : SV_Target
  152. {
  153. fixed4 col;
  154.  
  155. //环境光
  156. fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
  157. //用纹理颜色作为漫反射颜色
  158. fixed3 albedo = tex2D(_MainTex, i.uv.xy).rgb * _Color;
  159.  
  160. #if USE_LIGHTMAP
  161. //光照图采样
  162. half4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uv.zw);
  163. fixed3 bakedColor = DecodeLightmap(bakedColorTex);
  164. col = fixed4(ambient + albedo * bakedColor, 1.0);
  165. #else
  166. fixed3 worldNormal = normalize(i.worldNormal);
  167. fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPosition));
  168. fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPosition));
  169. fixed3 halfDir = normalize(worldLightDir + viewDir);
  170. //_LightColor0记录了最亮的平行光颜色
  171. //漫反射光
  172. fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
  173. //高光
  174. fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
  175. //对于Base Pass来说,它处理的逐像素光源类型一定是平行光。
  176. //由于平行光可以认为是没有衰减的,因此这里我们直接令衰减值为1.0
  177. //衰减值
  178. fixed atten = 1.0;
  179. //计算阴影值
  180. //如果关闭了阴影,SHADOW_COORDS和TRANSFER_SHADOW没有任何作用
  181. //如果关闭了阴影,SHADOW_ATTENUATION会返回1
  182. fixed shadow = SHADOW_ATTENUATION(i);//对阴影纹理采样
  183. col = fixed4(ambient + (diffuse + specular) * shadow * atten, 1.0);
  184. #endif
  185.  
  186. //雾
  187. #if USING_FOG
  188. col.rgb = lerp(unity_FogColor.rgb, col.rgb, i.fog);
  189. #endif
  190.  
  191. return col;
  192. }
  193. ENDCG
  194. }
  195.  
  196. Pass {
  197. //ForwardAdd说明: 与ForwardBase中的处理没多大区别,只是要判断下光源类型
  198. //为场景中其他逐像素光源定义Additional Pass
  199. Tags { "LightMode"="ForwardAdd" }
  200. //与缓冲区中的ForwardBase处理结果混合
  201. Blend One One
  202.  
  203. CGPROGRAM
  204. //multi_compile_fwdadd指令可以保证我们在Additional Pass中访问到正确的光照变量
  205. //获得正确的光照变量,不处理阴影
  206. #pragma multi_compile_fwdadd
  207. //multi_compile_fwdadd_fullshadows指令可以保证我们在Additional Pass中访问到正确的光照变量
  208. //获得正确的光照变量,要处理阴影
  209. //#pragma multi_compile_fwdadd_fullshadows
  210. #pragma vertex vert
  211. #pragma fragment frag
  212. #include "UnityCG.cginc"
  213. #include "Lighting.cginc"
  214. #include "Autolight.cginc"
  215.  
  216. #pragma shader_feature USE_LIGHTMAP
  217.  
  218. struct appdata
  219. {
  220. //模型空间坐标
  221. //TRANSFER_SHADOW宏用到了这个变量名
  222. float3 vertex : POSITION;
  223. //模型空间法线
  224. float3 normal : NORMAL;
  225. //主纹理uv坐标
  226. float2 uv : TEXCOORD0;
  227. };
  228.  
  229. struct v2f
  230. {
  231. //裁剪空间坐标
  232. float4 pos : SV_POSITION;
  233. //世界空间坐标
  234. float3 worldPosition : TEXCOORD0;
  235. //世界空间法线
  236. float3 worldNormal : TEXCOORD1;
  237. //主纹理uv坐标
  238. float2 uv : TEXCOORD2;
  239. };
  240.  
  241. sampler2D _MainTex;
  242. float4 _MainTex_ST;
  243. fixed4 _Color;
  244. fixed4 _Specular;
  245. float _Gloss;
  246.  
  247. v2f vert (appdata v)
  248. {
  249. v2f o;
  250. //模型坐标转裁剪空间坐标
  251. o.pos = UnityObjectToClipPos(v.vertex);
  252. //模型空间坐标转到世界空间坐标
  253. o.worldPosition = mul(unity_ObjectToWorld, v.vertex).xyz;
  254. //将法线从模型空间转到世界空间
  255. o.worldNormal = UnityObjectToWorldNormal(v.normal);
  256. //计算主纹理的uv坐标(考虑 缩放&平移)
  257. o.uv = v.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw;
  258.  
  259. return o;
  260. }
  261.  
  262. fixed4 frag (v2f i) : SV_Target
  263. {
  264. fixed4 col;
  265.  
  266. #if USE_LIGHTMAP
  267. col = fixed4(0, 0, 0, 0);
  268. #else
  269. fixed3 worldNormal = normalize(i.worldNormal);
  270. fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPosition));
  271. //-----处理不同光源的方向-----//
  272. #ifdef USING_DIRECTIONAL_LIGHT
  273. //平行光
  274. fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
  275. #else
  276. //点光源 或 聚光灯
  277. fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPosition.xyz);
  278. #endif
  279. fixed3 halfDir = normalize(worldLightDir + viewDir);
  280.  
  281. //-----处理不同光源的衰减-----//
  282. #ifdef USING_DIRECTIONAL_LIGHT
  283. fixed atten = 1.0;//衰减值
  284. #else
  285. float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPosition, 1)).xyz;
  286. //尽管我们可以使用数学表达式来计算给定点相对于点光源或聚光灯的衰减,
  287. //但这些计算往往涉及开根号、除法等计算量相对较大的操作,因此Unity选择了使用一张纹理作为
  288. //查找表(Lookup Table, LUT),以在片元着色器中得到光源的衰减。我们首先得到光源空间下的坐标,
  289. //然后使用该坐标对衰减纹理进行采样得到衰减值。
  290. fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
  291. #endif
  292. //用纹理颜色作为漫反射颜色
  293. fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color;
  294. //漫反射光
  295. fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
  296. //高光
  297. fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
  298.  
  299. col = fixed4((diffuse + specular) * atten, 1.0);
  300. #endif
  301.  
  302. return col;
  303. }
  304. ENDCG
  305. }
  306.  
  307. // 投射阴影Pass
  308. // 没这个Pass物体无法向其他物体投射阴影
  309. Pass
  310. {
  311. Name "ShadowCaster"
  312. Tags { "LightMode" = "ShadowCaster" }
  313.  
  314. //开启深度写入
  315. ZWrite On
  316. //开启深度测试(<=)
  317. ZTest LEqual
  318. //关闭裁剪
  319. Cull Off
  320.  
  321. CGPROGRAM
  322. #pragma vertex vert
  323. #pragma fragment frag
  324. #pragma target 2.0
  325. //开启阴影投射
  326. #pragma multi_compile_shadowcaster
  327. #include "UnityCG.cginc"
  328.  
  329. struct v2f {
  330. V2F_SHADOW_CASTER;
  331. };
  332.  
  333. v2f vert( appdata_base v )
  334. {
  335. v2f o;
  336. TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
  337. return o;
  338. }
  339.  
  340. float4 frag( v2f i ) : SV_Target
  341. {
  342. SHADOW_CASTER_FRAGMENT(i)
  343. }
  344. ENDCG
  345. }
  346. }
  347. }


效果截图

1111.png2222.png


官方内置编译命令说明

1111.png

标签: Shader

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号