回答編集履歴
1
フィルタ処理の影響を後段に及ぼさないための修正案を追記
answer
CHANGED
@@ -232,4 +232,150 @@
|
|
232
232
|
ご質問者さんのおっしゃる「反復回数の異なる複数のシェーダーを作る」という方式なら、小反復回数のときの無駄な「グラブ」→「描画」部分を丸ごと削除することができるため、より高速化できると思います。
|
233
233
|
|
234
234
|
やはり、補助的なC#スクリプト抜きだとちょっと非効率的になってしまいますね。特に多数の曇りガラスオブジェクトがある場合は、オブジェクトの数だけグラブパスが増えますので負荷が気になりそうです。
|
235
|
-
ただ、この形ですと「曇りガラスオブジェクトの手前に別の曇りガラスオブジェクトがある場合、手前のオブジェクトを透かして見た背後の曇りガラスオブジェクトはさらにぼやけて見える」という視覚的もっともらしさがあると思います。
|
235
|
+
ただ、この形ですと「曇りガラスオブジェクトの手前に別の曇りガラスオブジェクトがある場合、手前のオブジェクトを透かして見た背後の曇りガラスオブジェクトはさらにぼやけて見える」という視覚的もっともらしさがあると思います。
|
236
|
+
|
237
|
+
### 追記
|
238
|
+
|
239
|
+
1回目の平均化処理を行う部分までを下記のように変更してみました。
|
240
|
+
|
241
|
+
RepeatAve.shader
|
242
|
+
```ShaderLab
|
243
|
+
Shader "Custom/RepeatAve"
|
244
|
+
{
|
245
|
+
Properties
|
246
|
+
{
|
247
|
+
_Color ("Color", Color) = (1, 1, 1, 1)
|
248
|
+
_MainTex ("Diffuse", 2D) = "white" {}
|
249
|
+
_Noise ("Noise", 2D) = "gray" {}
|
250
|
+
_Range ("Range", Float) = 0.025
|
251
|
+
_Blur ("Blur", Float) = 0.005
|
252
|
+
[KeywordEnum(R0,R1,R2,R3,R4,R5,R6,R7,R8)] _Repeat ("Repeat", Float) = 0
|
253
|
+
_Size ("Size", int) = 3
|
254
|
+
}
|
255
|
+
|
256
|
+
SubShader
|
257
|
+
{
|
258
|
+
Tags { "Queue" = "Transparent" }
|
259
|
+
Cull Off
|
260
|
+
ZWrite Off
|
261
|
+
Stencil
|
262
|
+
{
|
263
|
+
Ref 0
|
264
|
+
Comp Equal
|
265
|
+
}
|
266
|
+
|
267
|
+
CGINCLUDE
|
268
|
+
#pragma target 3.0
|
269
|
+
#include "UnityCG.cginc"
|
270
|
+
ENDCG
|
271
|
+
|
272
|
+
GrabPass{"_FirstGrabTexture"}
|
273
|
+
pass
|
274
|
+
{
|
275
|
+
CGPROGRAM
|
276
|
+
#pragma multi_compile _ _REPEAT_R1 _REPEAT_R2 _REPEAT_R3 _REPEAT_R4 _REPEAT_R5 _REPEAT_R6 _REPEAT_R7 _REPEAT_R8
|
277
|
+
#pragma vertex vertAve
|
278
|
+
#pragma fragment fragAveFirst
|
279
|
+
#if _REPEAT_R1 | _REPEAT_R2 | _REPEAT_R3 | _REPEAT_R4 | _REPEAT_R5 | _REPEAT_R6 | _REPEAT_R7 | _REPEAT_R8
|
280
|
+
#define _AVE
|
281
|
+
#endif
|
282
|
+
#include "RepeatAve.cginc"
|
283
|
+
sampler2D _FirstGrabTexture;
|
284
|
+
half4 fragAveFirst(v2fAve i): SV_Target
|
285
|
+
{
|
286
|
+
float2 uv = i.screenPos.xy / i.screenPos.w;
|
287
|
+
half4 frost = 0.0;
|
288
|
+
#ifdef _AVE
|
289
|
+
for (int m = - (_Size - 1) / 2; m <= (_Size - 1) / 2; m ++)
|
290
|
+
{
|
291
|
+
for (int n = - (_Size - 1) / 2; n <= (_Size - 1) / 2; n ++)
|
292
|
+
{
|
293
|
+
frost += tex2D(_FirstGrabTexture, uv + float2(_Blur * m, _Blur * n));
|
294
|
+
}
|
295
|
+
}
|
296
|
+
frost /= _Size * _Size;
|
297
|
+
#else
|
298
|
+
frost = tex2D(_FirstGrabTexture, uv);
|
299
|
+
#endif
|
300
|
+
return half4(frost.xyz, 1);
|
301
|
+
}
|
302
|
+
ENDCG
|
303
|
+
}
|
304
|
+
|
305
|
+
// 省略...残り7回のフィルタ処理および最終合成処理には変更なし
|
306
|
+
}
|
307
|
+
Fallback Off
|
308
|
+
}
|
309
|
+
```
|
310
|
+
|
311
|
+
RepeatAve.cgincに変更はありません。
|
312
|
+
1回目のGrabPassのみグラブ先を`_FirstGrabTexture`として平均化もそのテクスチャを参照するようにし、2回目以降は先と同様にテクスチャ名指定なしでグラブ・平均化しています。
|
313
|
+
テクスチャ名指定ありでグラブすると最初の1回だけグラブが行われるので、フィルタ処理の起点は毎回最初のグラブ結果となります。このため、後で描画されるマテリアルにそれまでのフィルタ処理の影響が及ばなくなり、「曇りガラスを重ねるほどぼけ幅が大きくなる」という現象を回避できるかと思います。
|
314
|
+
また、ついでにコメントで申し上げた`ZWrite Off`を加え、さらにステンシルテストを有効にしてステンシルバッファの内容が0の場合だけ描画を行うようにしました。
|
315
|
+
|
316
|
+
これと併せて、ステンシル値を加算してステンシルバッファの内容を0でなくするマテリアルをマスク用オブジェクトに使用すれば、キューの大小に基づいたマスキングが可能かと思います。
|
317
|
+
|
318
|
+
StencilMask.shader
|
319
|
+
```ShaderLab
|
320
|
+
Shader "Custom/StencilMask"
|
321
|
+
{
|
322
|
+
Properties
|
323
|
+
{
|
324
|
+
}
|
325
|
+
|
326
|
+
SubShader
|
327
|
+
{
|
328
|
+
Tags { "Queue" = "Transparent" }
|
329
|
+
Cull Off
|
330
|
+
ZWrite Off
|
331
|
+
Stencil
|
332
|
+
{
|
333
|
+
Pass IncrSat
|
334
|
+
}
|
335
|
+
ColorMask 0
|
336
|
+
|
337
|
+
Pass
|
338
|
+
{
|
339
|
+
CGPROGRAM
|
340
|
+
#pragma target 3.0
|
341
|
+
#pragma vertex vert
|
342
|
+
#pragma fragment frag
|
343
|
+
#include "UnityCG.cginc"
|
344
|
+
struct v2f
|
345
|
+
{
|
346
|
+
float4 pos: SV_POSITION;
|
347
|
+
};
|
348
|
+
v2f vert(appdata_full v)
|
349
|
+
{
|
350
|
+
v2f o;
|
351
|
+
o.pos = UnityObjectToClipPos(v.vertex);
|
352
|
+
return o;
|
353
|
+
}
|
354
|
+
half4 frag(v2f i): SV_Target
|
355
|
+
{
|
356
|
+
return 0.0;
|
357
|
+
}
|
358
|
+
ENDCG
|
359
|
+
}
|
360
|
+
}
|
361
|
+
Fallback Off
|
362
|
+
}
|
363
|
+
```
|
364
|
+
|
365
|
+
テストとして、下記3種のマテリアルを作成し...
|
366
|
+
|
367
|
+
- マテリアルA...赤ガラス、ぼけ幅中、ノイズ効果小、キュー2501
|
368
|
+
- マテリアルB...緑ガラス、ぼけ幅大、ノイズ効果大、キュー2511
|
369
|
+
- マテリアルC...青ガラス、ぼけ幅小、ノイズ効果なし、キュー2521
|
370
|
+
|
371
|
+
これらを、`_FirstGrabTexture`を使わない従来通りの方法で描画すると、下図のように先に描画した曇りガラスの影響が後段にも引き継がれますが...
|
372
|
+
|
373
|
+

|
374
|
+
|
375
|
+
`_FirstGrabTexture`を使う方式にすると、下図のような結果となります。
|
376
|
+
|
377
|
+

|
378
|
+
|
379
|
+
また、キュー2510のマスクオブジェクト(Aの次に描画され、描画領域へのB・Cの描画を防止する)を左右に横切るよう配置、キュー2520のマスクオブジェクト(Bの次に描画され、描画領域へのCの描画を防止する)を上下に横切るよう配置して、描画過程を見てみると下図のようになります。
|
380
|
+
|
381
|
+

|