Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Is it possible to use Geometry shader with surface shaders?

Discussion in 'Shaders' started by Noisecrime, Jan 5, 2013.

  1. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,051
    Hi,

    Playing around with geometry shaders in dx111 and wonder if its possible to incorporate them directly into surface shaders?

    My experience so far says no. You can't add the #pragma geometry and there appears to be no Unity directives to allow a reference to a GS (e.g. like vertex for defining your own vertex shader for surface shaders).

    Obviously it should be possible to use debug to extract all the relevant parts of a surface shader and retro-actively add a GS into it, but I was hoping for a easier solution.

    Thanks
     
  2. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,051
    Ok, this is proving more difficult than I expected.

    I went with using a debug version of the standard Unity normal-diffuse shader to extract the Fwd_Base pass code from it, hoping to just integrate the geometry shader into it. However all i get are errors, well warnings, but the upshot is the full shader fails to compile.

    Below you'll find firstly the basic GS shader. Its taken from the old june2010 DirectX SDK, tutorial 13 and simply 'explodes' each triangle in a mesh into a pyramid. Apply this shader to a material and place it on a mesh (in dx11 mode) and it works fine.

    After that i've posted my progress with trying to integrate this GeometryShader into the code Unity creates for a fwd_Base surface shader and the errors it reports.

    If anyone has any ideas how to get this to compile correctly i'd be very grateful. Alternatively i'm still looking to see if there is an easier method of integrating a GS into a surface shader or a good way to use Unity to obtain lighting data to shade the GS.


    The basic GS shader
    Code (csharp):
    1. // Taken from DirectX SDK (June 2010) - Tutorial 13
    2. // http://msdn.microsoft.com/en-us/library/windows/desktop/bb205122%28v=vs.85%29.aspx
    3.  
    4. Shader "|Unity 4/Geomtery/GeometryPyramid"
    5. {
    6.     Properties
    7.     {
    8.         _MainTex ("Particle Texture", 2D) = "white" {}
    9.         _Explode ("Explode factor", Range(0.0, 4.0)) = 1.0
    10.     }
    11.    
    12.     SubShader
    13.     {
    14.         Pass
    15.         {          
    16.             CGPROGRAM
    17.                 #pragma target 5.0
    18.            
    19.                 #pragma vertex vert
    20.                 #pragma geometry geom
    21.                 #pragma fragment frag
    22.            
    23.                 #include "UnityCG.cginc"
    24.                    
    25.                 sampler2D   _MainTex;              
    26.                 float4      _MainTex_ST;           
    27.                 float       _Explode;
    28.                 float4x4    _ViewMatrix;
    29.                                
    30.                 struct VS_INPUT
    31.                 {
    32.                     float4 Pos  : POSITION;        
    33.                     float3 Norm : NORMAL;          
    34.                     float2 Tex  : TEXCOORD0;        
    35.                 };
    36.  
    37.                 // GEOMETRY
    38.                 struct GSPS_INPUT
    39.                 {                          
    40.                     float4 Pos  : SV_POSITION;
    41.                     float3 Norm : TEXCOORD0;
    42.                     float2 Tex  : TEXCOORD1;
    43.                 };
    44.                                
    45.                 // Vertex Shader
    46.                 GSPS_INPUT vert( VS_INPUT input )
    47.                 {
    48.                     GSPS_INPUT output = (GSPS_INPUT)0;
    49.                    
    50.                     output.Pos  = input.Pos;  // mul( float4(input.Pos,1), _Object2World);  // mul( float4(input.Pos,1), World );
    51.                     output.Norm = input.Norm; // mul(input.Norm, (float3x3)_Object2World ); // mul( input.Norm, (float3x3)World );
    52.                     output.Tex  = TRANSFORM_TEX(input.Tex, _MainTex);  // input.Tex;
    53.                                    
    54.                     return output;
    55.                 }
    56.  
    57.                 // Geometry Shader
    58.                 [maxvertexcount(12)]
    59.                 void geom( triangle GSPS_INPUT input[3], inout TriangleStream<GSPS_INPUT> outStream )
    60.                 {
    61.                     GSPS_INPUT output;
    62.  
    63.                     // Calculate the face normal
    64.                     float3 faceEdgeA = input[1].Pos - input[0].Pos;
    65.                     float3 faceEdgeB = input[2].Pos - input[0].Pos;
    66.                     float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );
    67.                     float3 ExplodeAmt = faceNormal*_Explode;
    68.                    
    69.                     // Calculate the face center                 
    70.                     float3 centerPos = (input[0].Pos.xyz + input[1].Pos.xyz + input[2].Pos.xyz)/3.0;
    71.                     float2 centerTex = (input[0].Tex + input[1].Tex + input[2].Tex)/3.0;
    72.                     centerPos += faceNormal*_Explode;                  
    73.                
    74.                     // Output the pyramid          
    75.                     for( int i=0; i<3; i++ )
    76.                     {
    77.                         output.Pos = input[i].Pos + float4(ExplodeAmt,0);                                                  
    78.                         output.Pos = mul(UNITY_MATRIX_MVP, output.Pos);
    79.                         output.Norm = input[i].Norm;
    80.                         output.Tex = input[i].Tex;
    81.                         outStream.Append( output );
    82.                        
    83.                         int iNext = (i+1)%3;
    84.                         output.Pos = input[iNext].Pos + float4(ExplodeAmt,0);
    85.                         output.Pos = mul(UNITY_MATRIX_MVP, output.Pos);
    86.                         output.Norm = input[iNext].Norm;
    87.                         output.Tex = input[iNext].Tex;
    88.                         outStream.Append( output );
    89.                        
    90.                         output.Pos = float4(centerPos,1) + float4(ExplodeAmt,0);
    91.                         output.Pos = mul(UNITY_MATRIX_MVP, output.Pos);                  
    92.                         output.Norm = faceNormal;
    93.                         output.Tex = centerTex;
    94.                         outStream.Append( output );
    95.                        
    96.                         outStream.RestartStrip();
    97.                     }
    98.                    
    99.                     for( int i=2; i>=0; i-- )
    100.                     {
    101.                         output.Pos = input[i].Pos + float4(ExplodeAmt,0);
    102.                         output.Pos = mul(UNITY_MATRIX_MVP, output.Pos);
    103.                         output.Norm = -input[i].Norm;
    104.                         output.Tex = input[i].Tex;
    105.                         outStream.Append( output );
    106.                     }
    107.                     outStream.RestartStrip();
    108.                 }
    109.                
    110.                
    111.                 // FRAG
    112.                 fixed4 frag (GSPS_INPUT i ) : COLOR0
    113.                 {                  
    114.                     fixed4 col = tex2D(_MainTex, i.Tex);   
    115.                     return col;
    116.                 }      
    117.             ENDCG          
    118.         }
    119.     }
    120.     Fallback Off
    121. }
    122.  

    This is the current state of the version that attempts to integrate with Unity lighting via using the compiled/debug code from the normal-diffuse surface shader.
    Code (csharp):
    1. // Taken from DirectX SDK (June 2010) - Tutorial 13
    2. // http://msdn.microsoft.com/en-us/library/windows/desktop/bb205122%28v=vs.85%29.aspx
    3.  
    4. Shader "|Unity 4/Geomtery/GeometryPyramidLit"
    5. {
    6.     Properties
    7.     {
    8.         _Color ("Main Color", Color) = (1,1,1,1)
    9.         _MainTex ("Particle Texture", 2D) = "white" {}
    10.         _Explode ("Explode factor", Range(0.0, 4.0)) = 1.0
    11.     }
    12.  
    13.     SubShader
    14.     {
    15.         Tags { "RenderType"="Opaque" }
    16.         LOD 200
    17.            
    18.         Pass
    19.         {  
    20.             Name "FORWARD"
    21.             Tags { "LightMode" = "ForwardBase" }
    22.    
    23.             CGPROGRAM
    24.             #pragma target      5.0
    25.            
    26.             #pragma vertex      vert
    27.             #pragma geometry    geom
    28.             #pragma fragment    frag           
    29.            
    30.             #pragma fragmentoption ARB_precision_hint_fastest
    31.             #pragma multi_compile_fwdbase
    32.            
    33.             #include "HLSLSupport.cginc"
    34.             #include "UnityShaderVariables.cginc"
    35.            
    36.             #define UNITY_PASS_FORWARDBASE
    37.            
    38.             #include "UnityCG.cginc"
    39.             #include "Lighting.cginc"
    40.             #include "AutoLight.cginc"
    41.            
    42.             #define INTERNAL_DATA
    43.             #define WorldReflectionVector(data,normal) data.worldRefl
    44.             #define WorldNormalVector(data,normal) normal
    45.  
    46.             #pragma only_renderers d3d11
    47.             //#pragma surface surf Lambert                                 
    48.             //#pragma debug
    49.                        
    50.             sampler2D   _MainTex;
    51.             fixed4      _Color;
    52.             float       _Explode;
    53.                                                
    54.             struct Input
    55.             {
    56.                 float2 uv_MainTex;
    57.             };
    58.                        
    59.             void surf (Input IN, inout SurfaceOutput o)
    60.             {
    61.                 fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    62.                 o.Albedo = c.rgb;
    63.                 o.Alpha  = c.a;
    64.             }      
    65.            
    66.             struct v2f_surf
    67.             {
    68.                 float4 pos : SV_POSITION;
    69.                 float2 pack0 : TEXCOORD0;
    70.                 fixed3 normal : TEXCOORD1;
    71.                 fixed3 vlight : TEXCOORD2;
    72.                 LIGHTING_COORDS(3,4)
    73.             //  float3 _LightCoord : TEXCOORD3;
    74.             //  float3 _ShadowCoord : TEXCOORD4;               
    75.             };
    76.                                
    77.             float4 _MainTex_ST;
    78.                        
    79.             v2f_surf vert (appdata_full v)
    80.             {
    81.                 v2f_surf o;
    82.                      
    83.                 o.pos = v.vertex; // mul (UNITY_MATRIX_MVP, v.vertex);
    84.                 o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    85.                                        
    86.                 float3 worldN = mul((float3x3)_Object2World, SCALED_NORMAL);
    87.                
    88.                 o.normal = worldN;
    89.            
    90.                 float3 shlight = ShadeSH9 (float4(worldN,1.0));
    91.                 o.vlight = shlight;
    92.                
    93.                 #ifdef VERTEXLIGHT_ON
    94.                     float3 worldPos = mul(_Object2World, v.vertex).xyz;
    95.                     o.vlight += Shade4PointLights (
    96.                     unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
    97.                     unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
    98.                     unity_4LightAtten0, worldPos, worldN );
    99.                 #endif // VERTEXLIGHT_ON
    100.            
    101.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    102.              
    103.                 return o;
    104.             }
    105.            
    106.        
    107.                 // Geometry Shader
    108.                 [maxvertexcount(12)]
    109.                 void geom( triangle v2f_surf input[3], inout TriangleStream<v2f_surf> outStream )
    110.                 {                  
    111.                     v2f_surf output;
    112.                
    113.                     // Calculate the face normal
    114.                     float3 faceEdgeA = input[1].pos - input[0].pos;
    115.                     float3 faceEdgeB = input[2].pos - input[0].pos;
    116.                     float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );
    117.                     float3 ExplodeAmt = faceNormal*_Explode;
    118.                    
    119.                     // Calculate the face center                 
    120.                     float3 centerPos = (input[0].pos.xyz + input[1].pos.xyz + input[2].pos.xyz)/3.0;
    121.                     float2 centerTex = (input[0].pack0 + input[1].pack0 + input[2].pack0)/3.0;
    122.                     centerPos += faceNormal*_Explode;                  
    123.                
    124.                     // Output the pyramid          
    125.                     for( int looper=0; looper<3; looper++ )
    126.                     {
    127.                         output.pos = input[looper].pos + float4(ExplodeAmt,0);                                         
    128.                         output.pos = mul(UNITY_MATRIX_MVP, output.pos);                
    129.                         output.normal = input[looper].normal;
    130.                         output.pack0 = input[looper].pack0;
    131.                         output.vlight = input[looper].vlight;
    132.                    //     output._ShadowCoord = input[looper]._ShadowCoord;
    133.                    //     output._LightCoord  = input[looper]._LightCoord;
    134.                         outStream.Append( output );
    135.                                                
    136.                         int iNext = (looper+1)%3;
    137.                         output.pos = input[iNext].pos + float4(ExplodeAmt,0);
    138.                         output.pos = mul(UNITY_MATRIX_MVP, output.pos);
    139.                         output.normal = input[iNext].normal;
    140.                         output.pack0 = input[iNext].pack0;
    141.                         output.vlight = input[iNext].vlight;
    142.                   //      output._ShadowCoord = input[iNext]._ShadowCoord;
    143.                   //      output._LightCoord  = input[iNext]._LightCoord;  
    144.                         outStream.Append( output );
    145.                                                
    146.                         output.pos = float4(centerPos,1) + float4(ExplodeAmt,0);
    147.                         output.pos = mul(UNITY_MATRIX_MVP, output.pos);                  
    148.                         output.normal = faceNormal;
    149.                         output.pack0 = centerTex;
    150.                         output.vlight = input[looper].vlight;
    151.                    //     output._ShadowCoord = input[looper]._ShadowCoord;
    152.                    //     output._LightCoord  = input[looper]._LightCoord;
    153.                         outStream.Append( output );
    154.                        
    155.                         outStream.RestartStrip();
    156.                     }
    157.                    
    158.                     for( int looper=2; looper>=0; looper-- )
    159.                     {
    160.                         output.pos = input[looper].pos + float4(ExplodeAmt,0);
    161.                         output.pos = mul(UNITY_MATRIX_MVP, output.pos);
    162.                         output.normal = -input[looper].normal;
    163.                         output.pack0 = input[looper].pack0;
    164.                         output.vlight = input[looper].vlight;
    165.                    //     output._ShadowCoord = input[looper]._ShadowCoord;
    166.                    //     output._LightCoord  = input[looper]._LightCoord;
    167.                         outStream.Append( output );
    168.                     }
    169.                     outStream.RestartStrip();
    170.                 }                  
    171.            
    172.             fixed4 frag (v2f_surf IN) : COLOR
    173.             {
    174.                 Input surfIN;
    175.                 surfIN.uv_MainTex = IN.pack0.xy;
    176.                
    177.                 #ifdef UNITY_COMPILER_HLSL
    178.                     SurfaceOutput o = (SurfaceOutput)0;
    179.                 #else
    180.                     SurfaceOutput o;
    181.                 #endif
    182.                
    183.                 o.Albedo    = 0.0;
    184.                 o.Emission  = 0.0;
    185.                 o.Specular  = 0.0;
    186.                 o.Alpha     = 0.0;
    187.                 o.Gloss     = 0.0; 
    188.                 o.Normal = IN.normal;
    189.                                
    190.                 surf (surfIN, o);
    191.                 fixed atten = LIGHT_ATTENUATION(IN);
    192.                 fixed4 c = 0;                
    193.                
    194.                 c = LightingLambert (o, _WorldSpaceLightPos0.xyz, atten);          
    195.                 c.rgb += o.Albedo * IN.vlight; 
    196.                
    197.                 return c;
    198.             }
    199.            
    200.             ENDCG          
    201.         } // Pass ForwardBase      
    202.        
    203.     } // subshader
    204.  
    205.     Fallback Off
    206. }
    207.  
    This shader gives the following warnings and fails to compile


    None of which occur in the initial GS shader example above, and some of which are rather weird, e.g. looper redefinition?

    I tried adding _LightCoord _ShadowCoord to the GS (see commented out lines) as I suspect they will be needed, but bizarrely that throws up different warnings in the vertex shader?
    I also tried defining _LightCoord _ShadowCoord directly in the struct, but as the types change depending on the incoming light type that didn't work either.

    So any ideas?
     
    Last edited: Jan 5, 2013
  3. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    you can not use anything but VS and PS in surface shaders.
    Surface shaders are meant to work on all unity platforms, not only Windows 7+ with DX11+ gpu which is the only place where DX11 will work.

    Technically its also related to the fac that Unity rewrites parts of it and expands it.

    But you could add the debug pragma to see the output and then expand that one for example, that gives you the surface shader aspect while you can freely modify it for your DX11 only version while you take the original code as another fallback shader in case DX11 is not supported for example
     
    juliocrm likes this.
  4. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    No. There's also some support for tessellation (hull domain shaders).

    No. "Work on all platforms" was never the goal of surface shaders, and will never be (though of course it's desirable). The goal of surface shaders is "make working with lighting simpler", that's the only problem they try to solve.

    Answer to noisecrime: no, it's not possible to use geometry shaders with surface shaders right now, so you'll have to write the shader "by hand". I haven't looked at the errors you're getting with your approach (not on a Windows box right now either). But DX11 shader compiler (HLSL) is much more strict than Cg, e.g. it doesn't like output parameters that aren't initialized, and so on.
     
  5. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,051
    Thanks Aras, though I did ensure that all output parameters are initialized, though doing so for the GS caused additional errors.
    I'd be very grateful if you could find some time to check out the shader errors at some point, or alternatively if you could maybe write out how you'd write a shader that can utilise Unity lighting and shadows with a GS.

    Do you have any plans to incorporate support for GS in surface shaders in the future like how you were able to with tessellation shaders?
     
  6. Jonathan Marin

    Jonathan Marin

    Joined:
    Oct 7, 2013
    Posts:
    6
    Hello Noisecrime,
    I took a look at your shader and fix the issues you mentioned above:

    Code (csharp):
    1.  
    2. Shader "Geom/GeometryPyramidLit"
    3.  
    4. {
    5.  
    6.     Properties
    7.  
    8.     {
    9.  
    10.         _Color ("Main Color", Color) = (1,1,1,1)
    11.  
    12.         _MainTex ("Particle Texture", 2D) = "white" {}
    13.  
    14.         _Explode ("Explode factor", Range(0.0, 4.0)) = 1.0
    15.  
    16.     }
    17.  
    18.  
    19.  
    20.     SubShader
    21.  
    22.     {
    23.  
    24.         Tags { "RenderType"="Opaque" }
    25.  
    26.         LOD 200
    27.  
    28.            
    29.  
    30.         Pass
    31.  
    32.         {  
    33.  
    34.             Name "FORWARD"
    35.  
    36.             Tags { "LightMode" = "ForwardBase" }
    37.  
    38.    
    39.  
    40.             CGPROGRAM
    41.  
    42.             #pragma target      5.0
    43.  
    44.            
    45.  
    46.             #pragma vertex      vert
    47.  
    48.             #pragma geometry    geom
    49.  
    50.             #pragma fragment    frag            
    51.  
    52.            
    53.  
    54.             #pragma fragmentoption ARB_precision_hint_fastest
    55.  
    56.             #pragma multi_compile_fwdbase
    57.  
    58.            
    59.  
    60.             #include "HLSLSupport.cginc"
    61.  
    62.             #include "UnityShaderVariables.cginc"
    63.  
    64.            
    65.  
    66.             #define UNITY_PASS_FORWARDBASE
    67.  
    68.            
    69.  
    70.             #include "UnityCG.cginc"
    71.  
    72.             #include "Lighting.cginc"
    73.  
    74.             #include "AutoLight.cginc"
    75.  
    76.            
    77.  
    78.             #define INTERNAL_DATA
    79.  
    80.             #define WorldReflectionVector(data,normal) data.worldRefl
    81.  
    82.             #define WorldNormalVector(data,normal) normal
    83.  
    84.  
    85.  
    86.             #pragma only_renderers d3d11
    87.  
    88.             //#pragma surface surf Lambert                                  
    89.  
    90.             //#pragma debug
    91.  
    92.                        
    93.  
    94.             sampler2D   _MainTex;
    95.  
    96.             fixed4      _Color;
    97.  
    98.             float       _Explode;
    99.  
    100.                                                
    101.  
    102.             struct Input
    103.  
    104.             {
    105.  
    106.                 float2 uv_MainTex;
    107.  
    108.             };
    109.  
    110.                        
    111.  
    112.             void surf (Input IN, inout SurfaceOutput o)
    113.  
    114.             {
    115.  
    116.                 fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    117.  
    118.                 o.Albedo = c.rgb;
    119.  
    120.                 o.Alpha  = c.a;
    121.  
    122.             }      
    123.  
    124.            
    125.  
    126.             struct v2f_surf
    127.  
    128.             {
    129.  
    130.                 float4 pos : SV_POSITION;
    131.  
    132.                 float2 pack0 : TEXCOORD0;
    133.  
    134.                 fixed3 normal : TEXCOORD1;
    135.  
    136.                 fixed3 vlight : TEXCOORD2;
    137.  
    138.                 LIGHTING_COORDS(3,4)
    139.  
    140.             //  float3 _LightCoord : TEXCOORD3;
    141.  
    142.             //  float3 _ShadowCoord : TEXCOORD4;                
    143.  
    144.             };
    145.  
    146.                                
    147.  
    148.             float4 _MainTex_ST;
    149.  
    150.                        
    151.  
    152.             v2f_surf vert (appdata_full v)
    153.  
    154.             {
    155.  
    156.                 v2f_surf o;
    157.  
    158.                      
    159.  
    160.                 o.pos = v.vertex; // mul (UNITY_MATRIX_MVP, v.vertex);
    161.  
    162.                 o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    163.  
    164.                                        
    165.  
    166.                 float3 worldN = mul((float3x3)_Object2World, SCALED_NORMAL);
    167.  
    168.                
    169.  
    170.                 o.normal = worldN;
    171.  
    172.            
    173.  
    174.                 float3 shlight = ShadeSH9 (float4(worldN,1.0));
    175.  
    176.                 o.vlight = shlight;
    177.  
    178.                
    179.  
    180.                 #ifdef VERTEXLIGHT_ON
    181.  
    182.                     float3 worldPos = mul(_Object2World, v.vertex).xyz;
    183.  
    184.                     o.vlight += Shade4PointLights (
    185.  
    186.                     unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
    187.  
    188.                     unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
    189.  
    190.                     unity_4LightAtten0, worldPos, worldN );
    191.  
    192.                 #endif // VERTEXLIGHT_ON
    193.  
    194.            
    195.  
    196.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    197.  
    198.              
    199.  
    200.                 return o;
    201.  
    202.             }
    203.  
    204.            
    205.  
    206.        
    207.  
    208.                 // Geometry Shader
    209.  
    210.                 [maxvertexcount(12)]
    211.  
    212.                 void geom( triangle v2f_surf input[3], inout TriangleStream<v2f_surf> outStream )
    213.  
    214.                 {                  
    215.  
    216.                     v2f_surf output;
    217.                                    
    218.  
    219.                     // Calculate the face normal
    220.  
    221.                     float3 faceEdgeA = input[1].pos - input[0].pos;
    222.  
    223.                     float3 faceEdgeB = input[2].pos - input[0].pos;
    224.  
    225.                     float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );
    226.  
    227.                     float3 ExplodeAmt = faceNormal*_Explode;
    228.  
    229.                    
    230.  
    231.                     // Calculate the face center                
    232.  
    233.                     float3 centerPos = (input[0].pos.xyz + input[1].pos.xyz + input[2].pos.xyz)/3.0;
    234.  
    235.                     float2 centerTex = (input[0].pack0 + input[1].pack0 + input[2].pack0)/3.0;
    236.  
    237.                     centerPos += faceNormal*_Explode;                  
    238.                                    
    239.                     // Output the pyramid          
    240.  
    241.                     for( int looper=0; looper<3; looper++ )
    242.  
    243.                     {
    244.  
    245.                         output.pos = input[looper].pos + float4(ExplodeAmt,0);                                          
    246.  
    247.                         output.pos = mul(UNITY_MATRIX_MVP, output.pos);                
    248.  
    249.                         output.normal = input[looper].normal;
    250.  
    251.                         output.pack0 = input[looper].pack0;
    252.  
    253.                         output.vlight = input[looper].vlight;
    254.                          TRANSFER_VERTEX_TO_FRAGMENT(output);
    255.                        // output._ShadowCoord = input[looper]._ShadowCoord;
    256.  
    257.                    //     output._LightCoord  = input[looper]._LightCoord;
    258.  
    259.                         outStream.Append( output );
    260.        
    261.                         uint iNext = looper+1;
    262.  
    263.                         if(iNext>2)
    264.                         {
    265.                             iNext=0;
    266.                         }
    267.                         output.pos = input[iNext].pos + float4(ExplodeAmt,0);
    268.  
    269.                         output.pos = mul(UNITY_MATRIX_MVP, output.pos);
    270.  
    271.                         output.normal = input[iNext].normal;
    272.  
    273.                         output.pack0 = input[iNext].pack0;
    274.  
    275.                         output.vlight = input[iNext].vlight;
    276.  
    277.                   //      output._ShadowCoord = input[iNext]._ShadowCoord;
    278.  
    279.                   //      output._LightCoord  = input[iNext]._LightCoord;  
    280.  
    281.                         outStream.Append( output );
    282.  
    283.                                                
    284.  
    285.                         output.pos = float4(centerPos,1) + float4(ExplodeAmt,0);
    286.  
    287.                         output.pos = mul(UNITY_MATRIX_MVP, output.pos);                  
    288.  
    289.                         output.normal = faceNormal;
    290.  
    291.                         output.pack0 = centerTex;
    292.  
    293.                         output.vlight = input[looper].vlight;
    294.  
    295.                    //     output._ShadowCoord = input[looper]._ShadowCoord;
    296.  
    297.                    //     output._LightCoord  = input[looper]._LightCoord;
    298.  
    299.                         outStream.Append( output );
    300.  
    301.                        
    302.  
    303.                         outStream.RestartStrip();
    304.  
    305.                     }
    306.  
    307.                    
    308.  
    309.                     for(int cpt=2; cpt>=0; cpt-- )
    310.  
    311.                     {
    312.  
    313.                         output.pos = input[cpt].pos + float4(ExplodeAmt,0);
    314.  
    315.                         output.pos = mul(UNITY_MATRIX_MVP, output.pos);
    316.  
    317.                         output.normal = -input[cpt].normal;
    318.  
    319.                         output.pack0 = input[cpt].pack0;
    320.  
    321.                         output.vlight = input[cpt].vlight;
    322.  
    323.                    //     output._ShadowCoord = input[looper]._ShadowCoord;
    324.  
    325.                    //     output._LightCoord  = input[looper]._LightCoord;
    326.  
    327.                         outStream.Append( output );
    328.  
    329.                     }
    330.  
    331.                     outStream.RestartStrip();
    332.  
    333.                 }                  
    334.  
    335.            
    336.  
    337.             fixed4 frag (v2f_surf IN) : COLOR
    338.  
    339.             {
    340.  
    341.                 Input surfIN;
    342.  
    343.                 surfIN.uv_MainTex = IN.pack0.xy;
    344.  
    345.                
    346.  
    347.                 #ifdef UNITY_COMPILER_HLSL
    348.  
    349.                     SurfaceOutput o = (SurfaceOutput)0;
    350.  
    351.                 #else
    352.  
    353.                     SurfaceOutput o;
    354.  
    355.                 #endif
    356.  
    357.                
    358.  
    359.                 o.Albedo    = 0.0;
    360.  
    361.                 o.Emission  = 0.0;
    362.  
    363.                 o.Specular  = 0.0;
    364.  
    365.                 o.Alpha     = 0.0;
    366.  
    367.                 o.Gloss     = 0.0;  
    368.  
    369.                 o.Normal = IN.normal;
    370.  
    371.                                
    372.  
    373.                 surf (surfIN, o);
    374.  
    375.                 fixed atten = LIGHT_ATTENUATION(IN);
    376.  
    377.                 fixed4 c = 0;                
    378.  
    379.                
    380.  
    381.                 c = LightingLambert (o, _WorldSpaceLightPos0.xyz, atten);          
    382.  
    383.                 c.rgb += o.Albedo * IN.vlight;  
    384.  
    385.                
    386.  
    387.                 return c;
    388.  
    389.             }
    390.  
    391.            
    392.  
    393.             ENDCG          
    394.  
    395.         } // Pass ForwardBase      
    396.  
    397.        
    398.  
    399.     } // subshader
    400.  
    401.  
    402.  
    403.     Fallback Off
    404.  
    405. }
    I am actually making a shader using approximatively the same idea. I need to collect and cast shadows too, take me aware if it helped and if you improved your shader.
     
  7. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,051
    Hey, well that's a coincidence, I was just looking at this old shader the other day whilst doing some related tessellation work. I'd not checked in on this thread for a long time, but after fixing a number of issues with the original shader, I thought i'd come and check out my original post.

    I'd fixed most of the errors I mentioned at the time, not sure why I couldn't back then, maybe i'd just been working on it for too long and got fed up with it. However your code addressed the last two issues i'd ran into, the first being the modulus function that you replaced ( plus unit to int), the second being the addition of TRANSFER_VERTEX_TO_FRAGMENT(); though that's partly just to fix the output not being fully initialized error.

    Overall the shader does provide some correct lighting now, but its not perfect (its predetermined by the original faces) and doesn't seem to support shadows properly yet either. I susepct both of these issues are due to using the TRANSFER_VERTEX_TO_FRAGMENT function as it relies on using v.vertex and not the newly generated vertices from the geom shader. I'm hopeful that this can be fixed relatively easily with a custom function. I'll post any further fixes here when/if I get time to look into it.
     
  8. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,051
    Think I've finally nailed it and so will post the source here for others in case its of any use. There are still issues with getting the correct lighting/shading on the pyramids, but that is an issue with the original code (see msdn link) not the shader code.

    This is basically a proof-of-concept, without being able to use surface shader code directly the code has ended up being very long, a bit messy, non-optimal and only supports forward base, so no forward-add, no deferred and is Dx11 only. It should also be noted that this is just a replacement for the standard diffuse shader with a geometry shader designed to turn triangles into pyramids, so specifically it has limited uses.

    I have no idea if recent Unity releases (e.g. 4.5) have addressed the overall issue of supporting Geometry shaders directly within surface shaders, I intend to check it out, but continued with this as a learning process. However as I said above the end result is very long and messy, so assuming Surface shaders do not support geometry shaders there will be considerable amount of effort to go through and clean up the code, more so to get something that is re-usable for different shader types.

    In order to get it working I had to append code to both AutoLight.cginc and UnityCG.cginc, so these need to be place at the same directory level as the shaders that use them in your project in order for them to override the Unity defaults.

    The main stumbling block in getting this working was replacing the various function defines that Unity/surface shaders use such as TRANSFER_VERTEX_TO_FRAGMENT, TRANSFER_SHADOW,TRANSFER_SHADOW_COLLECTOR and TRANSFER_SHADOW_CASTER.


    The Triangle To Pyramid Geometry Shader

    Code (CSharp):
    1. // Taken from DirectX SDK (June 2010) - Tutorial 13
    2. // http://msdn.microsoft.com/en-us/library/windows/desktop/bb205122%28v=vs.85%29.aspx
    3. Shader "|Unity 4/Geometery/GeometryPyramidDiffuse"
    4. {
    5.    Properties
    6.    {
    7.      _Color ("Main Color", Color) = (1,1,1,1)
    8.      _MainTex ("Particle Texture", 2D) = "white" {}
    9.      _Explode ("Explode factor", Range(0.0, 4.0)) = 1.0
    10.    }
    11.  
    12.    SubShader
    13.    {
    14.      Tags { "RenderType"="Opaque" }
    15.      LOD 200
    16.    
    17.      Pass
    18.      {
    19.        Name "FORWARD"
    20.        Tags { "LightMode" = "ForwardBase" }
    21.      
    22.        CGPROGRAM
    23.        #pragma target  5.0
    24.      
    25.        #pragma vertex  vert
    26.        #pragma geometry  geom
    27.        #pragma fragment  frag
    28.      
    29.        #pragma fragmentoption ARB_precision_hint_fastest
    30.        #pragma multi_compile_fwdbase
    31.      
    32.        #include "HLSLSupport.cginc"
    33.        #include "UnityShaderVariables.cginc"
    34.      
    35.        #define UNITY_PASS_FORWARDBASE
    36.      
    37.        #include "UnityCG.cginc"
    38.        #include "Lighting.cginc"
    39.        #include "AutoLight.cginc"
    40.      
    41.        #define INTERNAL_DATA
    42.        #define WorldReflectionVector(data,normal) data.worldRefl
    43.        #define WorldNormalVector(data,normal) normal
    44.      
    45.        #pragma only_renderers d3d11
    46.        // #pragma surface surf Lambert
    47.        // #pragma debug
    48.      
    49.        sampler2D  _MainTex;
    50.        fixed4  _Color;
    51.        float  _Explode;
    52.      
    53.        struct Input
    54.        {
    55.          float2 uv_MainTex;
    56.        };
    57.      
    58.        void surf (Input IN, inout SurfaceOutput o)
    59.        {
    60.          fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    61.          o.Albedo = c.rgb;
    62.          o.Alpha  = c.a;
    63.        }
    64.      
    65.        struct v2f_surf
    66.        {
    67.          float4 pos : SV_POSITION;
    68.          float2 pack0 : TEXCOORD0;
    69.          fixed3 normal : TEXCOORD1;
    70.          fixed3 vlight : TEXCOORD2;
    71.          LIGHTING_COORDS(3,4)
    72.        };
    73.      
    74.        float4 _MainTex_ST;
    75.      
    76.        v2f_surf vert (appdata_full v)
    77.        {
    78.          v2f_surf o;
    79.          o.pos = v.vertex; // mul (UNITY_MATRIX_MVP, v.vertex);
    80.          o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    81.        
    82.          float3 worldN = mul((float3x3)_Object2World, SCALED_NORMAL);
    83.          o.normal = worldN;
    84.          float3 shlight = ShadeSH9 (float4(worldN,1.0));
    85.          o.vlight = shlight;
    86.        
    87.          #ifdef VERTEXLIGHT_ON
    88.            float3 worldPos = mul(_Object2World, v.vertex).xyz;
    89.            o.vlight += Shade4PointLights (
    90.            unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
    91.            unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
    92.            unity_4LightAtten0, worldPos, worldN );
    93.          #endif // VERTEXLIGHT_ON
    94.        
    95.          // TRANSFER_VERTEX_TO_FRAGMENT(o);
    96.          return o;
    97.        }
    98.      
    99.        // Geometry Shader
    100.        [maxvertexcount(12)]
    101.        void geom( triangle v2f_surf input[3], inout TriangleStream<v2f_surf> outStream )
    102.        {
    103.          v2f_surf output;
    104.        
    105.          // Calculate the face normal
    106.          float3 faceEdgeA = input[1].pos - input[0].pos;
    107.          float3 faceEdgeB = input[2].pos - input[0].pos;
    108.          float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );
    109.          float3 ExplodeAmt = faceNormal*_Explode;
    110.        
    111.          // Calculate the face center
    112.          float3 centerPos = (input[0].pos.xyz + input[1].pos.xyz + input[2].pos.xyz)/3.0;
    113.          float2 centerTex = (input[0].pack0 + input[1].pack0 + input[2].pack0)/3.0;
    114.          centerPos += faceNormal*_Explode;
    115.        
    116.          // Output the pyramid
    117.          for( int looper=0; looper<3; looper++ )
    118.          {
    119.            output.pos = input[looper].pos + float4(ExplodeAmt,0);
    120.            output.pos = mul(UNITY_MATRIX_MVP, output.pos);
    121.            output.normal = input[looper].normal;
    122.            output.pack0 = input[looper].pack0;
    123.            output.vlight = input[looper].vlight;
    124.            TRANSFER_GEOM_TO_FRAGMENT(output); // Probably need to do this by hand since it uses v.vertex!!    
    125.            outStream.Append( output );
    126.          
    127.            // uint iNext = (looper+1)%3; // Note: this causes errors in compilation
    128.            uint iNext = looper+1;
    129.            if (iNext>2) iNext = 0;
    130.          
    131.            output.pos = input[iNext].pos + float4(ExplodeAmt,0);
    132.            output.pos = mul(UNITY_MATRIX_MVP, output.pos);
    133.            output.normal = input[iNext].normal;
    134.            output.pack0 = input[iNext].pack0;
    135.            output.vlight = input[iNext].vlight;
    136.            TRANSFER_GEOM_TO_FRAGMENT(output);     // TRANSFER_VERTEX_TO_FRAGMENT
    137.            outStream.Append( output );
    138.          
    139.            output.pos = float4(centerPos,1) + float4(ExplodeAmt,0);
    140.            output.pos = mul(UNITY_MATRIX_MVP, output.pos);
    141.            output.normal = faceNormal;
    142.            output.pack0 = centerTex;
    143.            output.vlight = input[looper].vlight;
    144.            TRANSFER_GEOM_TO_FRAGMENT(output);
    145.            outStream.Append( output );
    146.          
    147.            outStream.RestartStrip();
    148.          }
    149.        
    150.          for(int cpt=2; cpt>=0; cpt-- )
    151.          {
    152.            output.pos = input[cpt].pos + float4(ExplodeAmt,0);
    153.            output.pos = mul(UNITY_MATRIX_MVP, output.pos);
    154.            output.normal = -input[cpt].normal;
    155.            output.pack0 = input[cpt].pack0;
    156.            output.vlight = input[cpt].vlight;
    157.            TRANSFER_GEOM_TO_FRAGMENT(output);
    158.            outStream.Append( output );
    159.          }
    160.        
    161.          outStream.RestartStrip();
    162.        }
    163.      
    164.      
    165.        fixed4 frag (v2f_surf IN) : COLOR
    166.        {
    167.          Input surfIN;
    168.          surfIN.uv_MainTex = IN.pack0.xy;
    169.        
    170.          #ifdef UNITY_COMPILER_HLSL
    171.            SurfaceOutput o = (SurfaceOutput)0;
    172.          #else
    173.            SurfaceOutput o;
    174.          #endif
    175.        
    176.          o.Albedo  = 0.0;
    177.          o.Emission  = 0.0;
    178.          o.Specular  = 0.0;
    179.          o.Alpha  = 0.0;
    180.          o.Gloss  = 0.0;
    181.          o.Normal = IN.normal;
    182.        
    183.          surf (surfIN, o);
    184.          fixed atten = LIGHT_ATTENUATION(IN);
    185.          fixed4 c = 0;
    186.        
    187.          c = LightingLambert (o, _WorldSpaceLightPos0.xyz, atten);
    188.          c.rgb += o.Albedo * IN.vlight;
    189.          return c;
    190.        }
    191.      
    192.        ENDCG    
    193.      } // Pass ForwardBase
    194.    
    195.        
    196.      // Pass to render object as a shadow caster
    197.      Pass
    198.      {
    199.        Name "ShadowCaster"
    200.        Tags { "LightMode" = "ShadowCaster" }
    201.      
    202.        Fog {Mode Off}
    203.        ZWrite On ZTest LEqual Cull Off
    204.        Offset 1, 1
    205.        CGPROGRAM
    206.        #pragma target  5.0
    207.      
    208.        #pragma vertex      vert
    209.        #pragma geometry  geom
    210.        #pragma fragment    frag
    211.      
    212.        #pragma multi_compile_shadowcaster
    213.        #pragma only_renderers d3d11
    214.      
    215.        #include "UnityCG.cginc"
    216.        #include "HLSLSupport.cginc"
    217.      
    218.        float  _Explode;
    219.        struct v2f
    220.        {
    221.          V2F_SHADOW_CASTER;
    222.        };
    223.        v2f vert( appdata_base v )
    224.        {
    225.          v2f o;
    226.          //o.pos = v.vertex;
    227.          TRANSFER_SHADOW_CASTER(o)
    228.          o.pos = v.vertex;
    229.          return o;
    230.        }
    231.        // Geometry Shader
    232.        [maxvertexcount(12)]
    233.        void geom( triangle v2f input[3], inout TriangleStream<v2f> outStream )
    234.        {
    235.          v2f output;
    236.        
    237.          // Calculate the face normal
    238.          float3 faceEdgeA = input[1].pos - input[0].pos;
    239.          float3 faceEdgeB = input[2].pos - input[0].pos;
    240.          float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );
    241.          float3 ExplodeAmt = faceNormal*_Explode;
    242.        
    243.          // Calculate the face center
    244.          float3 centerPos = (input[0].pos.xyz + input[1].pos.xyz + input[2].pos.xyz)/3.0;
    245.          centerPos += faceNormal*_Explode;
    246.        
    247.          // Define for TRANSFER_GEOM_SHADOW_CASTER
    248.          float clamped;
    249.        
    250.          // Output the pyramid
    251.          for( int looper=0; looper<3; looper++ )
    252.          {
    253.            output.pos = input[looper].pos + float4(ExplodeAmt,0);
    254.            TRANSFER_GEOM_SHADOW_CASTER(output)
    255.          
    256.            output.pos = input[looper].pos + float4(ExplodeAmt,0);    
    257.            output.pos = mul(UNITY_MATRIX_MVP, output.pos);          
    258.            outStream.Append( output );
    259.          
    260.            uint iNext = looper+1;
    261.            if (iNext>2) iNext = 0;
    262.          
    263.            output.pos = input[iNext].pos + float4(ExplodeAmt,0);
    264.            TRANSFER_GEOM_SHADOW_CASTER(output)
    265.          
    266.            output.pos = input[iNext].pos + float4(ExplodeAmt,0);
    267.            output.pos = mul(UNITY_MATRIX_MVP, output.pos);
    268.            outStream.Append( output );
    269.          
    270.            output.pos = float4(centerPos,1) + float4(ExplodeAmt,0);
    271.            TRANSFER_GEOM_SHADOW_CASTER(output)
    272.          
    273.            output.pos = float4(centerPos,1) + float4(ExplodeAmt,0);
    274.            output.pos = mul(UNITY_MATRIX_MVP, output.pos);        
    275.            outStream.Append( output );
    276.          
    277.            outStream.RestartStrip();
    278.          }
    279.        
    280.          for(int cpt=2; cpt>=0; cpt-- )
    281.          {
    282.            output.pos = input[cpt].pos + float4(ExplodeAmt,0);
    283.            TRANSFER_GEOM_SHADOW_CASTER(output)
    284.          
    285.            output.pos = input[cpt].pos + float4(ExplodeAmt,0);
    286.            output.pos = mul(UNITY_MATRIX_MVP, output.pos);        
    287.            outStream.Append( output );
    288.          }
    289.        
    290.          outStream.RestartStrip();
    291.        }
    292.      
    293.      
    294.        float4 frag( v2f i ) : COLOR
    295.        {
    296.          SHADOW_CASTER_FRAGMENT(i)
    297.        }
    298.        ENDCG
    299.      }
    300.  
    301.      // Pass to render object as a shadow collector
    302.      Pass
    303.      {
    304.        Name "ShadowCollector"
    305.        Tags { "LightMode" = "ShadowCollector" }
    306.      
    307.        Fog {Mode Off}
    308.        ZWrite On ZTest LEqual
    309.        CGPROGRAM
    310.        #pragma target  5.0
    311.      
    312.        #pragma vertex      vert
    313.        #pragma geometry  geom
    314.        #pragma fragment    frag
    315.      
    316.        #pragma multi_compile_shadowcollector
    317.        #pragma only_renderers d3d11
    318.      
    319.        #define SHADOW_COLLECTOR_PASS
    320.      
    321.        #include "UnityCG.cginc"
    322.        #include "HLSLSupport.cginc"
    323.      
    324.        float  _Explode;
    325.      
    326.        struct appdata
    327.        {
    328.          float4 vertex : POSITION;
    329.        };
    330.        struct v2f
    331.        {
    332.          V2F_SHADOW_COLLECTOR;
    333.        };
    334.    
    335.        v2f vert (appdata v)
    336.        {
    337.          v2f o;
    338.          TRANSFER_SHADOW_COLLECTOR(o)
    339.          o.pos = v.vertex;
    340.          return o;
    341.        }
    342.      
    343.        // Geometry Shader
    344.        [maxvertexcount(12)]
    345.        void geom( triangle v2f input[3], inout TriangleStream<v2f> outStream )
    346.        {
    347.          v2f output;
    348.        
    349.          // Calculate the face normal
    350.          float3 faceEdgeA = input[1].pos - input[0].pos;
    351.          float3 faceEdgeB = input[2].pos - input[0].pos;
    352.          float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );
    353.          float3 ExplodeAmt = faceNormal*_Explode;
    354.        
    355.          // Calculate the face center
    356.          float3 centerPos = (input[0].pos.xyz + input[1].pos.xyz + input[2].pos.xyz)/3.0;
    357.          centerPos += faceNormal*_Explode;
    358.        
    359.          // Define for TRANSFER_GEOM_SHADOW_CASTER
    360.          float    clamped;
    361.          float4    vert;
    362.          float4    wpos;
    363.        
    364.          // Output the pyramid
    365.          for( int looper=0; looper<3; looper++ )
    366.          {
    367.            vert = input[looper].pos + float4(ExplodeAmt,0);
    368.            TRANSFER_GEOM_SHADOW_COLLECTOR(output, vert)          
    369.            outStream.Append( output );
    370.          
    371.            uint iNext = looper+1;
    372.            if (iNext>2) iNext = 0;
    373.          
    374.            vert = input[iNext].pos + float4(ExplodeAmt,0);
    375.            TRANSFER_GEOM_SHADOW_COLLECTOR(output, vert)
    376.            outStream.Append( output );
    377.          
    378.            vert = float4(centerPos,1) + float4(ExplodeAmt,0);
    379.            TRANSFER_GEOM_SHADOW_COLLECTOR(output, vert)      
    380.            outStream.Append( output );
    381.          
    382.            outStream.RestartStrip();
    383.          }
    384.        
    385.          for(int cpt=2; cpt>=0; cpt-- )
    386.          {
    387.            vert = input[cpt].pos + float4(ExplodeAmt,0);
    388.            TRANSFER_GEOM_SHADOW_COLLECTOR(output, vert)        
    389.            outStream.Append( output );
    390.          }
    391.        
    392.          outStream.RestartStrip();
    393.        }
    394.      
    395.        fixed4 frag (v2f i) : COLOR
    396.        {
    397.          SHADOW_COLLECTOR_FRAGMENT(i)
    398.        }
    399.        ENDCG
    400.      }
    401.    } // subshader
    402.    // FallBack "Diffuse" // Use for testing shadows via Normal-VertexLit.shader fallback.
    403.  
    404.    FallBack Off
    405. }

    The AutoLight.cginc replacement


    Code (CSharp):
    1. #ifndef AUTOLIGHT_INCLUDED
    2. #define AUTOLIGHT_INCLUDED
    3.  
    4. #include "HLSLSupport.cginc"
    5.  
    6. // Unity 4.3.4
    7. // 2014.06.09 - Amended to support Geometry Shader
    8.  
    9.  
    10. // ------------ Shadow helpers --------
    11.  
    12.  
    13. // ---- Screen space shadows
    14. #if defined (SHADOWS_SCREEN)
    15.  
    16. uniform float4 _ShadowOffsets[4];
    17.  
    18. #if defined(SHADOWS_NATIVE)
    19. UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture);
    20. #else
    21. uniform sampler2D _ShadowMapTexture;
    22. #endif
    23.  
    24. #define SHADOW_COORDS(idx1) float4 _ShadowCoord : TEXCOORD##idx1;
    25.  
    26. #if (defined(SHADER_API_GLES) || defined(SHADER_API_GLES3)) && defined(SHADER_API_MOBILE)
    27. #define TRANSFER_SHADOW(a)      a._ShadowCoord = mul( unity_World2Shadow[0], mul( _Object2World, v.vertex ) );
    28. // GEOMETRY SHADER
    29. #define TRANSFER_GEOM_SHADOW(a) a._ShadowCoord = mul( unity_World2Shadow[0], mul( _Object2World, a.pos ) );
    30.  
    31. inline fixed unitySampleShadow (float4 shadowCoord)
    32. {
    33.     #if defined(SHADOWS_NATIVE)
    34.  
    35.     fixed shadow = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, shadowCoord.xyz);
    36.     shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r);
    37.     return shadow;
    38.  
    39.     #else
    40.  
    41.     float dist = tex2Dproj( _ShadowMapTexture, UNITY_PROJ_COORD(shadowCoord) ).x;
    42.  
    43.     // tegra is confused if we use _LightShadowData.x directly
    44.     // with "ambiguous overloaded function reference max(mediump float, float)"
    45.     half lightShadowDataX = _LightShadowData.x;
    46.     return max(dist > (shadowCoord.z/shadowCoord.w), lightShadowDataX);
    47.  
    48.     #endif
    49. }
    50.  
    51. #else // !((defined(SHADER_API_GLES) || defined(SHADER_API_GLES3)) && defined(SHADER_API_MOBILE))
    52.  
    53. #define TRANSFER_SHADOW(a) a._ShadowCoord = ComputeScreenPos(a.pos);
    54. // GEOMETRY SHADER: WHAT TO DO HERE????
    55. #define TRANSFER_GEOM_SHADOW(a) a._ShadowCoord = ComputeScreenPos(a.pos);
    56.  
    57. inline fixed unitySampleShadow (float4 shadowCoord)
    58. {
    59.     fixed shadow = tex2Dproj( _ShadowMapTexture, UNITY_PROJ_COORD(shadowCoord) ).r;
    60.     return shadow;
    61. }
    62.  
    63. #endif
    64.  
    65. #define SHADOW_ATTENUATION(a) unitySampleShadow(a._ShadowCoord)
    66.  
    67. #endif
    68.  
    69.  
    70. // ---- Depth map shadows
    71.  
    72. #if defined (SHADOWS_DEPTH) && defined (SPOT)
    73.  
    74. #if !defined(SHADOWMAPSAMPLER_DEFINED)
    75. UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture);
    76. #endif
    77. #if defined (SHADOWS_SOFT)
    78. uniform float4 _ShadowOffsets[4];
    79. #endif
    80.  
    81. inline fixed unitySampleShadow (float4 shadowCoord)
    82. {
    83.     #if defined (SHADOWS_SOFT)
    84.  
    85.     // 4-tap shadows
    86.  
    87.     float3 coord = shadowCoord.xyz / shadowCoord.w;
    88.     #if defined (SHADOWS_NATIVE)
    89.     half4 shadows;
    90.     shadows.x = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[0]);
    91.     shadows.y = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[1]);
    92.     shadows.z = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[2]);
    93.     shadows.w = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[3]);
    94.     shadows = _LightShadowData.rrrr + shadows * (1-_LightShadowData.rrrr);
    95.     #else
    96.     float4 shadowVals;
    97.     shadowVals.x = UNITY_SAMPLE_DEPTH (tex2D( _ShadowMapTexture, coord + _ShadowOffsets[0].xy ));
    98.     shadowVals.y = UNITY_SAMPLE_DEPTH (tex2D( _ShadowMapTexture, coord + _ShadowOffsets[1].xy ));
    99.     shadowVals.z = UNITY_SAMPLE_DEPTH (tex2D( _ShadowMapTexture, coord + _ShadowOffsets[2].xy ));
    100.     shadowVals.w = UNITY_SAMPLE_DEPTH (tex2D( _ShadowMapTexture, coord + _ShadowOffsets[3].xy ));
    101.     half4 shadows = (shadowVals < coord.zzzz) ? _LightShadowData.rrrr : 1.0f;
    102.     #endif
    103.  
    104.     // average-4 PCF
    105.     half shadow = dot (shadows, 0.25f);
    106.  
    107.     #else
    108.  
    109.     // 1-tap shadows
    110.  
    111.     #if defined (SHADOWS_NATIVE)
    112.     half shadow = UNITY_SAMPLE_SHADOW_PROJ(_ShadowMapTexture, shadowCoord);
    113.     shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r);
    114.     #else
    115.     half shadow = UNITY_SAMPLE_DEPTH(tex2Dproj (_ShadowMapTexture, UNITY_PROJ_COORD(shadowCoord))) < (shadowCoord.z / shadowCoord.w) ? _LightShadowData.r : 1.0;
    116.     #endif
    117.  
    118.     #endif
    119.  
    120.     return shadow;
    121. }
    122. #define SHADOW_COORDS(idx1) float4 _ShadowCoord : TEXCOORD##idx1;
    123. #define TRANSFER_SHADOW(a) a._ShadowCoord = mul (unity_World2Shadow[0], mul(_Object2World,v.vertex));
    124. #define SHADOW_ATTENUATION(a) unitySampleShadow(a._ShadowCoord)
    125. // GEOMETRY SHADER:
    126. #define TRANSFER_GEOM_SHADOW(a) a._ShadowCoord = mul (unity_World2Shadow[0], mul(_Object2World, a.pos));
    127.  
    128. #endif
    129.  
    130.  
    131. // ---- Point light shadows
    132.  
    133. #if defined (SHADOWS_CUBE)
    134.  
    135. uniform samplerCUBE _ShadowMapTexture;
    136. inline float SampleCubeDistance (float3 vec)
    137. {
    138.     float4 packDist = texCUBE (_ShadowMapTexture, vec);
    139.     return DecodeFloatRGBA( packDist );
    140. }
    141. inline float unityCubeShadow (float3 vec)
    142. {
    143.     float mydist = length(vec) * _LightPositionRange.w;
    144.     mydist *= 0.97; // bias
    145.  
    146.     #if defined (SHADOWS_SOFT)
    147.     float z = 1.0/128.0;
    148.     float4 shadowVals;
    149.     shadowVals.x = SampleCubeDistance (vec+float3( z, z, z));
    150.     shadowVals.y = SampleCubeDistance (vec+float3(-z,-z, z));
    151.     shadowVals.z = SampleCubeDistance (vec+float3(-z, z,-z));
    152.     shadowVals.w = SampleCubeDistance (vec+float3( z,-z,-z));
    153.     half4 shadows = (shadowVals < mydist.xxxx) ? _LightShadowData.rrrr : 1.0f;
    154.     return dot(shadows,0.25);
    155.     #else
    156.     float dist = SampleCubeDistance (vec);
    157.     return dist < mydist ? _LightShadowData.r : 1.0;
    158.     #endif
    159. }
    160. #define SHADOW_COORDS(idx1) float3 _ShadowCoord : TEXCOORD##idx1;
    161. #define TRANSFER_SHADOW(a) a._ShadowCoord = mul(_Object2World, v.vertex).xyz - _LightPositionRange.xyz;
    162. #define SHADOW_ATTENUATION(a) unityCubeShadow(a._ShadowCoord)
    163. // GEOMETRY SHADER:
    164. #define TRANSFER_GEOM_SHADOW(a) a._ShadowCoord = mul(_Object2World, a.pos).xyz - _LightPositionRange.xyz;
    165.  
    166. #endif
    167.  
    168.  
    169.  
    170. // ---- Shadows off
    171. #if !defined (SHADOWS_SCREEN) && !defined (SHADOWS_DEPTH) && !defined (SHADOWS_CUBE)
    172.  
    173. #define SHADOW_COORDS(idx1)
    174. #define TRANSFER_SHADOW(a)
    175. #define SHADOW_ATTENUATION(a) 1.0
    176. // GEOMETRY SHADER:
    177. #define TRANSFER_GEOM_SHADOW(a)
    178.  
    179. #endif
    180.  
    181.  
    182.  
    183. // ------------ Light helpers --------
    184.  
    185. #ifdef POINT
    186. #define LIGHTING_COORDS(idx1,idx2) float3 _LightCoord : TEXCOORD##idx1; SHADOW_COORDS(idx2)
    187. uniform sampler2D _LightTexture0;
    188. uniform float4x4 _LightMatrix0;
    189. #define TRANSFER_VERTEX_TO_FRAGMENT(a) a._LightCoord = mul(_LightMatrix0, mul(_Object2World, v.vertex)).xyz; TRANSFER_SHADOW(a)
    190. #define LIGHT_ATTENUATION(a)    (tex2D(_LightTexture0, dot(a._LightCoord,a._LightCoord).rr).UNITY_ATTEN_CHANNEL * SHADOW_ATTENUATION(a))
    191. // GEOMETRY SHADER:
    192. #define TRANSFER_GEOM_TO_FRAGMENT(a)   a._LightCoord = mul(_LightMatrix0, mul(_Object2World, a.pos)).xyz; TRANSFER_GEOM_SHADOW(a)
    193. #endif
    194.  
    195. #ifdef SPOT
    196. #define LIGHTING_COORDS(idx1,idx2) float4 _LightCoord : TEXCOORD##idx1; SHADOW_COORDS(idx2)
    197. uniform sampler2D _LightTexture0;
    198. uniform float4x4 _LightMatrix0;
    199. uniform sampler2D _LightTextureB0;
    200. #define TRANSFER_VERTEX_TO_FRAGMENT(a) a._LightCoord = mul(_LightMatrix0, mul(_Object2World, v.vertex)); TRANSFER_SHADOW(a)
    201. // GEOMETRY SHADER:
    202. #define TRANSFER_GEOM_TO_FRAGMENT(a)   a._LightCoord = mul(_LightMatrix0, mul(_Object2World, a.pos)); TRANSFER_GEOM_SHADOW(a)
    203.  
    204. inline fixed UnitySpotCookie(float4 LightCoord)
    205. {
    206.     return tex2D(_LightTexture0, LightCoord.xy / LightCoord.w + 0.5).w;
    207. }
    208. inline fixed UnitySpotAttenuate(float3 LightCoord)
    209. {
    210.     return tex2D(_LightTextureB0, dot(LightCoord, LightCoord).xx).UNITY_ATTEN_CHANNEL;
    211. }
    212. #define LIGHT_ATTENUATION(a)    ( (a._LightCoord.z > 0) * UnitySpotCookie(a._LightCoord) * UnitySpotAttenuate(a._LightCoord.xyz) * SHADOW_ATTENUATION(a) )
    213. #endif
    214.  
    215.  
    216. #ifdef DIRECTIONAL
    217.     #define LIGHTING_COORDS(idx1,idx2) SHADOW_COORDS(idx1)
    218.     #define TRANSFER_VERTEX_TO_FRAGMENT(a) TRANSFER_SHADOW(a)
    219.     #define LIGHT_ATTENUATION(a)    SHADOW_ATTENUATION(a)
    220.     // GEOMETRY SHADER:
    221.     #define TRANSFER_GEOM_TO_FRAGMENT(a) TRANSFER_GEOM_SHADOW(a)
    222. #endif
    223.  
    224.  
    225. #ifdef POINT_COOKIE
    226. #define LIGHTING_COORDS(idx1,idx2) float3 _LightCoord : TEXCOORD##idx1; SHADOW_COORDS(idx2)
    227. uniform samplerCUBE _LightTexture0;
    228. uniform float4x4 _LightMatrix0;
    229. uniform sampler2D _LightTextureB0;
    230. #define TRANSFER_VERTEX_TO_FRAGMENT(a) a._LightCoord = mul(_LightMatrix0, mul(_Object2World, v.vertex)).xyz; TRANSFER_SHADOW(a)
    231. // GEOMETRY SHADER:
    232. #define TRANSFER_GEOM_TO_FRAGMENT(a)   a._LightCoord = mul(_LightMatrix0, mul(_Object2World, a.pos)).xyz; TRANSFER_GEOM_SHADOW(a)
    233.  
    234. #define LIGHT_ATTENUATION(a)    (tex2D(_LightTextureB0, dot(a._LightCoord,a._LightCoord).rr).UNITY_ATTEN_CHANNEL * texCUBE(_LightTexture0, a._LightCoord).w * SHADOW_ATTENUATION(a))
    235. #endif
    236.  
    237. #ifdef DIRECTIONAL_COOKIE
    238. #define LIGHTING_COORDS(idx1,idx2) float2 _LightCoord : TEXCOORD##idx1; SHADOW_COORDS(idx2)
    239. uniform sampler2D _LightTexture0;
    240. uniform float4x4 _LightMatrix0;
    241. #define TRANSFER_VERTEX_TO_FRAGMENT(a) a._LightCoord = mul(_LightMatrix0, mul(_Object2World, v.vertex)).xy; TRANSFER_SHADOW(a)
    242. // GEOMETRY SHADER:
    243. #define TRANSFER_GEOM_TO_FRAGMENT(a)   a._LightCoord = mul(_LightMatrix0, mul(_Object2World, a.pos)).xy; TRANSFER_GEOM_SHADOW(a)
    244.  
    245. #define LIGHT_ATTENUATION(a)    (tex2D(_LightTexture0, a._LightCoord).w * SHADOW_ATTENUATION(a))
    246. #endif
    247.  
    248.  
    249. #endif
    250.  

    The UnityCG.cginc replacement

    Code (CSharp):
    1. // Unity 4.3.4
    2. // 2014.06.09 - Amended to support Geometry Shader
    3.  
    4. #ifndef UNITY_CG_INCLUDED
    5. #define UNITY_CG_INCLUDED
    6.  
    7. #include "UnityShaderVariables.cginc"
    8.  
    9.  
    10.  
    11.  
    12. #if SHADER_API_FLASH
    13. uniform float4 unity_NPOTScale;
    14. #endif
    15. #if defined(SHADER_API_PS3)
    16. #    define UNITY_SAMPLE_DEPTH(value) (dot((value).wxy, float3(0.996093809371817670572857294849, 0.0038909914428586627756752238080039, 1.5199185323666651467481343000015e-5)))
    17. #elif defined(SHADER_API_FLASH)
    18. #    define UNITY_SAMPLE_DEPTH(value) (DecodeFloatRGBA(value))
    19. #else
    20. #    define UNITY_SAMPLE_DEPTH(value) (value).r
    21. #endif
    22.  
    23. uniform fixed4 unity_ColorSpaceGrey;
    24.  
    25. // -------------------------------------------------------------------
    26. //  helper functions and macros used in many standard shaders
    27.  
    28.  
    29. #if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE) || defined (POINT) || defined (SPOT) || defined (POINT_NOATT) || defined (POINT_COOKIE)
    30. #define USING_LIGHT_MULTI_COMPILE
    31. #endif
    32.  
    33. #define SCALED_NORMAL (v.normal * unity_Scale.w)
    34.  
    35. struct appdata_base {
    36.     float4 vertex : POSITION;
    37.     float3 normal : NORMAL;
    38.     float4 texcoord : TEXCOORD0;
    39. };
    40.  
    41. struct appdata_tan {
    42.     float4 vertex : POSITION;
    43.     float4 tangent : TANGENT;
    44.     float3 normal : NORMAL;
    45.     float4 texcoord : TEXCOORD0;
    46. };
    47.  
    48. struct appdata_full {
    49.     float4 vertex : POSITION;
    50.     float4 tangent : TANGENT;
    51.     float3 normal : NORMAL;
    52.     float4 texcoord : TEXCOORD0;
    53.     float4 texcoord1 : TEXCOORD1;
    54.     fixed4 color : COLOR;
    55. #if defined(SHADER_API_XBOX360)
    56.     half4 texcoord2 : TEXCOORD2;
    57.     half4 texcoord3 : TEXCOORD3;
    58.     half4 texcoord4 : TEXCOORD4;
    59.     half4 texcoord5 : TEXCOORD5;
    60. #endif
    61. };
    62.  
    63. // Computes world space light direction
    64. inline float3 WorldSpaceLightDir( in float4 v )
    65. {
    66.     float3 worldPos = mul(_Object2World, v).xyz;
    67.     #ifndef USING_LIGHT_MULTI_COMPILE
    68.         return _WorldSpaceLightPos0.xyz - worldPos * _WorldSpaceLightPos0.w;
    69.     #else
    70.         #ifndef USING_DIRECTIONAL_LIGHT
    71.         return _WorldSpaceLightPos0.xyz - worldPos;
    72.         #else
    73.         return _WorldSpaceLightPos0.xyz;
    74.         #endif
    75.     #endif
    76. }
    77.  
    78. // Computes object space light direction
    79. inline float3 ObjSpaceLightDir( in float4 v )
    80. {
    81.     float3 objSpaceLightPos = mul(_World2Object, _WorldSpaceLightPos0).xyz;
    82.     #ifndef USING_LIGHT_MULTI_COMPILE
    83.         return objSpaceLightPos.xyz - v.xyz * _WorldSpaceLightPos0.w;
    84.     #else
    85.         #ifndef USING_DIRECTIONAL_LIGHT
    86.         return objSpaceLightPos.xyz * unity_Scale.w - v.xyz;
    87.         #else
    88.         return objSpaceLightPos.xyz;
    89.         #endif
    90.     #endif
    91. }
    92.  
    93. // Computes world space view direction
    94. inline float3 WorldSpaceViewDir( in float4 v )
    95. {
    96.     return _WorldSpaceCameraPos.xyz - mul(_Object2World, v).xyz;
    97. }
    98.  
    99. // Computes object space view direction
    100. inline float3 ObjSpaceViewDir( in float4 v )
    101. {
    102.     float3 objSpaceCameraPos = mul(_World2Object, float4(_WorldSpaceCameraPos.xyz, 1)).xyz * unity_Scale.w;
    103.     return objSpaceCameraPos - v.xyz;
    104. }
    105.  
    106. // Declares 3x3 matrix 'rotation', filled with tangent space basis
    107. #define TANGENT_SPACE_ROTATION \
    108.     float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w; \
    109.     float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal )
    110.  
    111.  
    112.  
    113.  
    114. float3 Shade4PointLights (
    115.     float4 lightPosX, float4 lightPosY, float4 lightPosZ,
    116.     float3 lightColor0, float3 lightColor1, float3 lightColor2, float3 lightColor3,
    117.     float4 lightAttenSq,
    118.     float3 pos, float3 normal)
    119. {
    120.     // to light vectors
    121.     float4 toLightX = lightPosX - pos.x;
    122.     float4 toLightY = lightPosY - pos.y;
    123.     float4 toLightZ = lightPosZ - pos.z;
    124.     // squared lengths
    125.     float4 lengthSq = 0;
    126.     lengthSq += toLightX * toLightX;
    127.     lengthSq += toLightY * toLightY;
    128.     lengthSq += toLightZ * toLightZ;
    129.     // NdotL
    130.     float4 ndotl = 0;
    131.     ndotl += toLightX * normal.x;
    132.     ndotl += toLightY * normal.y;
    133.     ndotl += toLightZ * normal.z;
    134.     // correct NdotL
    135.     float4 corr = rsqrt(lengthSq);
    136.     ndotl = max (float4(0,0,0,0), ndotl * corr);
    137.     // attenuation
    138.     float4 atten = 1.0 / (1.0 + lengthSq * lightAttenSq);
    139.     float4 diff = ndotl * atten;
    140.     // final color
    141.     float3 col = 0;
    142.     col += lightColor0 * diff.x;
    143.     col += lightColor1 * diff.y;
    144.     col += lightColor2 * diff.z;
    145.     col += lightColor3 * diff.w;
    146.     return col;
    147. }
    148.  
    149.  
    150. float3 ShadeVertexLights (float4 vertex, float3 normal)
    151. {
    152.     float3 viewpos = mul (UNITY_MATRIX_MV, vertex).xyz;
    153.     float3 viewN = mul ((float3x3)UNITY_MATRIX_IT_MV, normal);
    154.     float3 lightColor = UNITY_LIGHTMODEL_AMBIENT.xyz;
    155.     for (int i = 0; i < 4; i++) {
    156.         float3 toLight = unity_LightPosition[i].xyz - viewpos.xyz * unity_LightPosition[i].w;
    157.         float lengthSq = dot(toLight, toLight);
    158.         float atten = 1.0 / (1.0 + lengthSq * unity_LightAtten[i].z);
    159.         float diff = max (0, dot (viewN, normalize(toLight)));
    160.         lightColor += unity_LightColor[i].rgb * (diff * atten);
    161.     }
    162.     return lightColor;
    163. }
    164.  
    165.  
    166. // normal should be normalized, w=1.0
    167. half3 ShadeSH9 (half4 normal)
    168. {
    169.     half3 x1, x2, x3;
    170.  
    171.     // Linear + constant polynomial terms
    172.     x1.r = dot(unity_SHAr,normal);
    173.     x1.g = dot(unity_SHAg,normal);
    174.     x1.b = dot(unity_SHAb,normal);
    175.  
    176.     // 4 of the quadratic polynomials
    177.     half4 vB = normal.xyzz * normal.yzzx;
    178.     x2.r = dot(unity_SHBr,vB);
    179.     x2.g = dot(unity_SHBg,vB);
    180.     x2.b = dot(unity_SHBb,vB);
    181.  
    182.     // Final quadratic polynomial
    183.     float vC = normal.x*normal.x - normal.y*normal.y;
    184.     x3 = unity_SHC.rgb * vC;
    185.     return x1 + x2 + x3;
    186. }
    187.  
    188.  
    189. // Transforms 2D UV by scale/bias property
    190. #define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
    191. // Transforms 4D UV by a texture matrix (use only if you know exactly which matrix you need)
    192. #define TRANSFORM_UV(idx) mul (UNITY_MATRIX_TEXTURE##idx, v.texcoord).xy
    193.  
    194.  
    195.  
    196. struct v2f_vertex_lit {
    197.     float2 uv    : TEXCOORD0;
    198.     fixed4 diff    : COLOR0;
    199.     fixed4 spec    : COLOR1;
    200. };
    201.  
    202. inline fixed4 VertexLight( v2f_vertex_lit i, sampler2D mainTex )
    203. {
    204.     fixed4 texcol = tex2D( mainTex, i.uv );
    205.     fixed4 c;
    206.     c.xyz = ( texcol.xyz * i.diff.xyz + i.spec.xyz * texcol.a ) * 2;
    207.     c.w = texcol.w * i.diff.w;
    208.     return c;
    209. }
    210.  
    211.  
    212. // Calculates UV offset for parallax bump mapping
    213. inline float2 ParallaxOffset( half h, half height, half3 viewDir )
    214. {
    215.     h = h * height - height/2.0;
    216.     float3 v = normalize(viewDir);
    217.     v.z += 0.42;
    218.     return h * (v.xy / v.z);
    219. }
    220.  
    221.  
    222. // Converts color to luminance (grayscale)
    223. inline fixed Luminance( fixed3 c )
    224. {
    225.     return dot( c, fixed3(0.22, 0.707, 0.071) );
    226. }
    227.  
    228. // Decodes lightmaps:
    229. // - doubleLDR encoded on GLES
    230. // - RGBM encoded with range [0;8] on other platforms using surface shaders
    231. inline fixed3 DecodeLightmap( fixed4 color )
    232. {
    233. #if (defined(SHADER_API_GLES) || defined(SHADER_API_GLES3)) && defined(SHADER_API_MOBILE)
    234.     return 2.0 * color.rgb;
    235. #else
    236.     // potentially faster to do the scalar multiplication
    237.     // in parenthesis for scalar GPUs
    238.     return (8.0 * color.a) * color.rgb;
    239. #endif
    240. }
    241.  
    242.  
    243. // Helpers used in image effects. Most image effects use the same
    244. // minimal vertex shader (vert_img).
    245.  
    246. struct appdata_img {
    247.     float4 vertex : POSITION;
    248.     half2 texcoord : TEXCOORD0;
    249. };
    250. struct v2f_img {
    251.     float4 pos : SV_POSITION;
    252.     half2 uv : TEXCOORD0;
    253. };
    254.  
    255. float2 MultiplyUV (float4x4 mat, float2 inUV) {
    256.     float4 temp = float4 (inUV.x, inUV.y, 0, 0);
    257.     temp = mul (mat, temp);
    258.     return temp.xy;
    259. }
    260.  
    261. v2f_img vert_img( appdata_img v )
    262. {
    263.     v2f_img o;
    264.     o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    265.     o.uv = MultiplyUV( UNITY_MATRIX_TEXTURE0, v.texcoord );
    266.     return o;
    267. }
    268.  
    269.  
    270. // Encoding/decoding [0..1) floats into 8 bit/channel RGBA. Note that 1.0 will not be encoded properly.
    271. inline float4 EncodeFloatRGBA( float v )
    272. {
    273.     float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 160581375.0);
    274.     float kEncodeBit = 1.0/255.0;
    275.     float4 enc = kEncodeMul * v;
    276.     enc = frac (enc);
    277.     enc -= enc.yzww * kEncodeBit;
    278.     return enc;
    279. }
    280. inline float DecodeFloatRGBA( float4 enc )
    281. {
    282.     float4 kDecodeDot = float4(1.0, 1/255.0, 1/65025.0, 1/160581375.0);
    283.     return dot( enc, kDecodeDot );
    284. }
    285.  
    286. // Encoding/decoding [0..1) floats into 8 bit/channel RG. Note that 1.0 will not be encoded properly.
    287. inline float2 EncodeFloatRG( float v )
    288. {
    289.     float2 kEncodeMul = float2(1.0, 255.0);
    290.     float kEncodeBit = 1.0/255.0;
    291.     float2 enc = kEncodeMul * v;
    292.     enc = frac (enc);
    293.     enc.x -= enc.y * kEncodeBit;
    294.     return enc;
    295. }
    296. inline float DecodeFloatRG( float2 enc )
    297. {
    298.     float2 kDecodeDot = float2(1.0, 1/255.0);
    299.     return dot( enc, kDecodeDot );
    300. }
    301.  
    302.  
    303. // Encoding/decoding view space normals into 2D 0..1 vector
    304. inline float2 EncodeViewNormalStereo( float3 n )
    305. {
    306.     float kScale = 1.7777;
    307.     float2 enc;
    308.     enc = n.xy / (n.z+1);
    309.     enc /= kScale;
    310.     enc = enc*0.5+0.5;
    311.     return enc;
    312. }
    313. inline float3 DecodeViewNormalStereo( float4 enc4 )
    314. {
    315.     float kScale = 1.7777;
    316.     float3 nn = enc4.xyz*float3(2*kScale,2*kScale,0) + float3(-kScale,-kScale,1);
    317.     float g = 2.0 / dot(nn.xyz,nn.xyz);
    318.     float3 n;
    319.     n.xy = g*nn.xy;
    320.     n.z = g-1;
    321.     return n;
    322. }
    323.  
    324. inline float4 EncodeDepthNormal( float depth, float3 normal )
    325. {
    326.     float4 enc;
    327.     enc.xy = EncodeViewNormalStereo (normal);
    328.     enc.zw = EncodeFloatRG (depth);
    329.     return enc;
    330. }
    331.  
    332. inline void DecodeDepthNormal( float4 enc, out float depth, out float3 normal )
    333. {
    334.     depth = DecodeFloatRG (enc.zw);
    335.     normal = DecodeViewNormalStereo (enc);
    336. }
    337.  
    338. inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal)
    339. {
    340.     fixed3 normal;
    341.     normal.xy = packednormal.wy * 2 - 1;
    342. #if defined(SHADER_API_FLASH)
    343.     // Flash does not have efficient saturate(), and dot() seems to require an extra register.
    344.     normal.z = sqrt(1 - normal.x*normal.x - normal.y*normal.y);
    345. #else
    346.     normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
    347. #endif
    348.     return normal;
    349. }
    350.  
    351. inline fixed3 UnpackNormal(fixed4 packednormal)
    352. {
    353. #if (defined(SHADER_API_GLES) || defined(SHADER_API_GLES3)) && defined(SHADER_API_MOBILE)
    354.     return packednormal.xyz * 2 - 1;
    355. #else
    356.     return UnpackNormalDXT5nm(packednormal);
    357. #endif
    358. }
    359.  
    360.  
    361. // Z buffer to linear 0..1 depth (0 at eye, 1 at far plane)
    362. inline float Linear01Depth( float z )
    363. {
    364.     return 1.0 / (_ZBufferParams.x * z + _ZBufferParams.y);
    365. }
    366. // Z buffer to linear depth
    367. inline float LinearEyeDepth( float z )
    368. {
    369.     return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w);
    370. }
    371.  
    372.  
    373. // Depth render texture helpers
    374. #if defined(UNITY_MIGHT_NOT_HAVE_DEPTH_TEXTURE)
    375.     #define UNITY_TRANSFER_DEPTH(oo) oo = o.pos.zw
    376.     #if SHADER_API_FLASH
    377.     #define UNITY_OUTPUT_DEPTH(i) return EncodeFloatRGBA(i.x/i.y)
    378.     #else
    379.     #define UNITY_OUTPUT_DEPTH(i) return i.x/i.y
    380.     #endif
    381. #else
    382.     #define UNITY_TRANSFER_DEPTH(oo)
    383.     #define UNITY_OUTPUT_DEPTH(i) return 0
    384. #endif
    385. #define DECODE_EYEDEPTH(i) LinearEyeDepth(i)
    386. #define COMPUTE_EYEDEPTH(o) o = -mul( UNITY_MATRIX_MV, v.vertex ).z
    387. #define COMPUTE_DEPTH_01 -(mul( UNITY_MATRIX_MV, v.vertex ).z * _ProjectionParams.w)
    388. #define COMPUTE_VIEW_NORMAL mul((float3x3)UNITY_MATRIX_IT_MV, v.normal)
    389.  
    390.  
    391. // Projected screen position helpers
    392. #define V2F_SCREEN_TYPE float4
    393. inline float4 ComputeScreenPos (float4 pos) {
    394.     float4 o = pos * 0.5f;
    395.     #if defined(UNITY_HALF_TEXEL_OFFSET)
    396.     o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w * _ScreenParams.zw;
    397.     #else
    398.     o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;
    399.     #endif
    400.  
    401.     #if defined(SHADER_API_FLASH)
    402.     o.xy *= unity_NPOTScale.xy;
    403.     #endif
    404.  
    405.     o.zw = pos.zw;
    406.     return o;
    407. }
    408.  
    409. inline float4 ComputeGrabScreenPos (float4 pos) {
    410.     #if UNITY_UV_STARTS_AT_TOP
    411.     float scale = -1.0;
    412.     #else
    413.     float scale = 1.0;
    414.     #endif
    415.     float4 o = pos * 0.5f;
    416.     o.xy = float2(o.x, o.y*scale) + o.w;
    417.     o.zw = pos.zw;
    418.     return o;
    419. }
    420.  
    421. // snaps post-transformed position to screen pixels
    422. inline float4 UnityPixelSnap (float4 pos)
    423. {
    424.     float2 hpc = _ScreenParams.xy * 0.5;
    425.     #ifdef UNITY_HALF_TEXEL_OFFSET
    426.     float2 hpcO = float2(-0.5,0.5);
    427.     #else
    428.     float2 hpcO = float2(0,0);
    429.     #endif  
    430.     float2 pixelPos = floor ((pos.xy / pos.w) * hpc + 0.5);
    431.     pos.xy = (pixelPos + hpcO) / hpc * pos.w;
    432.     return pos;
    433. }
    434.  
    435.  
    436. inline float2 TransformViewToProjection (float2 v) {
    437.     return float2(v.x*UNITY_MATRIX_P[0][0], v.y*UNITY_MATRIX_P[1][1]);
    438. }
    439.  
    440. inline float3 TransformViewToProjection (float3 v) {
    441.     return float3(v.x*UNITY_MATRIX_P[0][0], v.y*UNITY_MATRIX_P[1][1], v.z*UNITY_MATRIX_P[2][2]);
    442. }
    443.  
    444.  
    445.  
    446.  
    447. // Shadow caster pass helpers
    448.  
    449.  
    450. #ifdef SHADOWS_CUBE
    451.     #define V2F_SHADOW_CASTER float4 pos : SV_POSITION; float3 vec : TEXCOORD0
    452.     #define TRANSFER_SHADOW_CASTER(o) o.vec = mul( _Object2World, v.vertex ).xyz - _LightPositionRange.xyz; o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    453.     #define SHADOW_CASTER_FRAGMENT(i) return EncodeFloatRGBA( min(length(i.vec) * _LightPositionRange.w, 0.999) );
    454.     #define TRANSFER_GEOM_SHADOW_CASTER(o) o.vec = mul( _Object2World, o.pos ).xyz - _LightPositionRange.xyz; o.pos = mul(UNITY_MATRIX_MVP, o.pos);
    455. #else
    456.     #if defined(UNITY_MIGHT_NOT_HAVE_DEPTH_TEXTURE)
    457.         #define V2F_SHADOW_CASTER float4 pos : SV_POSITION; float4 hpos : TEXCOORD0
    458.         #define TRANSFER_SHADOW_CASTER(o) o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.pos.z += unity_LightShadowBias.x; \
    459.         float clamped = max(o.pos.z, o.pos.w*UNITY_NEAR_CLIP_VALUE); o.pos.z = lerp(o.pos.z, clamped, unity_LightShadowBias.y); o.hpos = o.pos;
    460.         #define TRANSFER_GEOM_SHADOW_CASTER(o) o.pos = mul(UNITY_MATRIX_MVP, o.pos); o.pos.z += unity_LightShadowBias.x; \
    461.         clamped = max(o.pos.z, o.pos.w*UNITY_NEAR_CLIP_VALUE); o.pos.z = lerp(o.pos.z, clamped, unity_LightShadowBias.y); o.hpos = o.pos;
    462.     #else
    463.         #define V2F_SHADOW_CASTER float4 pos : SV_POSITION
    464.         #define TRANSFER_SHADOW_CASTER(o) o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.pos.z += unity_LightShadowBias.x; \
    465.         float clamped = max(o.pos.z, o.pos.w*UNITY_NEAR_CLIP_VALUE); o.pos.z = lerp(o.pos.z, clamped, unity_LightShadowBias.y);
    466.         #define TRANSFER_GEOM_SHADOW_CASTER(o) o.pos = mul(UNITY_MATRIX_MVP, o.pos); o.pos.z += unity_LightShadowBias.x; \
    467.         clamped = max(o.pos.z, o.pos.w*UNITY_NEAR_CLIP_VALUE); o.pos.z = lerp(o.pos.z, clamped, unity_LightShadowBias.y);
    468.     #endif
    469.     #define SHADOW_CASTER_FRAGMENT(i) UNITY_OUTPUT_DEPTH(i.hpos.zw);
    470. #endif
    471.  
    472. // Shadow collector pass helpers
    473. #ifdef SHADOW_COLLECTOR_PASS
    474.  
    475.  
    476. #if !defined(SHADOWMAPSAMPLER_DEFINED)
    477. UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture);
    478. #endif
    479.  
    480.  
    481. #define V2F_SHADOW_COLLECTOR float4 pos : SV_POSITION; float3 _ShadowCoord0 : TEXCOORD0; float3 _ShadowCoord1 : TEXCOORD1; float3 _ShadowCoord2 : TEXCOORD2; float3 _ShadowCoord3 : TEXCOORD3; float4 _WorldPosViewZ : TEXCOORD4
    482. #define TRANSFER_SHADOW_COLLECTOR(o)    \
    483.     o.pos = mul(UNITY_MATRIX_MVP, v.vertex); \
    484.     float4 wpos = mul(_Object2World, v.vertex); \
    485.     o._WorldPosViewZ.xyz = wpos; \
    486.     o._WorldPosViewZ.w = -mul( UNITY_MATRIX_MV, v.vertex ).z; \
    487.     o._ShadowCoord0 = mul(unity_World2Shadow[0], wpos).xyz; \
    488.     o._ShadowCoord1 = mul(unity_World2Shadow[1], wpos).xyz; \
    489.     o._ShadowCoord2 = mul(unity_World2Shadow[2], wpos).xyz; \
    490.     o._ShadowCoord3 = mul(unity_World2Shadow[3], wpos).xyz;
    491.  
    492. #define TRANSFER_GEOM_SHADOW_COLLECTOR(o, v)    \
    493.     o.pos = mul(UNITY_MATRIX_MVP, v); \
    494.     wpos = mul(_Object2World, v); \
    495.     o._WorldPosViewZ.xyz = wpos; \
    496.     o._WorldPosViewZ.w = -mul( UNITY_MATRIX_MV, v ).z; \
    497.     o._ShadowCoord0 = mul(unity_World2Shadow[0], wpos).xyz; \
    498.     o._ShadowCoord1 = mul(unity_World2Shadow[1], wpos).xyz; \
    499.     o._ShadowCoord2 = mul(unity_World2Shadow[2], wpos).xyz; \
    500.     o._ShadowCoord3 = mul(unity_World2Shadow[3], wpos).xyz;
    501.  
    502.  
    503. #if defined (SHADOWS_NATIVE)
    504.     #define SAMPLE_SHADOW_COLLECTOR_SHADOW(coord) \
    505.     half shadow = UNITY_SAMPLE_SHADOW(_ShadowMapTexture,coord); \
    506.     shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r);
    507. #else
    508.     #define SAMPLE_SHADOW_COLLECTOR_SHADOW(coord) \
    509.     float shadow = UNITY_SAMPLE_DEPTH(tex2D( _ShadowMapTexture, coord.xy )) < coord.z ? _LightShadowData.r : 1.0;
    510. #endif
    511.  
    512. #define COMPUTE_SHADOW_COLLECTOR_SHADOW(i, weights, shadowFade) \
    513.     float4 coord = float4(i._ShadowCoord0 * weights[0] + i._ShadowCoord1 * weights[1] + i._ShadowCoord2 * weights[2] + i._ShadowCoord3 * weights[3], 1); \
    514.     SAMPLE_SHADOW_COLLECTOR_SHADOW(coord) \
    515.     float4 res; \
    516.     res.x = saturate(shadow + shadowFade); \
    517.     res.y = 1.0; \
    518.     res.zw = EncodeFloatRG (1 - i._WorldPosViewZ.w * _ProjectionParams.w); \
    519.     return res;  
    520.  
    521. #if defined (SHADOWS_SPLIT_SPHERES)
    522. #define SHADOW_COLLECTOR_FRAGMENT(i) \
    523.     float3 fromCenter0 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[0].xyz; \
    524.     float3 fromCenter1 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[1].xyz; \
    525.     float3 fromCenter2 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[2].xyz; \
    526.     float3 fromCenter3 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[3].xyz; \
    527.     float4 distances2 = float4(dot(fromCenter0,fromCenter0), dot(fromCenter1,fromCenter1), dot(fromCenter2,fromCenter2), dot(fromCenter3,fromCenter3)); \
    528.     float4 cascadeWeights = float4(distances2 < unity_ShadowSplitSqRadii); \
    529.     cascadeWeights.yzw = saturate(cascadeWeights.yzw - cascadeWeights.xyz); \
    530.     float sphereDist = distance(i._WorldPosViewZ.xyz, unity_ShadowFadeCenterAndType.xyz); \
    531.     float shadowFade = saturate(sphereDist * _LightShadowData.z + _LightShadowData.w); \
    532.     COMPUTE_SHADOW_COLLECTOR_SHADOW(i, cascadeWeights, shadowFade)
    533. #else
    534. #define SHADOW_COLLECTOR_FRAGMENT(i) \
    535.     float4 viewZ = i._WorldPosViewZ.w; \
    536.     float4 zNear = float4( viewZ >= _LightSplitsNear ); \
    537.     float4 zFar = float4( viewZ < _LightSplitsFar ); \
    538.     float4 cascadeWeights = zNear * zFar; \
    539.     float shadowFade = saturate(i._WorldPosViewZ.w * _LightShadowData.z + _LightShadowData.w); \
    540.     COMPUTE_SHADOW_COLLECTOR_SHADOW(i, cascadeWeights, shadowFade)
    541. #endif
    542.  
    543. #endif
    544.  
    545. #endif
    546.  
     
  9. Doggettx

    Doggettx

    Joined:
    Jul 18, 2014
    Posts:
    3
    I've tried to implement the above code, it seems to work mostly but having problems with the geometry shader not writing correct depth texture. It seems to only write the input vertices and not the geometry output vertices. Any ideas on how to solve that?
     
  10. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,051
    Last time I checked it worked fine for me, had various overlapping objects and didn't notice any depth issues. However there are problems with shadowing (can't remember off-hand if that was all shadowing or just self-shadowing) which were related to either depth or offsets.

    Something to keep in mind, if the geometry shader generates a mesh that considerably changes its volume or position then other aspects of Unity's renderer may fail or produce weird results (e.g. culling).

    I'm afraid i'm rather busy on other topics at present so can't investigate this further, but like I said this code is really just presented as a starting point for others to save some time. Its more of an initial framework with which to write geometry shaders and not a complete solution. Indeed its actual effects are pretty useless ;)
     
  11. Doggettx

    Doggettx

    Joined:
    Jul 18, 2014
    Posts:
    3
    Thanks for the quick reply, indeed the objects itself don't show any depth issues. It's just that any deferred effect gets incorrect depth information (so shadows, ssao etc don't work correctly). My volume does indeed change quite a bit since a single vertex goes in and a cube comes out, if I ever figure it out i'll post an update here....

    Wouldn't it be nice though if we could just add geometry: geom to a #pragma surface instead ;)
     
  12. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,051
    Sounds like deferred is not playing nice with forward rendering then, since my shader only supports forward rendering. If you are able, try adding a deferred shader pass to my shader and see if that fixes the issue.

    Agree about it being nice if we could just add geom to a surface shader, however I seem to remember when writing the shader that it wasn't so straight forward to do.
     
  13. sejton

    sejton

    Joined:
    Dec 3, 2012
    Posts:
    7
    I've faced similar difficulties trying to create my custom grass billboards in geometry shader and make them receive shadows from trees and also cast them on the ground. I used vertex/geometry/fragment shaders since I couldn't use geometry shader with surface shader. This topic helped me a lot so I thought it would be a good idea to link it to my solution trough this post.

    Solution is presented in answer to this question:
    http://answers.unity3d.com/questions/973067/using-shadow-texture-to-recieve-shadows-on-grass.html

    This solution doesn't require to change AutoLight.cginc, UnityCG.cginc or any other .cginc file. It's a one shader solution with base and shadowcaster passes.

    Source included at the bottom of the answer!

    I hope that someone would find it helpful. Enjoy!
     
    Howard-Day and Noisecrime like this.