multi target shaders?

hi guys,

i have a little (big) problem. i wrote a shader effect which works fine in dx9 with sm3. then i’ve added tessellation and with that it runs perfectly in dx11 BUT it doesnt anymore do anything in dx9. which is ok, if it has tessellation its compiled to dx11 automatically…
the question is. can a shader be built up from 2 parts (maybe with multiple passes or multi_compile etc) so the dx9 bit would run on both dx9 and 11 and the tessellation would run on dx11 only?

thanks for all the help.

That’s what SubShader tag is for.
Your Shader can contain multiple SubShaders and the first one that can run on current device will be used.

1 Like

ok, i have to write the entire shader in 2 version in the 2 subshaders or can i use one sub-s output in an other sub? i cant really understand this from the unity doc of subshaders and i havent found a good example yet. could you just write in a few lines how would you separate these 2 bits in 2 subshaders?

  • CGPROGRAM
  • #ifdef SHADER_API_D3D11
  • #pragma surface surf NoLight alpha:fade vertex:dispNone tessellate:tessEdge tessphong:_Phong nolightmap
  • #include"Tessellation.cginc"
  • #pragma target 5.0
  • #else
  • #pragma surface surf NoLight alpha:fade nolightmap
  • #pragma target 3.0
  • #endif

thanks a lot

You can’t use output of one SubShader in another, because only one SubShader can be used.

Shader{
    Properties { ... }
    SubShader { //This one uses direct3d11, Unity will try to use this first
        Pass { ...some code... }
        Pass { ...some code... }
    }
    SubShader { //If previous subshader couldn't run then this one will run using direct3d9
        Pass { ...some code... }
        Pass { ...some code... }
    }
    //Note, if you put the SubShader for direct3d9 above the one that uses direct3d11 the second one will never be used.
    //Also note that mac and linux can't use direct3d at all, they use OpenGL,
    //but I assume that your direct3d9 code can be compiled using OpenGL
}

You can define SurfaceOutput function within CGINCLUDE and use in any subshader you write
Something like that:

Shader{
Properties { ... }
CGINCLUDE
    float4 YourTessellateFunction (appdata v0, appdata v1, appdata v2){...}
    void YourSurfFunction(Input IN, inout SurfaceOutput o){...}
ENDCG
SubShader
{
    Tags { "RenderType"="Opaque" }
    LOD 300
    
    CGPROGRAM
    #pragma surface YourSurfFunction Lambert tessellate:YourTessellateFunction
    ENDCG
}
SubShader
{
    Tags { "RenderType"="Opaque" }
    LOD 200
    
    CGPROGRAM
    #pragma surface YourSurfFunction Lambert
    ENDCG
}
}

ok, things get cleared up, greatly thanks for both of you. this knowledge is already enough to make it working :slight_smile:

my problem is based on defaxers code is, as i’ve understood from my googling cginclude will put the entire functions i write between into both subshaders. generally the same as if i would copy paste them. isnt it? (it still looks better, just asking)

so if i understood well i can do it like write the surface shader in cginclude
then write the dx11 subshader with the tags, #pragma lines, vertex and tessellation routines as the surf shader will be included
and then really just an empty subshader for dx9 with just the tags and the #pragma line, as cginclude will insert the surf shader code there.

but after compiling there will be the surf shader code in the file twice? is there a way to have it like one pass for my lighting code, one for my surf code and then having a subshader just for the tessellation?
for me this logic is just strange. i would think you build up things like first the least demanding stuff and then add the more demanding ones if the system supports them…

The include comand just means “copy this here”. You will end up with the same functions in both subshaders, but that doesn’t matter because only one will be used.

That would be fine IF the graphic card didn’t need to execute the complex stuff like tessellation before the rest of the code.

ahh, i see, thanks a lot for all the help and explanation. i will start rewriting the code :slight_smile: have a nice day both of you.