2016-02-23 34 views
12

Próbuję napisać shader dla jedności, która będzie podkreślać nakładających się fragmentów oczek. Powinien działać dla jednego obiektu nakładającego się na siebie, jak również wielu obiektów.Unity Shader podświetlanie pokrywa

Wynik powinien wyglądać załączonym obrazku. enter image description here

Najpierw próbowałem to zrobić z wykrywaniem kolizji, ale myślę, że najlepszym sposobem jest napisanie modułu cieniującego.

nie jestem bardzo obeznany z shaderów więc jeśli ktoś może mi pomóc byłbym wdzięczny.

Myślę, że można to zrobić za pomocą szablonów cieniowania, takich jak tutaj http://docs.unity3d.com/Manual/SL-Stencil.html , ale te shadery renderują tylko przecięcie dwóch obiektów bez renderowania całego obiektu.

Znalazłem również shader oparte na głębokość (https://chrismflynn.wordpress.com/2012/09/06/fun-with-shaders-and-the-depth-buffer/), ale również działać na dwóch obiektach i nie działa na jednej siatki, które pokrywają się

Odnośnie komentarza @Zze z pojęcia o Dwuprzebiegowe Mam teraz dwa shaderów . I działa na dwóch obiektach, gdy jeden ma jeden moduł cieniujący, a drugi drugi.

Może ktoś może mi pomóc, jak połączyć je w jeden moduł cieniujący, który będzie działał także w obiekt, który będzie pokrywać się?

ShaderOne

Shader "Custom/ShaderOne" 
{ 
    SubShader { 
     Tags { "RenderType"="Opaque" "Queue"="Geometry"} 
     Pass { 
      Stencil { 
       Ref 2 
       Comp always 
       Pass keep 
       Fail decrWrap 
       ZFail keep 
      } 

      CGPROGRAM 
      #pragma vertex vert 
      #pragma fragment frag 
      struct appdata { 
       float4 vertex : POSITION; 
      }; 
      struct v2f { 
       float4 pos : SV_POSITION; 
      }; 
      v2f vert(appdata v) { 
       v2f o; 
       o.pos = mul(UNITY_MATRIX_MVP, v.vertex); 
       return o; 
      } 
      half4 frag(v2f i) : SV_Target { 
       return half4(0,1,0,1); 
      } 
      ENDCG 
     } 
     Pass { 
      Stencil { 
       Ref 2 
       Comp equal 
      } 

      CGPROGRAM 
      #pragma vertex vert 
      #pragma fragment frag 
      struct appdata { 
       float4 vertex : POSITION; 
      }; 
      struct v2f { 
       float4 pos : SV_POSITION; 
      }; 
      v2f vert(appdata v) { 
       v2f o; 
       o.pos = mul(UNITY_MATRIX_MVP, v.vertex); 
       return o; 
      } 
      half4 frag(v2f i) : SV_Target { 
       return half4(0,0,1,1); 
      } 
      ENDCG 
     } 

    } 
} 

ShaderTwo

Shader "Custom/ShaderTwo" 
{ 
    SubShader { 
     Tags { "RenderType"="Opaque" "Queue"="Geometry"} 
     Pass { 
      Stencil { 
       Ref 2 
       Comp always 
       Pass replace 
       ZFail keep 
      } 

      CGPROGRAM 
      #pragma vertex vert 
      #pragma fragment frag 
      struct appdata { 
       float4 vertex : POSITION; 
      }; 
      struct v2f { 
       float4 pos : SV_POSITION; 
      }; 
      v2f vert(appdata v) { 
       v2f o; 
       o.pos = mul(UNITY_MATRIX_MVP, v.vertex); 
       return o; 
      } 
      half4 frag(v2f i) : SV_Target { 
       return half4(1,0,0,1); 
      } 
      ENDCG 
     } 
    } 
} 

wynik wygląda na załączonym obrazem enter image description here

+0

Jeśli shader szablon renderuje punkty przecięcia, to dlaczego nie można zrobić shader z 2 przejazdów, pierwszy rysuje normalnie a potem drugi naśladuje wyniku cieniującego szablonu? – Zze

+0

Być może zechcesz spojrzeć na pojęcie głębokiego obierania. Zobacz [tutaj] (http: //www.opengl-tutorial.org/intermediate-tutorials/tutorial-10-transparency /) i [here] (http://www.eng.utah.edu/~cs5610/handouts/order_independent_transparency.pdf). Również ile obiektów planujesz mieć. Jeśli nie wiele, możesz chcieć renderować każdy obiekt do tekstury, a następnie łączyć je jak bufor akumulacyjny. – mrVoid

+0

@ mrVoid Myślę, że testowanie głębokości zadziała w tej sytuacji tylko z widokiem z góry aparatu - ale kiedy będzie to perspektywa, to nie zadziała? Mam z tego ból głowy. może możesz podać mi przykład użycia go z przykładowym kodem? – seek

Odpowiedz

2

Problem ten można rozwiązać przy pomocy buforu do wzornika i jeden, dwa przejścia module. Idea jest następująca:

  • Pierwsze przejście porównuje wartość w bufor szablonowy 0. W obu przypadkach (pass/fail) zwiększenie wartości w buforze.
  • Drugie przejście porównuje wartość w buforze szablonu z 1. Jeśli wartość odniesienia 1 jest mniejsza, niż przejeżdżamy i podświetlamy zachodzący piksel.

Możesz chcieć dodać więcej podań, które są takie same jak w drugim, ale z inną wartością odniesienia, aby wyróżnić regiony, które nakłada się dwa razy, trzy razy itd

W notacji shaderlab Jedności, to powinien coś takiego:

Pass 
    { 
     Stencil { 
      Ref 0 
      Comp Equal 
      Pass IncrSat 
      Fail IncrSat 
     } 

     // Shader for not overlapping regions goes here. 
    } 

    Pass 
    { 
     Stencil { 
      Ref 1 
      Comp Less 
     } 

     // Shader for one-time overlapping regions goes here. 
    } 

    Pass 
    { 
     Stencil { 
      Ref 2 
      Comp Less 
     } 

     // Shader for two-time overlapping regions goes here. 
    } 

przykład:

enter image description here

Shader:

Shader "Unlit/Stencil" 
{ 
    Properties 
    { 
     _MainTex ("Texture", 2D) = "white" {} 
    } 
    SubShader 
    { 
     Tags { "RenderType"="Opaque" } 
     LOD 100 

     Pass 
     { 
      Stencil { 
       Ref 0 
       Comp Equal 
       Pass IncrSat 
       Fail IncrSat 
      } 

      CGPROGRAM 
      #pragma vertex vert 
      #pragma fragment frag 

      #include "UnityCG.cginc" 

      struct appdata 
      { 
       float4 vertex : POSITION; 
      }; 

      struct v2f 
      { 
       float4 vertex : SV_POSITION; 
      }; 

      v2f vert (appdata v) 
      { 
       v2f o; 
       o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); 
       return o; 
      } 

      fixed4 frag (v2f i) : SV_Target 
      { 
       fixed4 col = fixed4(0.0, 0.0, 1.0, 1.0); 
       return col; 
      } 
      ENDCG 
     } 

     Pass 
     { 
      Stencil { 
       Ref 1 
       Comp Less 
      } 

      CGPROGRAM 
      #pragma vertex vert 
      #pragma fragment frag 

      #include "UnityCG.cginc" 

      struct appdata 
      { 
       float4 vertex : POSITION; 
      }; 

      struct v2f 
      { 
       float4 vertex : SV_POSITION; 
      }; 

      v2f vert (appdata v) 
      { 
       v2f o; 
       o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); 
       return o; 
      } 

      fixed4 frag (v2f i) : SV_Target 
      { 
       fixed4 col = fixed4(1.0, 1.0, 0.0, 1.0); 
       return col; 
      } 
      ENDCG 
     } 

     Pass 
     { 
      Stencil { 
       Ref 2 
       Comp Less 
      } 

      CGPROGRAM 
      #pragma vertex vert 
      #pragma fragment frag 

      #include "UnityCG.cginc" 

      struct appdata 
      { 
       float4 vertex : POSITION; 
      }; 

      struct v2f 
      { 
       float4 vertex : SV_POSITION; 
      }; 

      v2f vert (appdata v) 
      { 
       v2f o; 
       o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); 
       return o; 
      } 

      fixed4 frag (v2f i) : SV_Target 
      { 
       fixed4 col = fixed4(1.0, 0.0, 0.0, 1.0); 
       return col; 
      } 
      ENDCG 
     } 
    } 
} 
+0

Działa świetnie !. To dokładnie to, czego szukałem. Proszę powiedzieć, że ten moduł cieniujący jest wyświetlany na wierzchu pozostałych, czy można dodać do niego kolejkę? A druga rzecz jest również możliwa do renderowania dla dwustronnej? – seek

+2

> Powiedz mi, że ten moduł cieniujący jest wyświetlany na wierzchu innych, czy można dodać do tego Kolejka? Nie jestem pewien, czy poprawnie zrozumiałem pytanie. Możesz zamienić moduł cieniujący w każdym przebiegu na własny, aby uzyskać różne shadery dla nakładających się i nie nakładających się obszarów. Możesz renderować go na innych za pomocą kolejki. Możesz również renderować dwustronne. Musisz tylko ustawić "Cull Off". – Podgorskiy

+0

Mam na myśli to, że mam inne obiekty na scenie, które powinny być renderowane na wierzchu tego obiektu za pomocą twojego shadera. – seek