当游戏中地面的纹理都是重复的时候,会看起来很假,而且影响沉浸感。
很明显地可以看出来有固定的pattern。这主要是因为每个0~1的tile内的纹理都是完全一样的,iq提出了两种方法来改良,使得看起来不会这么有重复感。当然,这两种技术都会成倍增大采样的次数,同时也有一些额外的计算,但效果还是不错的,在能够承受这种cost的时候还是很值得一用的。
对每个tile使用的纹理进行随机的翻转和平移
- 消除每个tile的重复感。这是通过判断当前所处的tile(这可以利用floor(uv)轻松得到),然后给每个tile一个四维的伪随机数,xy表示该tile的翻转方向(即水平和竖直方向上是否要进行mirror),zw表示该tile的平移方向,至此就可以保证每个tile都是不同的了。
上一步的结果有两个问题,首先是在tile和tile相交处有明显的接缝问题。这个可以通过算该tile旁边的三个tiles的采样结果,然后靠uv的小数部分判断距离接缝处的距离,并据此来混合四个采样结果,模糊接缝处使得结果看起来比较自然。何时开始混合边界可以当成一个参数来调节。
即便模糊了接缝处,还是会有一些残留的接缝。这些接缝产生的原因是因为我们这种方法会使得uv在tile的边界处产生很大的跳跃,导致mipmaping的时候也会出现跳跃。解决方法就是传递正确的ddx和ddy给tex2D函数,避免uv跳跃即可。
fixed4 texNoTileTech1(sampler2D tex, float2 uv) {float2 iuv = floor(uv)float2 fuv = frac(uv)// Generate per-tile transformation
#if defined (USE_HASH)float4 ofa = hash4(iuv + float2(
0,
0))float4 ofb = hash4(iuv + float2(
1,
0))float4 ofc = hash4(iuv + float2(
0,
1))float4 ofd = hash4(iuv + float2(
1,
1))
#elsefloat4 ofa = tex2D(_NoiseTex, (iuv + float2(
0.5,
0.5))/
256.0)float4 ofb = tex2D(_NoiseTex, (iuv + float2(
1.5,
0.5))/
256.0)float4 ofc = tex2D(_NoiseTex, (iuv + float2(
0.5,
1.5))/
256.0)float4 ofd = tex2D(_NoiseTex, (iuv + float2(
1.5,
1.5))/
256.0)
#endif// Compute the correct derivativesfloat2 dx = ddx(uv)float2 dy = ddy(uv)// Mirror per-tile uvsofa
.zw = sign(ofa
.zw -
0.5)ofb
.zw = sign(ofb
.zw -
0.5)ofc
.zw = sign(ofc
.zw -
0.5)ofd
.zw = sign(ofd
.zw -
0.5)float2 uva = uv * ofa
.zw + ofa
.xy, dxa = dx * ofa
.zw, dya = dy * ofa
.zwfloat2 uvb = uv * ofb
.zw + ofb
.xy, dxb = dx * ofb
.zw, dyb = dy * ofb
.zwfloat2 uvc = uv * ofc
.zw + ofc
.xy, dxc = dx * ofc
.zw, dyc = dy * ofc
.zwfloat2 uvd = uv * ofd
.zw + ofd
.xy, dxd = dx * ofd
.zw, dyd = dy * ofd
.zw// Fetch
and blendfloat2 b = smoothstep(_BlendRatio,
1.0 - _BlendRatio, fuv)return lerp( lerp(tex2D(tex, uva, dxa, dya), tex2D(tex, uvb, dxb, dyb), b
.x),lerp(tex2D(tex, uvc, dxc, dyc), tex2D(tex, uvd, dxd, dyd), b
.x), b
.y)
}
Voronoi分布来划分和混合空间
这种划分的好处是混合是发生在Voronoi图上的,而不是整整齐齐的方格上,看起来可能更加自然。
- 空间划分。整个空间还是会有若干的tile,但是会在每个tile内随机生成一个Voronoi点,每个点对应了一个纹理样式(靠随机平移来区分)。
- 混合。计算每个像素所在的周围9个Voronoi点,采样得到它们的纹理颜色,混合的时候依靠该像素到每个Voronoi点的距离的高斯衰减值作为混合权重,也就是说,距离Voronoi点越近权重越高。与方法一不同,这种方法其实随时随地都在混合(方法一的混合只发生在边界处),因此采用高斯衰减的好处就在于越靠近高斯衰减权重会迅速升高,使得混合不会造成整体非常模糊。最后,还需要对总体混合权重进行一次归一化,防止颜色失真。
shader代码——
fixed4 texNoTileTech2(
sampler2D tex, float2 uv) {float2 iuv =
floor(uv);float2 fuv = frac(uv);float2 dx = ddx(uv);float2 dy = ddy(uv);float4 va =
0.0;
float wt =
0.0;
float blur = -(_BlendRatio +
0.5) *
30.0;
for (
int j = -
1; j <=
1; j++) {
for (
int i = -
1; i <=
1; i++) {float2 g = float2((
float)i, (
float)j);
#if defined (USE_HASH)float4 o = hash4(iuv + g);
#elsefloat4 o = tex2D(_NoiseTex, (iuv + g + float2(
0.5,
0.5))/
256.0);
#endiffloat2 r = g - fuv + o.xy;
float d =
dot(r, r);
float w =
exp(blur * d);float4 c = tex2D(tex, uv + o.zw, dx, dy);va += w * c;wt += w;}}
return va/wt;
}
总结
以上是生活随笔为你收集整理的#游戏unity-VR场景漫游#shader之消除纹理重复感的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。