in programming, shader, tutorial, Unity3D

Arrays & Shaders in Unity 5.4+

Share Button

This post shows how to use arrays and shaders in Unity 5.4. Back in January I already covered this topic in an article called Arrays & shaders: Heatmaps in Unity. My original approach exposed an undocumented feature that allowed to pass arrays to shaders. Since then, Unity 5.4 has introduced proper support in its API. This tutorial replaces the previous article. If you have read the previous tutorial, you do not need any changes to your shader code and you can skip to Step 2.

Step 1. The Shader

Every shader has a section called Property, which allows to expose certain variables in the material inspector. At the time this article is written, Unity does not support an array type. Consequently, you cannot access arrays directly from the inspector. It’s worth notice that Unity supports a type called 2DArray, but that is reserved for texture arrays; what we want is an array of numbers instead.

All arrays, have to be declared as variables and initialised externally via a script. Arrays in shaders need to have a predefined length. If you don’t know in advance how many items you’ll need to store, allocate more space and keep a variable (for instance, _ArrayLength) that will indicates how many items are actually present.

In the example above, both variables has been decorated with the uniform keyword. This is because their value is changed from an external script, and we assume that those changes do not happen in between frames.

You can now look your array in the shader code like any other type of array:

Step 2. The Script

If you want to use your shader, you need to initialise the array using an external script. The new API of Unity 5.4+ supports the following SetFloatArray, SetMatrixArray and SetVectorArray. As expected, they are used to initialise arrays of float, Matrix4x4 and Vector4, respectively. This is a snippet on how to correctly use those functions:

where material is the Unity material that uses your shader. You can drag it directly from the inspector, or retrieving it via code:

Unity 5.4 also supports global arrays. Those are properties that are set once and are then shared by all shaders. They work in a similar way, and have signatures  SetGlobalFloatArray, SetGlobalMatrixArray and SetGlobalVectorArray. However, they are static methods of the Shader class.

Step 3. Limitations

If you need to pass other types of arrays (such as int, long, Vector3, …) you have to use the method that closely matches your needs. For instance, you can fit int values in an array of floats. Similarly, if you want to provide Vector3s to your shader, you’ll need to wrap them into Vector4s. You can automatically assign a Vector3 to a Vector4, as Unity will automatically fit them in the right way, leaving the last coordinate set to zero. However, you cannot assign a Vector3[] to a Vector4[].

The second consideration that you have to keep in mind it involves some poor design choices made by Unity. It seems that the first time that you use set an array (whether it’s locally or globally), Unity fixes the size of the array itself. For instance, if you initialise an array defined in the shader as uniform float _Array[10]; with a C# array defined as float[] array = new float[5];, you will not be able to set more than 5 elements to your array. Whether this is a bug or a feature, it makes for some very nasty bugs. Waiting for this to be corrected, I advice you to initialise your arrays with the maximum size allowed, directly on the Awake function of a script:

Some users reported that once the arrays have been initialised, you need to restart the editor to be able to reset their size. Well, now you’ve been warned…


Don't miss the next tutorial!

There's a new post every Wednesday: leave your email to be notified!


Ways to Support

In the past months I've been dedicating more and more of my time to the creation of quality tutorials, mainly about game development and machine learning. If you think these posts have either helped or inspired you, please consider supporting this blog.

PatreonBecome a Patron Oo4th_patreon_name
PaypalDonate on PayPal
Twitter_logoFollow on Twitter

Write a Comment

Comment

  1. I’m working with somewhat large dataset.
    At first I’ve noticed there’s an array size limit on cg (it’s mentioned on nvidia web site, but I didn’t see the exact size limit) – could you elaborate on this subject?
    I’m able to have an array size of 2000 without compilation errors.
    But it seems I’m unable to read values of this array at places greater than 1023.
    Any help on this subject would be appreciated. Thanks for the great tutorials.

    • Hey!
      Yes, the size of arrays in shaders is definitely limited.
      I don’t think this is something you can change from Unity, unfortunately.
      However, you could split your render mesh in multiple quads, each one with a different material. You can check which points ends up in which quad, and assign only them.
      As long as no quad has more than 1023 points in it, it should work!

Webmentions

  • Unity3D: Tutoriais e Documentação de Shaders | February 15, 2017

    You’re welcome! 🙂

  • Arrays & shaders: heatmaps in Unity - Alan Zucconi February 15, 2017

    You’re welcome! 🙂