Search Unity

Accessing Textures by Name?

Discussion in 'Shaders' started by lumoconnor, Oct 22, 2018.

  1. lumoconnor

    lumoconnor

    Joined:
    Jan 17, 2016
    Posts:
    27
    Hello, everyone. I'm writing a Compute Shader that needs to sample the textures associated with the materials in the scene. Is there any way to access these textures by name (Instead of having to declare a Texture2D with a matching name)?

    Right now I only seem to be able to access the textures by declaring variables such as:
    Texture2D<float> _texture1;


    Since the names of the textures can be arbitrary, I'd ideally like to access the textures by name, e.g.
    GetTexture("texture1");


    Does such a command exist?

    Thanks for your help!
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,348
    Nope.

    Understand the texture has no name on the GPU. It has a pre-assigned register index per shader. When you do something like this:

    sampler2D _TexA;
    sampler2D _TexB;
    sampler2D _TexC;

    fixed4 colC = tex2D(_TexC, UV);


    That tex2D function is really sampling "texture register 2". The name exists purely in the high level shader code, not in the compiled assembly shader the GPU is actually running. The name of the texture is used during shader compilation and CPU side draw call setup so that the texture asset assigned to _TexC gets sent to the GPU so it knows what to put in that register. The result is all "named" textures have to be known before the GPU even gets the shader.

    The solution to this kind of problem for the last decade has been using texture arrays. The obvious limitation being you're limited to textures of the same size and format. However you can use multiple texture arrays sorted by a few sizes and formats and that'll get you 90% of the way. Before texture arrays, the solution was texture atlases, which people still use today, and you can use with texture arrays to get textures that are different sizes in the same array. Atlases come with all kinds of gotchas, but they're effective.


    The modern solution is to use bindless textures. This is a DirectX12 & Vulkan feature (also available to OpenGL via extensions) which works similar to an array in that you access a texture by it's "index" (or handle in bindless parlance) from an array, but the array in this case is really just a contiguous list of textures of arbitrary sizes and formats. If you need to access a texture, you just need to know that texture's handle and then pass that to the shader as a material, vertex, or buffer property.

    Unfortunately, as far as I know, this isn't a feature that Unity supports. It may be possible with a native plugin, but that's outside my area of expertise.
     
  3. lumoconnor

    lumoconnor

    Joined:
    Jan 17, 2016
    Posts:
    27
    Thanks, this is really helpful!

    I was trying to find a way to use texture arrays, but as you said, had been running into the limitation that the textures must be the same size. My hacky solution for the time being was to just declare a bunch of textures in the shader (_texture1, _texture2 ..... _texture10) which is not ideal, but works.

    I'll take a look at bindless textures.