回答編集履歴

1

Unlit/Worldの場合の対策を追記

2019/12/07 04:18

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -181,3 +181,167 @@
181
181
 
182
182
 
183
183
  ![図2](a5e452a0849a2c4e81cd2570791d3bd8.gif)
184
+
185
+
186
+
187
+ **追記**
188
+
189
+ `Unlit/World`の場合は何を手がかりにサンプリング座標の変化率を算出するべきかですが、シェーダーコード以外のスクリプトが「[Unity2D テクスチャブレンド](https://teratail.com/questions/184671)」のものとほとんど変わらないと仮定しますと、好都合なことにシェーダーコード内の`modelPos`が利用できそうです。
190
+
191
+ これはメッシュが持っている頂点座標ですが、メッシュは縦横1.0の正方形が並んだ形に作られていて、この正方形内ぴったりにタイルの画像を貼り付ける形になっています。ですので`modelPos`の変化率をもとにサンプリング位置の変化率を算出できるはずです。
192
+
193
+
194
+
195
+ ですが`Unlit/World`のケースだともっと影響の大きい要因として、元のテクスチャがそれぞれの地形を並べて一枚にしている都合上隣のタイルの色が漏れて格子模様(元のテクスチャは地形を横に並べているため色漏れは横方向にだけ発生するので、「縦縞模様」と言った方が適切かもしれません)が生じてしまう現象があるかと思います。
196
+
197
+ ですので[Unity2D テクスチャが潰れる](https://teratail.com/questions/198656)のシェーダーコードと同様に、タイルの外周部分をサンプリング座標の飛び幅分だけそぎ落とす処置も組み合わせてみました。変更部分は`frag`の後半だけです。
198
+
199
+
200
+
201
+ ```ShaderLab
202
+
203
+ fixed4 frag(v2f i) : SV_Target
204
+
205
+ {
206
+
207
+ // まずは前回同様weightを計算する
208
+
209
+ float f = dot(float2(_EdgeDist, 1.0 - _EdgeDist), float2(fractal(i.modelPos * _EdgeDistFreq), 0.5));
210
+
211
+ float upper = 1.0 - 2.0 * (1.0 - i.weight) * (1.0 - f);
212
+
213
+ float lower = 2.0 * i.weight * f;
214
+
215
+ float weight = lerp(lower, upper, step(0.5, i.weight));
216
+
217
+
218
+
219
+ // weightを比較してどの範囲にいるか判定し、それを越えない最大のインデックスを調べる
220
+
221
+ uint index = 0;
222
+
223
+ [unroll(TYPE_COUNT_MAX)]
224
+
225
+ for (int k = 0; k < _TypeCount; k++)
226
+
227
+ {
228
+
229
+ if (_TypeLevels[k] < weight)
230
+
231
+ {
232
+
233
+ index = k + 1;
234
+
235
+ continue;
236
+
237
+ }
238
+
239
+ break;
240
+
241
+ }
242
+
243
+ index = min(index, _TypeCount - 1);
244
+
245
+
246
+
247
+ // さらに、その一つ下・一つ上のインデックスを求めておく
248
+
249
+ uint prevIndex = index > 0 ? index - 1 : 0;
250
+
251
+ uint nextIndex = min(index + 1, _TypeCount - 1);
252
+
253
+
254
+
255
+ // 範囲の下限・上限の高さを取得し、lowerLevelを0、upperLevelを1としたときのweightの位置を調べる
256
+
257
+ float lowerLevel = (index == prevIndex) ? 0.0 : _TypeLevels[prevIndex];
258
+
259
+ float upperLevel = (index == nextIndex) ? 1.0 : _TypeLevels[index];
260
+
261
+ float weightInRange = (lowerLevel == upperLevel) ? 0.0 : (weight - lowerLevel) / (upperLevel - lowerLevel);
262
+
263
+
264
+
265
+ // weightInRangeが0.5以上かどうかでnextIndex、prevIndexのいずれかを選択する
266
+
267
+ uint edgeIndex = weightInRange >= 0.5 ? nextIndex : prevIndex;
268
+
269
+
270
+
271
+ // weightInRangeが0.5の時0、そこより範囲境界に近いほど1になるような値を作る
272
+
273
+ // このとき_EdgeSharpness乗して、カーブを適宜鋭くする
274
+
275
+ float edgeFactor = saturate(pow(abs(weightInRange * 2.0 - 1.0), _EdgeSharpness));
276
+
277
+
278
+
279
+ // 範囲中心および範囲境界に対応するUVを取得し、そこからそれぞれ色を取得する
280
+
281
+ float4 edgeVector = _TypeUvs[edgeIndex / 2];
282
+
283
+ float4 centerVector = _TypeUvs[index / 2];
284
+
285
+ float2 edgeUv = lerp(edgeVector.xy, edgeVector.zw, edgeIndex % 2);
286
+
287
+ float2 centerUv = lerp(centerVector.xy, centerVector.zw, index % 2);
288
+
289
+
290
+
291
+ // 色取得の前に、modelPos変化率とUV変化率を算出する
292
+
293
+ float2 dPosdx = ddx(i.modelPos);
294
+
295
+ float2 dPosdy = ddy(i.modelPos);
296
+
297
+ float2 dUvdx = dPosdx * _TileSize;
298
+
299
+ float2 dUvdy = dPosdy * _TileSize;
300
+
301
+
302
+
303
+ // 色漏れ防止のため、modelPos変化率の分だけtileUvの外周を
304
+
305
+ // そぎ落としてから_TileSizeをかけてuvOffsetとする
306
+
307
+ float2 cornerOffset = abs(dPosdx) + abs(dPosdy);
308
+
309
+ float2 uvOffset = lerp(cornerOffset, 1.0 - cornerOffset, i.tileUv) * _TileSize;
310
+
311
+
312
+
313
+ // tex2Dの代わりにtex2Dgradを使って色を取得する
314
+
315
+ // このとき、第3・第4引数としてUV変化率を使用する
316
+
317
+ fixed4 edgeColor = tex2Dgrad(_MainTex, edgeUv + uvOffset, dUvdx, dUvdy);
318
+
319
+ fixed4 centerColor = tex2Dgrad(_MainTex, centerUv + uvOffset, dUvdx, dUvdy);
320
+
321
+
322
+
323
+ // 範囲中心でcenterColorが100%、境界部分でcenterColorとedgeColorが
324
+
325
+ // 50%混合になるように2つの色を混ぜ合わせる
326
+
327
+ return lerp(centerColor, edgeColor, edgeFactor * 0.5);
328
+
329
+ }
330
+
331
+ ```
332
+
333
+
334
+
335
+ テクスチャの設定はGenerate Mip MapsをオンにしてFilter ModeをTrilinearとした状態で、対策なしだと下図のように縦スジが目立ってしまいますが...
336
+
337
+
338
+
339
+ ![図3](b7526cd9714ed4461f7a7400ceff6bc3.gif)
340
+
341
+
342
+
343
+ 対策ありだと下図のようにマシになりました。
344
+
345
+
346
+
347
+ ![図4](2d74baa4d356bce533766d36c4508e26.gif)