vertex fragment domain hull shader > tessellation with shadows

Heyho!

After a week of research regarding tessellation I managed to build a edge length based tessellation shader based on example shaders I found on the internetz.

I have another shader with working shadows. Now I want to combine both…

I understand how the flow through both shader works and tessellation itself works flawless, shadows too. But now I have a bit of a problem to understand how to attach the tessellation shader to unitys shadow pipeline.

I found this interesting post but they are talking about a geometry program shader
__http://forum.unity3d.com/threads/is-it-possible-to-use-geometry-shader-with-surface-shaders.164905/__

Is it the way to go to expand the unityCG and AutoLight cginc files? (which would be ok)

also adding a shadow collector and caster pass.

I have unity 4 and 5 on my hands but I guess it makes no difference, right?

I’m currently working on it but I have the feeling this is not thought through. Could someone with more knowledge check the above thread and explain if that’s how it should be done? Is there definitely no support for something like TRANSFER_VERTEX_TO_FRAGMENT(o) for a hull - domain shader right now and in the near future?

cheers

ok to answer my own question. It is the way to go! It doesn’t matter if he is using an geometry program. it’s the same method.

So in very short (showing only the shadow relevant code) it is:

/############### base pass

struct HullType
{
    float4 pos : SV_POSITION;
    float2 uv : TEXCOORD0;
    float3 normal : NORMAL;
    float4 tangent : TANGENT;
    float4 color: COLOR;
};

struct PixelInputType
{
    LIGHTING_COORDS(4,5)  
};
//--------------------------------------------------------------------------------------


//--------------------------------------------------------------------------------------
// Domain Shader - Geometry Pass
//--------------------------------------------------------------------------------------
[domain("tri")]
PixelInputType DS(ConstantOutputType input, float3 domainCoord : SV_DomainLocation, const OutputPatch<HullType, 3> patch)
{  
    TRANSFER_GEOM_TO_FRAGMENT(output, output.pos);
}
//--------------------------------------------------------------------------------------





// /############### collector / caster pass



       //--------------------------------------------------------------------------------------
// TYPEDEFS - Shadow Pass
//--------------------------------------------------------------------------------------

struct HullType_S
{
    #ifdef SHADOW_CASTER_PASS
        V2F_SHADOW_CASTER; // (this one blocks TexCoord 0 to 4 and defines pos) //float4 pos : SV_POSITION;
    #else
        V2F_SHADOW_COLLECTOR; // (this one blocks TexCoord 0 to 4 and defines pos) //float4 pos : SV_POSITION;
    #endif
};
struct PixelInputType_S
{
    #ifdef SHADOW_CASTER_PASS
        V2F_SHADOW_CASTER; // (this one blocks TexCoord 0 to 4 and defines pos) //float4 pos : SV_POSITION;
    #else
        V2F_SHADOW_COLLECTOR; // (this one blocks TexCoord 0 to 4 and defines pos) //float4 pos : SV_POSITION;
    #endif
};
//--------------------------------------------------------------------------------------


//--------------------------------------------------------------------------------------
// Domain Shader - Shadow Pass
//--------------------------------------------------------------------------------------
[domain("tri")]
PixelInputType_S DS_S(ConstantOutputType input, float3 domainCoord : SV_DomainLocation, const OutputPatch<HullType_S, 3> patch)
{      

    // here it makes a lot more sense but the method must fit the domain shader
    #if defined (SHADOW_COLLECTOR_PASS)    
        TRANSFER_SHADOW_COLLECTOR(output, vertexPosition)   
    #elif defined (SHADOW_CASTER_PASS)       
        TRANSFER_SHADOW_CASTER(output, vertexPosition)
    #endif
  

}
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// Pixel Shader - Shadow Pass
//--------------------------------------------------------------------------------------

float4 PS_S(PixelInputType_S i) : COLOR
{
    #if defined (SHADOW_COLLECTOR_PASS)
        SHADOW_COLLECTOR_FRAGMENT(i) 
    #elif defined (SHADOW_CASTER_PASS)   
        SHADOW_CASTER_FRAGMENT(i)
    #endif    
}

But I have another question: why does the shader doesn’t render “multi_compile_fwdadd” correctly?

If I only output the Forward Add Pass like that

...
// forward add pass
    Pass {
        Name "FORWARDADD"    
        Tags {"LightMode" = "ForwardAdd"}
        //Blend One One
        //Blend Zero One // only ambient
        Blend One Zero     // only direct light

        CGPROGRAM

#pragma target 5.0      
     #pragma vertex VS   
     #pragma fragment PS
     #pragma hull HS   
     #pragma domain DS   
   
     #pragma multi_compile_fwdadd
     #pragma fragmentoption ARB_precision_hint_fastest
     #pragma only_renderers d3d11
     
     //----------------------------------------------------------
     #define UNITY_PASS_FORWARDADD
     #include "UnityCG.cginc"
     #include "cginc/DwarfMines_UnityCG.cginc"
     #include "AutoLight.cginc"
     #include "cginc/DwarfMines_AutoLight.cginc"
     //#include "Lighting.cginc"
     //----------------------------------------------------------
     
     sampler2D _MainTex;
     
     //-------------------------------------------------------
     uniform half _DisplacementFactor;   
     uniform half _StaticTessellationFactor;
     uniform half _MaxDynamicTesselation;
     
     #include "cginc/DwarfMines_Tessellation.cginc"
     //-------------------------------------------------------
     

     //--------------------------------------------------------------------------------------
     // Pixel Shader
     //--------------------------------------------------------------------------------------
     float4 PS(PixelInputType v) : COLOR
     {
        float4 returnColor = float4(0.0, 1.0, 0.0, 1.0);       
       
       float atten = LIGHT_ATTENUATION(v); // This gets you the attenuation + shadow value.
       
       float3 lightDirection;
       if (0.0f == _WorldSpaceLightPos0.w) // directional light?   
         lightDirection = normalize(float3(_WorldSpaceLightPos0.xyz));   
       else // point or spot light   
         lightDirection =  normalize(float3(_WorldSpaceLightPos0.xyz - v.pos.xyz));
         
       float lightIntensity = saturate(dot(v.normal_w,lightDirection));

       if(lightIntensity > 0.0f)       
         returnColor += lightIntensity;         

       float3 diffuse = tex2D (_MainTex, v.uv).rgb;
       returnColor.rgb = atten*lightIntensity;       

       return saturate(returnColor);
     }
     
     ENDCG
   
   } // end pass "forward add"
   //-----------------------------

I get this behaviour
(center sphere is a reference with my working shader without tessellation)
What I expect: see the red light illuminate the plane and the 2nd sphere with attenuation and whatnot.