unity 天空盒_unity的半透明阴影

常见方案问题

半透明的阴影主要涉及2个功能 投递阴影和接收阴影,投递阴影 unity里比较好实现,可自定义shadowcast的pass 或直接fallback 带这个pass的 内置shader即可。甚至可以不改任何shader 直接同位置摆放一个阴影代替投射物也行,unity支持 不显示自己但只投递阴影的shadowonly 渲染模式。所以不会代码的美术自己也能搞定这问题,网上大量可用教程。

这里讨论的是接受阴影,虽然也有大量教程但都是说一半就停了,基本都是利用 "AutoLight.cginc" 内对shadowmap的计算 然后 渲染队列改成 2500以下。这种篡改了正确排序的做法, 至少有2种错误。1与天空盒遮挡关系,2与远处半透明遮挡关系。如图错误方法 与本方案对比

480c5a86f9f6c2951148fb7a7d4cddb7.png
因为强改渲染顺序 导致 天空混合 和半透明绿球混合错误

c1fbc86432b54138814699cd31d46369.png
正确做法 依然用3000队列渲染 天空和半透明绿球混合正确

原因分析

半透明是个很模糊的概念,至少有2种不同技术角度描述,1根据混合模式,2根据渲染队列。这里讨论隐藏较多的渲染队列问题。

引擎有自己的规则 2500以下按OpaqueGeometry阶段 (不论forward还是deferred)渲染。2501及以上 按TransparentGeometry阶段渲染。这2个阶段有哪些额外区别呢?

1 这2个阶段中间会插入 skybox的渲染。skybox 虽然定义成1000的渲染队列 符合理论的描述 1clear 2天空 3实体从近到远排序渲染 4半透明从远到近排序渲染 。但实际上unity没这样做 而是在2500之后 2501之前渲染,就是所有的实体渲染完渲染。这是为了性能 把天空作为 最远的实体 避免overdraw。

2 这2个阶段引擎渲染的keywords 不同,这里主要是2501之后 不传shadowmap了

代码实现

知道了 这2个原因后 就可以实现 3000队列的阴影接收了。

首先获得shadowmap并传给shader的一个全局贴图变量 这种做法避免了rt拷贝 但不支持多份

c72a559e43fe5659f29276d3dca90a8e.png

然后shader内 有了这张图 就可以 走一般的 阴影流程

	Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }
		Blend SrcAlpha OneMinusSrcAlpha

		Pass
		{
		  Tags{ "LightMode" = "ForwardBase" }

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdbase

			#include "UnityCG.cginc"
		#include "AutoLight.cginc" 

			struct appdata
			{
				float4 vertex : POSITION;
			};

			struct v2f
			{
				float4 pos : SV_POSITION;
				 float3 worldPos : texcoord0;
				 SHADOW_COORDS(2)
			};

			fixed4 _ShadowColor;
			v2f vert(appdata v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.worldPos = mul(UNITY_MATRIX_M, v.vertex);

				 TRANSFER_SHADOW(o);
				return o;
			}

			fixed4 frag(v2f i) : SV_Target
			{


                            UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

				return fixed4(_ShadowColor.rgb * atten ,0.5);
			}
			ENDCG
		}

虽然这样已经好了很多 解决了2个顺序问题,但依然不足以一个真实项目的使用(这就是我一直不肯离开一线开发的原因吧),实际上 还需要考虑 非平行光的阴影,如果仅仅考虑平行光,上面改用screenshadowmask 性能更好些。

应用扩展

如果要支持点光或聚光灯的半透明阴影接收,cs代码和上面一样,但需要增加一个forwardadd的pass 特别是 #pragma multi_compile_fwdadd_fullshadows

.但是这也仅仅是实现单个光源阴影接收。如果要实现 同个场景同时多个光源给半透明物体 投递阴影,可以实现但比较复杂,要么挨个复制shadowmap 挨个采样。要么做个挨个计算出screenshadowmask合并到引擎默认的screenshadowmask 图上,对象渲染不需要额外采样。都是性能不高的做法,最后说下 unity默认不让半透明采样shadowmap的原因我做了个小小猜测,粒子等 大量半透明重叠的情况下 如果半透明默认采样shadowmap会非常非常消耗性能。

完整代码如下

Shader "Unlit/alphaShadow"
{Properties
	{
		_ShadowColor("Shadow Color", Color) = (0.1, 0.1, 0.1, 0.53)
}
SubShader
	{
		Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }
		Blend SrcAlpha OneMinusSrcAlpha

		Pass
		{
		  Tags{ "LightMode" = "ForwardBase" }

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdbase

			#include "UnityCG.cginc"
			#include "AutoLight.cginc" 

			struct appdata
			{
				float4 vertex : POSITION;
			};

			struct v2f
			{
				float4 pos : SV_POSITION;
				 float3 worldPos : texcoord0;
				 SHADOW_COORDS(2)
			};

			fixed4 _ShadowColor;
			v2f vert(appdata v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.worldPos = mul(UNITY_MATRIX_M, v.vertex);

				 TRANSFER_SHADOW(o);
				return o;
			}

			fixed4 frag(v2f i) : SV_Target
			{


				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

				return fixed4(_ShadowColor.rgb * atten ,0.5);
			}
			ENDCG
		}

		Pass
		{
						Blend SrcAlpha OneMinusSrcAlpha

					Tags{ "LightMode" = "ForwardAdd" }

				   CGPROGRAM
				   #pragma vertex vert
				   #pragma fragment frag
				   #pragma multi_compile_fwdadd
		           #pragma multi_compile_fwdadd_fullshadows

			  #include "UnityCG.cginc"
			  #include "AutoLight.cginc" 
				  struct appdata
				  {
					  float4 vertex : POSITION;
				  };

				  struct v2f
				  {
					  float4 pos : SV_POSITION;
					   float3 worldPos : texcoord0;
						#ifdef DIRECTIONAL
					   SHADOW_COORDS(1)
						#endif
				  };

				  fixed4 _ShadowColor;

					 v2f vert(appdata v)
					 {
						 v2f o;
						 o.pos = UnityObjectToClipPos(v.vertex);
						 o.worldPos = mul(UNITY_MATRIX_M, v.vertex);
						#ifdef DIRECTIONAL
						   TRANSFER_SHADOW(o);
						#endif

						 return o;
					 }

					 fixed4 frag(v2f i) : SV_Target
					 {

						UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

						 return fixed4(_ShadowColor.rgb * atten ,0.5);
					 }
					 ENDCG
				 }

}
FallBack "Diffuse"
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值