2016-02-23 13 views
12

Sto provando a scrivere uno shader per l'unità che evidenzi i frammenti sovrapposti delle mesh. Dovrebbe funzionare per un oggetto che si sovrappone a se stesso così come a più oggetti.Unity Shader che evidenzia sovrapposizioni

Il risultato dovrebbe apparire come un'immagine allegata. enter image description here

Prima ho provato a realizzare questo con il rilevamento delle collisioni ma penso che il modo migliore sia scrivere uno shader.

Non ho molta familiarità con gli shader quindi se qualcuno potesse aiutarmi sarei grato.

Penso che si possa fare usando stencil shader come qui http://docs.unity3d.com/Manual/SL-Stencil.html ma questi shader rendono solo l'intersezione di due oggetti senza rendere l'intero oggetto.

Ho anche trovato degli shader in base a Profondità (https://chrismflynn.wordpress.com/2012/09/06/fun-with-shaders-and-the-depth-buffer/), ma questo funziona anche su due oggetti e non funziona su una maglia che si

sovrappongono quanto riguarda @Zze commento con l'idea circa due Passo ho ora due shader . E funziona su due oggetti quando uno ha uno shader e l'altro ha un secondo.

Forse qualcuno può aiutarmi a combinarlo in uno shader che funzionerà anche in un oggetto che si sovrapporrà?

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

Il risultato appare come un'immagine associata enter image description here

+0

Se lo shader stencil rende i punti di intersezione, allora perché non si fa a fare uno shader con 2 passaggi, il primo trae normalmente e poi la seconda imita il risultato dello shader stencil? – Zze

+0

Si potrebbe voler guardare la nozione di peeling di profondità. Vedi [qui] (http: //www.opengl-tutorial.org/intermediate-tutorials/tutorial-10-transparency /) e [here] (http://www.eng.utah.edu/~cs5610/handouts/order_independent_transparency.pdf). Anche quanti oggetti hai intenzione di avere. Se non molti si potrebbe voler rendere ogni oggetto a una trama e quindi combinarli come un buffer di accumulo. – mrVoid

+0

@mrVoid Penso che i test di profondità funzioneranno in questa situazione solo con la vista dall'alto della fotocamera, ma quando sarà in prospettiva non funzionerà? Ho mal di testa da questo. forse puoi fornirmi qualche esempio di utilizzo con codice di esempio? – seek

risposta

2

Questo problema può essere risolto con l'aiuto di tampone Stencil e uno, due passaggi Shader. L'idea è la seguente:

  • primo passaggio confronta il valore in tampone stencil con 0. In entrambi i casi (pass/fail) aumentare il valore in tampone.
  • Secondo passaggio confronta il valore nel buffer stencil con 1. Se il valore di riferimento 1 è inferiore, si passa e si evidenzia il pixel sovrapposto.

Si potrebbe desiderare di aggiungere ulteriori passaggi che sono lo stesso come il secondo, ma con valore di riferimento diverso per evidenziare le regioni che si sovrappone due volte, tre volte, ecc

Nella notazione shaderlab di Unità, si deve essere qualcosa di simile:

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

Esempio:

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

Funziona alla grande !. Questo è esattamente quello che stavo cercando. Per favore dimmi che questo shader è reso in cima agli altri, è possibile aggiungere coda a questo? E l'altra cosa è possibile renderlo anche per doppia faccia? – seek

+2

> Per favore dimmi che questo shader è reso in cima agli altri, è possibile aggiungere coda a questo? Non sono sicuro di aver capito correttamente la domanda. Puoi sostituire lo shader in ogni Pass con il tuo, per ottenere ombreggiatori diversi per aree sovrapposte e non sovrapposte. Puoi renderlo sopra gli altri usando la coda. È possibile eseguire il rendering anche fronte-retro. Hai solo bisogno di impostare 'Cull Off'. – Podgorskiy

+0

Voglio dire che ho altri oggetti sulla scena che dovrebbero essere visualizzati sulla parte superiore di questo oggetto con lo shader. – seek