2016-02-23 9 views
12

Ich versuche, einen Shader für die Einheit zu schreiben, der die überlappenden Fragmente von Meshes hervorheben wird. Es sollte für ein Objekt, das sich selbst überlappt, sowie für mehrere Objekte funktionieren.Unity Shader Hervorhebung überlappt

Das Ergebnis sollte wie ein angehängtes Bild aussehen.

Zuerst habe ich versucht, dies mit Kollisionserkennung zu erreichen, aber ich denke, dass der beste Weg ist, einen Shader zu schreiben.

Ich bin nicht sehr vertraut mit Shadern, also wenn mir jemand helfen könnte wäre ich dankbar.

Ich denke, dass es durch die Verwendung von Stencil-Shadern wie hier http://docs.unity3d.com/Manual/SL-Stencil.html getan werden kann, aber diese Shader nur Schnittpunkt zweier Objekte ohne Rendering ganze Objekt.

Ich fand auch Shader basierend auf Tiefe (https://chrismflynn.wordpress.com/2012/09/06/fun-with-shaders-and-the-depth-buffer/) aber auch auf zwei Objekten arbeiten und funktioniert nicht auf ein Netz, das selbst ich habe jetzt zwei Shadern

In Bezug auf @Zze Kommentar mit Vorstellung über zwei Pass überlappen . Und es funktioniert auf zwei Objekte, wenn man einen Shader hat und andere zwei haben.

Vielleicht kann mir jemand helfen, wie man es zu einem Shader kombiniert, der auch in Objekten funktioniert, die sich überlappen?

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 
     } 
    } 
} 

Das Ergebnis sieht aus wie ein Bild angehängt enter image description here

+0

Wenn die Schablone Shader die Schnittpunkte macht, dann, warum man nicht einen Shader mit 2 Pässe machen, die erste zieht normalerweise und dann die zweite ahmt das Ergebnis der Schablone Shader? – Zze

+0

Vielleicht möchten Sie den Begriff der Tiefenschälung betrachten. Siehe [hier] (http://www.opengl-tutorial.com).org/intermediate-tutorials/tutorial-10-transparency /) und [hier] (http://www.eng.utah.edu/~cs5610/handouts/order_independent_transparency.pdf). Wie viele Objekte planen Sie auch? Wenn nicht viele, möchten Sie vielleicht jedes Objekt zu einer Textur rendern und sie dann wie einen Akkumulationspuffer kombinieren. – mrVoid

+0

@mrVoid Ich denke, dass Tiefentests in dieser Situation nur mit der Kamera-Draufsicht funktioniert - aber wenn es Perspektive wird das nicht funktionieren? Ich habe Kopfschmerzen davon. vielleicht können Sie mir ein Beispiel für die Verwendung mit Beispielcode zur Verfügung stellen? – seek

Antwort

2

Dieses Problem mit Hilfe von Stencil-Puffer gelöst werden kann, und einem, zwei Pässe Shader. Die Idee ist der folgende:

  • Erster Durchgang vergleicht den Wert in Schablonenpuffer mit 0. In beiden Fällen (bestanden/nicht bestanden), um den Wert im Puffer erhöhen.
  • Der zweite Durchlauf vergleicht den Wert im Schablonenpuffer mit 1. Wenn der Referenzwert 1 kleiner ist, übergeben wir das überlappende Pixel und markieren es.

Sie könnten mehr Pässe hinzufügen möchten, die die gleiche wie die zweiten, aber mit verschiedenen Werten Referenzbereiche betonen, dass zwei Mal überlappt, dreimal usw.

In shaderlab Notation Unity, sollte es so etwas wie das:

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. 
    } 

Beispiel:

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

Funktioniert gut !. Genau das habe ich gesucht. Bitte sagen Sie mir, dass dieser Shader oben auf den anderen gerendert wird. Ist es möglich, Queue hinzuzufügen? Und die andere Sache ist es möglich, dies auch für zweiseitige zu machen? – seek

+2

> Bitte sagen Sie mir, dass dieser Shader oben auf den anderen gerendert wird. Ist es möglich Queue dazu hinzuzufügen? Nicht sicher, dass ich Frage richtig verstanden habe. Sie können den Shader in jedem Pass durch Ihren eigenen ersetzen, um verschiedene Shader für überlappende und nicht überlappende Bereiche zu erhalten. Sie können es mithilfe der Warteschlange über die anderen rendern. Sie können auch doppelseitig rendern. Sie müssen nur 'Cull Off' einstellen. – Podgorskiy

+0

Ich meine, dass ich andere Objekte in der Szene habe, die mit dem Shader oben auf diesem Objekt gerendert werden sollen. – seek