Search Unity

Where is SetTextureArray?

Discussion in 'Shaders' started by TOES, Apr 14, 2020.

  1. TOES

    TOES

    Joined:
    Jun 23, 2017
    Posts:
    134
    You can pass array elements such as vectors and floats using SetVectorArray and SetFloatArray, but I need to pass textures to an array. How?

    I use GLSL, so my texture array is defined like this:

    Code (CSharp):
    1. uniform sampler2D textureSlot[16];
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    GPUs don’t actually support arrays of textures.

    GLSL has a funny quirk in that it sometimes lets you use the above code, but it’s doesn’t actually compile to an array, but rather expands out to multiple texture entries.

    Code (csharp):
    1. uniform sampler2D textureSlot[16];
    I’d really short hand for:
    Code (csharp):
    1. sampler2D textureSlot1;
    2. sampler2D textureSlot2;
    3. sampler2D textureSlot3;
    4. //etc
    If you want an array of textures you need to use the Texture2DArray texture type, which is a texture object with multiple layers.
     
    Last edited: Apr 15, 2020
  3. TOES

    TOES

    Joined:
    Jun 23, 2017
    Posts:
    134
    Thank you, this is very useful information!

    So does this mean I can use this in Unity, when declaring the textureSlot as an array in GLSL:

    Code (csharp):
    1. int textureIndex=1;
    2. material.setTexture("textureSlot"+textureIndex,texture2D);
    And, if I understand this correctly, on the GLSL side

    Code (csharp):
    1. uniform sampler2D textureSlot[4];
    2. ...
    3. Sampler2D currentSampler=textureSlot[textureIndex];
    would actually expand to

    Code (csharp):
    1. if (textureIndex== 1)
    2.    currentSampler = textureSlot1; else
    3. if (textureIndex== 2)
    4.    currentSampler = textureSlot2; else
    5. if (textureIndex== 3)
    6.    currentSampler = textureSlot3; else
    7. if (textureIndex== 4)
    8.    currentSampler = textureSlot4;
    Do you know if there are any performance benefits letting the compiler expand the code for you rather than manually write the if else as above?

    I think i would still like to use the array statement, as it looks cleaner and I might have quite a lot of samplers.

    Unfortunately I cannot use the Texture2DArray texture type as the textures might have different resolutions.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Honestly not sure. Possibly? Before Unity 5.4 or so there weren’t even
    Set_Array
    material functions and all array values were set like the c# example code you posted. Those don’t work anymore for proper arrays as there are now those material functions. I don’t know how smart Unity is at handling that kind of GLSL since it’s technically not valid code per the spec, just some compilers will handle it the way I described.

    Possibly even worse. It’ll probably be more like:
    Code (CSharp):
    1. fixed4 col = 0;
    2. fixed4 colTemp0 = tex2D(textureSlot0, uv);
    3. if (textureIndex == 0)
    4.   col = colTemp0;
    5. fixed4 colTemp1 = tex2D(textureSlot1, uv);
    6. if (textureIndex == 1)
    7.   col = colTemp1;
    8. // etc
    You will most likely pay for the actual texture sampling. You’d have to look at the compiled shader from your target device to find out what it actually does though.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You might want to rethink how you’re doing things then.
     
  6. TOES

    TOES

    Joined:
    Jun 23, 2017
    Posts:
    134
    No, I already looked into this. This is a rendering editor tool, it has to be flexible and I cannot limit what type of textures the artist can use. The way Unity loads texture arrays is also slow and cumbersome, which would slow down the rendering preview system too much.
     
  7. TOES

    TOES

    Joined:
    Jun 23, 2017
    Posts:
    134
    I tried and it looks like Unity has its own system for setting those uniform variables, and it is not compatible with texture array unrolling you described. I will probably have to do this in a plugin. I hoped to avoid that as working with DLLs is so tedious in Unity, you actually have to reboot your whole project every time you change the DLL as the editor hooks into it so it cannot be overwritten. Also, loads of overhead to execute even a single OpenGL command in the correct way.

    Probably easier to write my own unroll script that puts the code into the shader itself...