首页 >> 大全

Shader山下(二十七)平面阴影

2023-07-01 大全 58 作者:考证青年

以下摘录自《Unity 3D 开发实战详解》,第10章。

转注:这是一个非常简单且廉价的实时假阴影,比较常用到,据我所知,王者荣耀中就使用了类似的手法。缺点就是比较假,只能投射到平面上,不能应对地面的凹凸,最明显的问题就是会插到墙里去。

转注:需要传给接受阴影的地面(平面)的和。对应的变量分别为和。

Shader "Tut/Shadow/PlanarShadow_3" {
//转注:这里对原作里的平行光计算部分和阴影淡出部分做了整合,略去了点光源计算部分。Properties{_Intensity("atten",range(1,16))=1}SubShader {Pass {Tags {"LightMode" = "ForwardBase"}Material {Diffuce(1,1,1,1)}Lighting On}Pass {Tags {"LightMode" = "ForwardBase"}Cull FrontBlend DstColor SrcColorOffset -1,-1 //使阴影在平面之上CGPROGRAM#pragma vertex vert#pragma fragment frag#inlcude "UnityCG.cginc"float4x4 _World2Ground;float4x4 _Ground2World;float _Intensity;struct v2f{float4 pos:SV_POSITION;float atten:TEXCOORD0;};v2f vert(float4 vertex:POSITION){v2f o;float3 litDir;litDir = WorldSpaceLightDir(vertex);litDir = mul(float3x3(_World2Ground), litDir);//把光源方向转换到接受平面空间litDir = normalize(litDir);float4 vt;vt = mul(_Object2World, vertex);vt = mul(_World2Ground, vt);//将物体顶点转换到接受平面空间vt.xz=vt.xz-(vt.y/litDir.y)*litDir.xz;//用三角形相似计算沿光源方法投射后的xz//上面这行代码可拆解为如下的两行代码,这样可能在进行三角形相似计算时更好理解//vt.x=vt.x-(vt.y/litDir.y)*litDir.x;//vt.z=vt.z-(vt.y/litDir.y)*litDir.z;vt.y=0;//使阴影保持在接受平面上vt=mul(_Ground2World,vt);//返回到世界坐标空间vt=mul(_World2Object,vt);//将结果重新表达为Object Space坐标o.pos = mul(UNITY_MATRIX_MVP, vt);//经典的MVP变换,输出到Clip Spaceo.atten=distance(vertex,vt)/_Intensity;//根据前后定点的距离计算衰减return o;}float4 frag(void) : COLOR{return smoothstep(0,1,i.atten/2);}ENDCG}}
}

在此中,我们首先使用固定管线对物体做了一个简单的照明。在计算阴影的中,首先使用一个可以叠加阴影的混合模式,然后使用z偏移保证出来的阴影在接受平面之上。和分别是我们自定义的两个进出阴影接受平面矩阵(转注:这里原作解释的不好,按字面意思理解即可)。在具体计算中,首先将光源方向和投影物体的顶点都转换到接受平面的空间(接受平面的物体空间),在它们都处于同一空间后,通过简单的三角形近似算法,来计算投影物体顶点沿光线投影后在接受平面上的新位置。因为这是一个Build In的(Built-in)Unity Plane,所以只计算其xz分量即可,并将y分量设为0,这样投影出来的阴影就出现在接受平面上了。投影计算完成后,返回世界空间,然后到投影物体本身的 Space,之后的事情就如通常那样,一个经典的MVP变换即可。

这个方法还有一个显而易见的问题,那就是物体本身是立体的,不在一个平面,因此,这个计算前后的点的距离是包括物体本身厚度的,这个厚度就会表现在阴影上。

转注:使用可以解决这个问题,但是原作中并没有涉及,所以暂时略过。

算了,以下为原创:

su如何导出平面阴影__ps平面树的阴影

这里写图片描述

如上图所示,Cube和貌似没有什么问题,但是右边那个绳结形状的物体的阴影就出现了问题。解决方法,在第二个pass里之前,加入以下代码:

        Stencil{Ref 1           //参考值为1,stencilBuffer值默认为0  Comp Greater    //stencil比较方式是大于Pass replace    //通过的处理是替换,就是拿1替换buffer 的值  Fail Keep       //深度检测和模板检测双失败的处理是保持ZFail keep      //深度检测失败的处理是保持}

结果:

这里写图片描述

效果略好,但是也并不太理想,那是因为原作并不是把绳结物体当成一整个物体对待,而是当做一个一个的顶点处理,用原顶点和对应的影子顶点计算距离明显有问题。另外有一种做法是传入对象的世界坐标,然后跟世界空间的影子顶点计算距离,但其实也略复杂了,最简单的就是把o.atten=(,vt)/;这一段替换成:

o.atten=length(vt)/_Intensity;

其实就是计算影子顶点和物体的原点的距离。

效果如图:

这里写图片描述

这就需要在制作模型的时候把物体的原点设在y=0的平面上,这样这种影子才能达到较好的效果。

最后……需要提一句,原作中将物体和影子在一个里渲染,我认为这是有问题的,因为没法分别设置Queue,物体的Queue应该是,而影子的Queue应该是。所以正确的做法应该是,物体该怎么渲染就怎么渲染,影子做一个挂在物体上,添加和使用相同的Mesh,然后里使用阴影的材质。即上文中的去掉第一个Pass,并修改Tags。Blend方法建议修改为Blend ,最后frag方法建议修改为:

        float4 frag(v2f i) : COLOR {return float4(0,0,0, smoothstep(1, 0, i.atten / 2));}

综上所述,整合一下代码:

Shader "Tut/Shadow/PlanarShadow_Chaos" {Properties{_Intensity("atten",range(1,16))=1}SubShader {Tags{ "LightMode" = "ForwardBase""Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }pass {Cull FrontBlend SrcAlpha OneMinusSrcAlphaOffset -1,-1Stencil{Ref 1           //参考值为1,stencilBuffer值默认为0  Comp Greater    //stencil比较方式是大于Pass replace    //通过的处理是替换,就是拿1替换buffer 的值  Fail Keep       //深度检测和模板检测双失败的处理是保持ZFail keep      //深度检测失败的处理是保持}CGPROGRAM#pragma vertex vert #pragma fragment frag#include "UnityCG.cginc"float4x4 _World2Ground;float4x4 _Ground2World;float _Intensity;struct v2f{float4 pos:SV_POSITION;float atten:TEXCOORD0;};v2f vert(float4 vertex: POSITION){v2f o;float3 litDir;litDir=normalize(WorldSpaceLightDir(vertex));  litDir=mul(_World2Ground,float4(litDir,0)).xyz;float4 vt;vt= mul(unity_ObjectToWorld, vertex);vt=mul(_World2Ground,vt);vt.xz=vt.xz-(vt.y/litDir.y)*litDir.xz;vt.y=0;vt=mul(_Ground2World,vt);//back to worldvt=mul(unity_WorldToObject,vt);o.pos=UnityObjectToClipPos(vt);o.atten=length(vt)/_Intensity;return o;}float4 frag(v2f i) : COLOR {return float4(0,0,0, smoothstep(1, 0, i.atten / 2));}ENDCG }//}
}

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了