这个demo放出来之后,对其中的角色阴影部分的技术十分感兴趣,我就赶紧下过来研究了一下。官方的技术博客里有对这一部分技术的介绍,链接在这里:独特的角色阴影,
其中写到只要在其他shader里添加
#PRagma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE#include "UniqueShadow_ShadowSample.cginc"这两行代码就能使用这个高级阴影了。 我之前也因为在做一些demo的时候发现unity默认阴影达不到理想效果,和ue4比起来还是有一定差距的。于是就想到使用这个阴影技术了。于是我兴致勃勃的把这两行代码和几个库文件加到我的shader和项目里去,一运行发现,高级阴影并没有出现。哎,看样子只能自己研究了。既然是阴影,那么着手点就是unity里的阴影部分的代码,手动写过自定义阴影的人应该都知道,unity阴影计算:SHADOW_COORDS、TRANSFER_SHADOW、SHADOW_ATTENUATION三个函数了,unity把阴影生成的代码都写在了这三个函数里,方便调用。我看The Blacksmith的技术博客上写着: 我们发现原来有一个非常简单的方法来对常见的Unity shader所用的阴影方法进行重写。 于是我琢磨着应该是他们也用了这三个方法,于是打开 UniqueShadow_ShadowSample.cginc 文件,果不其然,在最下面找到了这么一段代码
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_FORWARDADD) || defined(UNIQUE_SHADOW_FORCE_REPLACE_BUILTIN) #undef SHADOW_COORDS #undef TRANSFER_SHADOW #undef SHADOW_ATTENUATION #define SHADOW_COORDS(i) UNIQUE_SHADOW_INTERP(i) #define TRANSFER_SHADOW o.uniqueShadowPos = mul(u_UniqueShadowMatrix, float4(worldPos.xyz, 1.f)); #define SHADOW_ATTENUATION(i) UNIQUE_SHADOW_SAMPLE(i);#endif这里的意思就是,如果判断pass的名字是UNITY_PASS_FORWARDBASE、NITY_PASS_FORWARDADD、UNIQUE_SHADOW_FORCE_REPLACE_BUILTIN这三个的话,就会把
SHADOW_COORDS(i) 替换成UNIQUE_SHADOW_INTERP(i),SHADOW_ATTENUATION(i)替换成UNIQUE_SHADOW_SAMPLE(i);TRANSFER_SHADOW的值替换成后面的 o.uniqueShadowPos这样的话就好说了,之后只要把自己的shader里生成阴影的pass名字改成三个里的任意一个,生成阴影的代码还是按照原来的方式写就可以了。于是我立马新建了一个Unlit Shader,添加上生成阴影的代码后,把pass的名字改成了UNITY_PASS_FORWARDBASE,代码如下
Shader "Custom/simpleSuperShadow"{ Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { Tags{ "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" #include "AutoLight.cginc"#define UNITY_PASS_FORWARDBASE#pragma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE#include "UniqueShadow/UniqueShadow_ShadowSample.cginc" struct v2f { float2 uv : TEXCOORD0; float4 pos : SV_POSITION; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2) }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata_full v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.worldPos = mul(_Object2World, v.vertex).xyz; TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); fixed shadow = SHADOW_ATTENUATION(i); return col * shadow; } ENDCG } } FallBack "Diffuse"}点击运行之后,shader报错,提示我顶点函数里worldPos未定义,报错的地方是在TRANSFER_SHADOW(o)这一行,但是我明明在v2f里定义了这个变量,并且在上一行赋值了才对。这个提示不应该出现才对。对于这个问题,我毫无头绪,不知道自己哪里出了问题。于是我又新建了一个standard surface shader,这次我只在里面添加了#pragma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE#include "UniqueShadow/UniqueShadow_ShadowSample.cginc"两行,运行一下,居然成功了,于是我在编辑器里点开了surface shader的原始代码,通过仔细对比阴影生成的三个函数发现,surface shader在顶点函数使用worldPos的时候,并不是直接给o.worldPos赋值的,而是先定义了一个float3的worldPos变量,计算出来以后再让o.worldPos = worldPos,这里感觉应该是一样的才是,并没有什么特别的地方啊。虽然我不是很清楚surface shader里为啥要这么写,但是抱着试一试的心情,我把自己的shader的顶点函数从原来的v2f vert (appdata_full v){ v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.worldPos = mul(_Object2World, v.vertex).xyz; TRANSFER_SHADOW(o); return o;}这样,改成了v2f vert (appdata_full v){ v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); float3 worldPos = mul(_Object2World, v.vertex).xyz; o.worldPos = worldPos; TRANSFER_SHADOW(o); return o;}这样,于是我运行一下。卧槽竟然成功了。按道理来说定义一个临时变量和直接赋值应该没有区别才是,为啥这里不定义一个就不行呢,mul(_Object2Wrold,v.vertex).xyz返回的本来就是一个float3的变量才是,为毛非要这么做才能正确显示呢。实在是不知道要怎么解释。希望知道的大大们能够帮我解释一下。总结一下这个高级阴影的使用方法1.给计算阴影的pass添加#define UNITY_PASS_FORWARDBASE#pragma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE#include "UniqueShadow/UniqueShadow_ShadowSample.cginc"
这三行代码,然后在顶点函数使用TRANSFES_SHADOW的地方改成float3 worldPos = mul(_Object2World, v.vertex).xyz;o.worldPos = worldPos;TRANSFER_SHADOW(o);这样自定义的shader也能够使用这个超高分辨率的阴影了。
这里我用了一个卡通shader做测试未使用高级阴影:使用高级阴影:这样就能做出媲美ue4的高级阴影来了。
新闻热点
疑难解答