回答編集履歴

1

フィルタ処理の影響を後段に及ぼさないための修正案を追記

2018/10/18 21:58

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -467,3 +467,295 @@
467
467
  やはり、補助的なC#スクリプト抜きだとちょっと非効率的になってしまいますね。特に多数の曇りガラスオブジェクトがある場合は、オブジェクトの数だけグラブパスが増えますので負荷が気になりそうです。
468
468
 
469
469
  ただ、この形ですと「曇りガラスオブジェクトの手前に別の曇りガラスオブジェクトがある場合、手前のオブジェクトを透かして見た背後の曇りガラスオブジェクトはさらにぼやけて見える」という視覚的もっともらしさがあると思います。
470
+
471
+
472
+
473
+ ### 追記
474
+
475
+
476
+
477
+ 1回目の平均化処理を行う部分までを下記のように変更してみました。
478
+
479
+
480
+
481
+ RepeatAve.shader
482
+
483
+ ```ShaderLab
484
+
485
+ Shader "Custom/RepeatAve"
486
+
487
+ {
488
+
489
+ Properties
490
+
491
+ {
492
+
493
+ _Color ("Color", Color) = (1, 1, 1, 1)
494
+
495
+ _MainTex ("Diffuse", 2D) = "white" {}
496
+
497
+ _Noise ("Noise", 2D) = "gray" {}
498
+
499
+ _Range ("Range", Float) = 0.025
500
+
501
+ _Blur ("Blur", Float) = 0.005
502
+
503
+ [KeywordEnum(R0,R1,R2,R3,R4,R5,R6,R7,R8)] _Repeat ("Repeat", Float) = 0
504
+
505
+ _Size ("Size", int) = 3
506
+
507
+ }
508
+
509
+
510
+
511
+ SubShader
512
+
513
+ {
514
+
515
+ Tags { "Queue" = "Transparent" }
516
+
517
+ Cull Off
518
+
519
+ ZWrite Off
520
+
521
+ Stencil
522
+
523
+ {
524
+
525
+ Ref 0
526
+
527
+ Comp Equal
528
+
529
+ }
530
+
531
+
532
+
533
+ CGINCLUDE
534
+
535
+ #pragma target 3.0
536
+
537
+ #include "UnityCG.cginc"
538
+
539
+ ENDCG
540
+
541
+
542
+
543
+ GrabPass{"_FirstGrabTexture"}
544
+
545
+ pass
546
+
547
+ {
548
+
549
+ CGPROGRAM
550
+
551
+ #pragma multi_compile _ _REPEAT_R1 _REPEAT_R2 _REPEAT_R3 _REPEAT_R4 _REPEAT_R5 _REPEAT_R6 _REPEAT_R7 _REPEAT_R8
552
+
553
+ #pragma vertex vertAve
554
+
555
+ #pragma fragment fragAveFirst
556
+
557
+ #if _REPEAT_R1 | _REPEAT_R2 | _REPEAT_R3 | _REPEAT_R4 | _REPEAT_R5 | _REPEAT_R6 | _REPEAT_R7 | _REPEAT_R8
558
+
559
+ #define _AVE
560
+
561
+ #endif
562
+
563
+ #include "RepeatAve.cginc"
564
+
565
+ sampler2D _FirstGrabTexture;
566
+
567
+ half4 fragAveFirst(v2fAve i): SV_Target
568
+
569
+ {
570
+
571
+ float2 uv = i.screenPos.xy / i.screenPos.w;
572
+
573
+ half4 frost = 0.0;
574
+
575
+ #ifdef _AVE
576
+
577
+ for (int m = - (_Size - 1) / 2; m <= (_Size - 1) / 2; m ++)
578
+
579
+ {
580
+
581
+ for (int n = - (_Size - 1) / 2; n <= (_Size - 1) / 2; n ++)
582
+
583
+ {
584
+
585
+ frost += tex2D(_FirstGrabTexture, uv + float2(_Blur * m, _Blur * n));
586
+
587
+ }
588
+
589
+ }
590
+
591
+ frost /= _Size * _Size;
592
+
593
+ #else
594
+
595
+ frost = tex2D(_FirstGrabTexture, uv);
596
+
597
+ #endif
598
+
599
+ return half4(frost.xyz, 1);
600
+
601
+ }
602
+
603
+ ENDCG
604
+
605
+ }
606
+
607
+
608
+
609
+ // 省略...残り7回のフィルタ処理および最終合成処理には変更なし
610
+
611
+ }
612
+
613
+ Fallback Off
614
+
615
+ }
616
+
617
+ ```
618
+
619
+
620
+
621
+ RepeatAve.cgincに変更はありません。
622
+
623
+ 1回目のGrabPassのみグラブ先を`_FirstGrabTexture`として平均化もそのテクスチャを参照するようにし、2回目以降は先と同様にテクスチャ名指定なしでグラブ・平均化しています。
624
+
625
+ テクスチャ名指定ありでグラブすると最初の1回だけグラブが行われるので、フィルタ処理の起点は毎回最初のグラブ結果となります。このため、後で描画されるマテリアルにそれまでのフィルタ処理の影響が及ばなくなり、「曇りガラスを重ねるほどぼけ幅が大きくなる」という現象を回避できるかと思います。
626
+
627
+ また、ついでにコメントで申し上げた`ZWrite Off`を加え、さらにステンシルテストを有効にしてステンシルバッファの内容が0の場合だけ描画を行うようにしました。
628
+
629
+
630
+
631
+ これと併せて、ステンシル値を加算してステンシルバッファの内容を0でなくするマテリアルをマスク用オブジェクトに使用すれば、キューの大小に基づいたマスキングが可能かと思います。
632
+
633
+
634
+
635
+ StencilMask.shader
636
+
637
+ ```ShaderLab
638
+
639
+ Shader "Custom/StencilMask"
640
+
641
+ {
642
+
643
+ Properties
644
+
645
+ {
646
+
647
+ }
648
+
649
+
650
+
651
+ SubShader
652
+
653
+ {
654
+
655
+ Tags { "Queue" = "Transparent" }
656
+
657
+ Cull Off
658
+
659
+ ZWrite Off
660
+
661
+ Stencil
662
+
663
+ {
664
+
665
+ Pass IncrSat
666
+
667
+ }
668
+
669
+ ColorMask 0
670
+
671
+
672
+
673
+ Pass
674
+
675
+ {
676
+
677
+ CGPROGRAM
678
+
679
+ #pragma target 3.0
680
+
681
+ #pragma vertex vert
682
+
683
+ #pragma fragment frag
684
+
685
+ #include "UnityCG.cginc"
686
+
687
+ struct v2f
688
+
689
+ {
690
+
691
+ float4 pos: SV_POSITION;
692
+
693
+ };
694
+
695
+ v2f vert(appdata_full v)
696
+
697
+ {
698
+
699
+ v2f o;
700
+
701
+ o.pos = UnityObjectToClipPos(v.vertex);
702
+
703
+ return o;
704
+
705
+ }
706
+
707
+ half4 frag(v2f i): SV_Target
708
+
709
+ {
710
+
711
+ return 0.0;
712
+
713
+ }
714
+
715
+ ENDCG
716
+
717
+ }
718
+
719
+ }
720
+
721
+ Fallback Off
722
+
723
+ }
724
+
725
+ ```
726
+
727
+
728
+
729
+ テストとして、下記3種のマテリアルを作成し...
730
+
731
+
732
+
733
+ - マテリアルA...赤ガラス、ぼけ幅中、ノイズ効果小、キュー2501
734
+
735
+ - マテリアルB...緑ガラス、ぼけ幅大、ノイズ効果大、キュー2511
736
+
737
+ - マテリアルC...青ガラス、ぼけ幅小、ノイズ効果なし、キュー2521
738
+
739
+
740
+
741
+ これらを、`_FirstGrabTexture`を使わない従来通りの方法で描画すると、下図のように先に描画した曇りガラスの影響が後段にも引き継がれますが...
742
+
743
+
744
+
745
+ ![旧描画方式](3a3fdc17044bfa8212aa736b9917d2c0.png)
746
+
747
+
748
+
749
+ `_FirstGrabTexture`を使う方式にすると、下図のような結果となります。
750
+
751
+
752
+
753
+ ![新描画方式](d5703f03f7bdf8c645bdd30f6cccebbd.png)
754
+
755
+
756
+
757
+ また、キュー2510のマスクオブジェクト(Aの次に描画され、描画領域へのB・Cの描画を防止する)を左右に横切るよう配置、キュー2520のマスクオブジェクト(Bの次に描画され、描画領域へのCの描画を防止する)を上下に横切るよう配置して、描画過程を見てみると下図のようになります。
758
+
759
+
760
+
761
+ ![マスク処理](9c00cd6241cbe946d4b3c3c69a5e820e.gif)