故事的起因是由于一个柱形环绕的特效Shader。
直接上代码和效果:
v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.vertex; return o; } fixed4 frag (v2f i) : SV_Target { float2 atuv = float2((-atan2(i.uv.x,i.uv.z) * 0.5 + 0.5) / UNITY_PI, i.uv.y) * _MainTex_ST.xy + _MainTex_ST.zw; fixed4 col = tex2D(_MainTex, atuv); return col; }
贴图会以环绕Y轴的方式显示在物体表面。
但是当把贴图替换为循环特效的时候,在环绕UV的起始点会产生一个像素接缝。
经过测试,当取消图片的mipmap设置后,该接缝会消失,所以推断这个接缝应该跟mipmap采样有关。
观察代码,当环绕物体Y轴进行贴图采样时,接缝的左侧和右侧分别为0和1,所以接缝处的UV偏导数会出现错误。
这一点我们可以通过一段简单的代码进行验证。
当时我们使用跨图片象限的大UV或者材质的Tiling参数进行贴图循环采样时,因为屏幕像素之间的UV是连续的,所以不会出现任何偏导数错误的问题。
但是下面我们换一种方式,使用fmod手动处理采样循环。
finalColor = tex2D(MainTexture, fmod(i.uv.xy , 1));
那么我们将会在原点象限以外的区域看到很多mipmap偏导数错误导致的接缝像素。
所以要想保证我们的循环结果正确,必须手动计算UV偏导数,以确保采样到正确的mipmap级别。
解决方案如下(仅修改frag片元的采样部分):
fixed4 frag (v2f i) : SV_Target { float2 atuv = float2((-atan2(i.uv.x,i.uv.z) * 0.5 + 0.5) / UNITY_PI, i.uv.y) * _MainTex_ST.xy + _MainTex_ST.zw; fixed4 col = tex2D(_MainTex, atuv, frac(ddx(atuv) + 0.5) - 0.5, frac(ddy(atuv) + 0.5) - 0.5); return col; }
然后最终采样的接缝已经可以被完美去除啦~~