Search Unity

tex2D inside UNITY_PROCEDURAL_INSTANCING_ENABLED in surf doesn't work.

Discussion in 'Shaders' started by JohnnyBackflip, Jul 29, 2019.

  1. JohnnyBackflip

    JohnnyBackflip

    Joined:
    Oct 28, 2015
    Posts:
    8
    Hi,
    I want to use multiple textures on an Instanced rendered Object. I've tested it with plain Colors and it works but as soon as I add Textures the Texture will be displayed as just one color on the Object:

    Code (CSharp):
    1.  
    2. ...
    3.                 #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    4.                         StructuredBuffer<Particle> particleBuffer;
    5.                 #endif
    6. ...
    7. void surf (Input IN, inout SurfaceOutputStandard o)
    8.         {
    9.  
    10.             #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    11.  
    12.                 int colorID = particleBuffer[unity_InstanceID].colorID;
    13.  
    14.                 if (colorID == 0) {
    15.                     //this works:
    16.                     o.Albedo = _Color.rgb;
    17.                     //this doesn't work:
    18.                     o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
    19.                 }
    20.             #endif
    21.            
    22.         }
    The UV mapping is correct, f.e. this Code works:

    Code (CSharp):
    1.    
    2. void surf (Input IN, inout SurfaceOutputStandard o)
    3.         {
    4.  
    5.             #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    6.  
    7.                 int colorID = particleBuffer[unity_InstanceID].colorID;
    8.  
    9.                 if (colorID == 0) {
    10.                     o.Albedo = _Color.rgb;
    11.                 }
    12.            
    13.             #endif
    14.                 o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
    15.            
    16.         }
    But doing it this way I can only get one Texture on the object. But I need a switch to change the texture.

    So I've introduced a helper Variable like this:

    Code (CSharp):
    1.    
    2. void surf (Input IN, inout SurfaceOutputStandard o)
    3.         {
    4.             int textureSwitch = 0;
    5.             #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    6.  
    7.                 int colorID = particleBuffer[unity_InstanceID].colorID;
    8.  
    9.                 if (colorID == 0) {
    10.                     o.Albedo = _Color.rgb;
    11.                     textureSwitch = 1;
    12.                 }
    13.  
    14.             #endif
    15.  
    16.                 if (textureSwitch) {
    17.                     o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
    18.                 }
    19.            
    20.         }
    textureSwitch is never set by what's inside UNITY_PROCEDURAL_INSTANCING_ENABLED but it's called.

    What's going on here?

    Edit.
    This guy is having the exact same problem:
    https://forum.unity.com/threads/structuredbuffer-with-surface-shader.173000/#post-3102487
     
    Last edited: Jul 29, 2019
  2. JohnnyBackflip

    JohnnyBackflip

    Joined:
    Oct 28, 2015
    Posts:
    8
    So after doing some more research it seems like the UV coordinates inside the surf function are wrong. This doesn't work as expected (Texture is one-colored):
    Code (CSharp):
    1.              
    2. void surf(Input IN, inout SurfaceOutputStandard o)
    3.                   {
    4.                       int k = 0;
    5.                       #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    6.                       k = 1;
    7.                       #endif
    8.                       o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb*k;
    9.  
    10.                   }
    This doesn't work.



    Edit: this is the whole Shader:

    Code (CSharp):
    1.  
    2. Shader "ComputeShader/Cubes"
    3. {
    4.     Properties
    5.     {
    6.             _MainTex("Texture", 2D) = "white" {}
    7.             _TextureTwo("_TextureTwo", 2D) = "white" {}
    8.  
    9.             _Color("Color", Color) = (1,1,1,1)
    10.             _ColorTest("ColorTest", Color) = (1,1,1,1)
    11.  
    12.             _ColorCollisionLeft("ColorCollisionLeft", Color) = (1,1,1,1)
    13.             _ColorCollisionRight("ColorCollisionRight", Color) = (1,1,1,1)
    14.             _ColorCollisionTop("ColorCollisionTop", Color) = (1,1,1,1)
    15.             _ColorCollisionBottom("ColorCollisionBottom", Color) = (1,1,1,1)
    16.             _ColorCollisionFront("ColorCollisionFront", Color) = (1,1,1,1)
    17.             _ColorCollisionBack("ColorCollisionBack", Color) = (1,1,1,1)
    18.  
    19.             _Glossiness("Smoothness", Range(0,1)) = 0.5
    20.             _Alpha("Alpha", Range(0,1)) = 0.5
    21.  
    22.     }
    23.         SubShader{
    24.             Tags { "RenderType" = "Opaque" }
    25.             LOD 200
    26.  
    27.                 #pragma surface surf Standard vertex:vert addshadow
    28.                 #pragma multi_compile_instancing
    29.                 #pragma instancing_options procedural:setup
    30.                 #pragma target 3.0
    31.                 #include "TransformMatrix.cginc"
    32.  
    33.                 half _Glossiness;
    34.                 half _Alpha;
    35.  
    36.  
    37.                 //debugging colorss
    38.                 half4 _Color;
    39.                 half4 _ColorTest;
    40.  
    41.                 //collision colors
    42.                 half4 _ColorCollisionLeft;
    43.                 half4 _ColorCollisionRight;
    44.                 half4 _ColorCollisionTop;
    45.                 half4 _ColorCollisionBottom;
    46.                 half4 _ColorCollisionFront;
    47.                 half4 _ColorCollisionBack;
    48.  
    49.                 struct Input {
    50.                     float2 uv_MainTex;
    51.                     float2 uv_TextureTwo;
    52.                     half4 col;
    53.                 };
    54.  
    55.                 //new particle struct
    56.                 struct Particle
    57.                 {
    58.                     half3 position;
    59.                     half3 positionToMoveTo;
    60.                     half3 velocity;
    61.                     half3 scale;
    62.                     half3 rotation;
    63.                     int isActive;
    64.                     int isVisible;
    65.                     int colorID;
    66.                 };
    67.                         #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    68.                                 StructuredBuffer<Particle> particleBuffer;
    69.                         #endif
    70.  
    71.                 void vert(inout appdata_full v)
    72.                 {
    73.                   #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    74.  
    75.                                           half3 position = particleBuffer[unity_InstanceID].position;
    76.                                           half3 scale = particleBuffer[unity_InstanceID].scale;
    77.                                           half3 rotation = particleBuffer[unity_InstanceID].rotation;
    78.  
    79.                                           int isActive = particleBuffer[unity_InstanceID].isActive;
    80.                                           int isVisible = particleBuffer[unity_InstanceID].isVisible;
    81.  
    82.                                           if (isVisible) {
    83.  
    84.                                               float4x4 object2world = (float4x4)0;
    85.                                               object2world._11_22_33_44 = float4(scale.xyz, 1.0);
    86.  
    87.                                               float4x4 rotMatrix = eulerAnglesToRotationMatrix(rotation.xyz);
    88.  
    89.                                               object2world = mul(rotMatrix, object2world);
    90.                                               object2world._14_24_34 += position.xyz;
    91.  
    92.                                               v.vertex = mul(object2world, v.vertex);
    93.                                               v.normal = normalize(mul(object2world, v.normal));
    94.  
    95.                                           }
    96.                                           else {
    97.                                             //...
    98.                                           }
    99.                       #endif
    100.                   }
    101.  
    102.                   void setup()
    103.                   {
    104.  
    105.                   }
    106.  
    107.                   sampler2D _MainTex;
    108.                   sampler2D _TextureTwo;
    109.                
    110.  
    111.                   void surf(Input IN, inout SurfaceOutputStandard o)
    112.                   {
    113.                       int k = 0;
    114.                       #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    115.                       k = 1;
    116.                       #endif
    117.                       o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb*k;
    118.  
    119.                   }
    120.         ENDCG
    121.     }
    122.     FallBack "Diffuse"
    123. }
    124.  
    125.  

    If I want to debug the vertex color using
    Code (CSharp):
    1.                 struct Input {
    2.                     float4 color : COLOR;
    3.                 };
    4.  
    This will be red:

    Code (CSharp):
    1.                  
    2. void surf(Input IN, inout SurfaceOutputStandard o)
    3.                   {
    4.                       #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    5.                       o.Albedo = IN.color;
    6.                       #endif
    7.                   }
    This will be white:

    Code (CSharp):
    1.                  
    2.  void surf(Input IN, inout SurfaceOutputStandard o)
    3.                   {
    4.                       o.Albedo = IN.color;
    5.                   }
     
    Last edited: Jul 29, 2019
  3. JohnnyBackflip

    JohnnyBackflip

    Joined:
    Oct 28, 2015
    Posts:
    8
    I've managed to solve it this way:

    Code (CSharp):
    1.  
    2. void surf(Input IN, inout SurfaceOutputStandard o)
    3.                   {
    4.                      
    5.                       float3 colorOne = tex2D(_MainTex, IN.uv_MainTex).rgb;
    6.                       float3 colorTwo = tex2D(_TextureTwo, IN.uv_MainTex).rgb;
    7.                       float3 colorThree = tex2D(_TextureThree, IN.uv_MainTex).rgb;
    8.  
    9.                       //default Color
    10.                       float3 cubeColor = colorOne;
    11.  
    12.                       #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    13.  
    14.                           int colorID = particleBuffer[unity_InstanceID].colorID;
    15.  
    16.                           if (colorID == 0) {
    17.                               cubeColor = colorTwo;
    18.                           }
    19.                           if (colorID == 1) {
    20.                               cubeColor = colorThree;
    21.                           }
    22.                           if (colorID == 2) {
    23.                               cubeColor = colorThree;
    24.                           }
    25.  
    26.                           o.Smoothness = _Glossiness;
    27.                           o.Alpha = _Alpha;
    28.                       #endif
    29.                           o.Albedo = cubeColor;
    30.  
    31.                   }
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Some explanation of why you were having issues.

    Unity's Surface Shaders look over your surf function to see what values are and aren't being used, but it does this with none of the built in defines. This means if you have a surf function that samples a texture, but only inside of #if UNITY_PROCEDURAL_INSTANCING_ENABLED, it'll think you're not using the texture UVs at all and skips setting up those values. By using them outside of the #if it lets the code generator see that you are actually using it.

    Also, if you're looking to use multiple textures with instancing, look into texture arrays.
     
    JohnnyBackflip likes this.
  5. JohnnyBackflip

    JohnnyBackflip

    Joined:
    Oct 28, 2015
    Posts:
    8
    Ah ok, I understand, thanks for clarifying.
    I have a custom set of UVs in IN.uv_MainTex which I can reuse for the other textures because the UVs of every object are the same.
    Currently I am not encountering any problems, do I really need to use Texture arrays? In what cases do I use them.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    With your current setup, for every texture you want to use, every instance has to sample from every texture. For 3 or 4 textures this isn’t a huge deal, but it does mean the shader is going to be slower than it could be. It also means more work if you want to add more textures.

    Texture arrays let you put multiple textures into a “single texture” where you can choose which texture to access with a third uv component that selects the layer index. This means you only sample “one texture” for all of the instances, and it doesn’t require any shader changes to add or remove textures. Just pass the index as an instanced property, like you already are, and you’re done.
     
    JohnnyBackflip likes this.
  7. JohnnyBackflip

    JohnnyBackflip

    Joined:
    Oct 28, 2015
    Posts:
    8
    Ah now I know what you mean. Yes I will keep that in mind for later thanks for the hint and the help, really appreciate it.