Search Unity

  1. Looking for a job or to hire someone for a project? Check out the re-opened job forums.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Accessing INTERAL_DATA fields in the surface shader

Discussion in 'Shaders' started by keeperkai2, Jul 3, 2013.

  1. keeperkai2


    Oct 26, 2012
    The unity surface shader compiler does a lot of things behind the scenes, one of them is calculating the Tangent space to world space matrix and passing it to the surface shader, i.e:
    if you write an input for your surface shader
    Code (csharp):
    1. struct Input{
    2. float3 worldRefl;
    3. float3 worldPos;
    4. INTERNAL_DATA//<---this is a #define preprocessed field, it is actually float3 TtoW0;float3 TtoW1;float3 TtoW2; which are the three //columns of Tangent to world space matrix
    5. }
    7. it will actually be like
    8. struct Input{
    9. float3 worldRefl;
    10. float3 worldPos;
    11. float3 TtoW0;
    12. float3 TtoW1;
    13. float3 TtoW2;
    14. }
    If your surface shader looks like this:
    Code (csharp):
    1. void surf (Input IN, inout SurfaceOutput o) {
    2. o.Normal=UnpackNormal(blah blah blah);//the surface shader only calculates the tangent space to world space matrix when you //write to o.Normal
    3. }
    and you want the per vertex world normal(to do some other stuff), you should be able to get it without introducing new fields for the Input since you can get it directly by float3(IN.TtoW0.z,IN.TtoW1.z,IN.TtoW2.z)
    but the surface shader compiler will throw an error saying that the expression left of TtoW* is not a struct(but if you change those TtoW0 fields to IN.worldPos.z, it will compile fine), so as you can see, the surface shader compiler doesn't recognize the TtoW* fields when it analyzes your surface shader and forbids you to save one interpolater and the redundant calculations to calculate the vertex normals. It seems that the unity compiler doesn't preprocess the INTERAL_DATA when it compiles the surface shader to the cg code, it only does it after.

    Well, this is a pain in the ass for me since: My previous post here
    for the Reflective shaders of unity, it uses a lot of interpolaters already. And I came up with this way to save one interpolater but unity forbids me from doing so. However, I could add #pragma debug and copy the code from the compiled shader and modify it after it is compiled, but that conflicts the fact that I developed this shader composer(that produces surface shader code), and now I still have to do the optimizations by hand, and unity won't let my radeon hd 7770 graphics card use all the interpolaters it has even if I use #pragma debug 4.0 or 5.0(which they confirmed is a bug).
    Even worse, unity doesn't have an api to call the surface shader so I can automatically get the compiled shader and modify it afterwards.

    And while doing so, I even discovered that I couldn't use #pragma 4.0 or 5.0 in the compiled cg shader for some reason(hd7770 supports shader model 5.0). For instance, if I write a surface shader and use pragma target 4.0 or 5.0, it's fine. but if I #pragma debug that shader and copy all the compiled cg code, it tells me that there is no subshader that can run on my graphics card...

    To sum up:
    1. Is there anyway to call the surface shader compiler and retrieve the compiled cg code from script?
    2. Is there anyway to access the TtoW* fields in the surface shader?
    Last edited: Jul 4, 2013