I am working on a procedural interior mapping shader in Unity's Shader Graph. Ideally, I'd like to feed it a set of cubemaps it can pick from semi-randomly.

However, it seems that by default the texture array asset one can provide to a graph does not support reading cubemaps.

Does anyone have a way to use this, or perhaps a clever custom node or alternate texture mapping, so that I can read a number of cubemaps into the shader semi-randomly? Preferably an arbitrary number, but even a fixed number would be somewhat of an improvement.

  • \$\begingroup\$ Have you tried using a custom shader code node to just write the code you want it to execute directly? \$\endgroup\$ – DMGregory Mar 3 at 12:21
  • \$\begingroup\$ @DMGregory I don't believe custom input types are generally possible? And I am not a wiz at actually writing shader code (hence my use of SG at all, really). Perhaps I'm a little tunnel visioned because of it. \$\endgroup\$ – Weckar E. Mar 3 at 14:50

We can use the Custom Function Node to work around limitations of the existing node types.

First, we'll make a new text file somewhere in our Assets folder. I called mine "CubeMapArray.cginc". Inside we can put just these nine lines of code:


void sample_cube_array_float(SamplerState ss, float3 coord3, float index, out float4 result) {
    result = SAMPLE_TEXTURECUBE_ARRAY(_CubeArray, ss, coord3, index);

void sample_cube_array_half(SamplerState ss, half3 coord3, half index, out half4 result) {
    result = SAMPLE_TEXTURECUBE_ARRAY(_CubeArray, ss, coord3, index);

You can see this defines a uniform variable _CubeArray that represents an array of cubemaps. Then it defines two versions of a function to sample that array - one at full float precision, and one at half precision. (I looked up the macros to use from this file)

Inside the shader graph editor, we'll create a new Custom Function Node and configure it like so:

Configuring Custom Function Node

Now unfortunately since we had to smuggle in our cubemap array texture via a uniform declared in code, we can't just assign the maps through the inspector. So we'll use a short C# script to copy our cubemaps into one texture array and assign that:

public class CubeMapArrayTest : MonoBehaviour
    public Cubemap[] maps;

    CubemapArray _array;
    Material _material;

    private void Start() {
        if (!SystemInfo.supportsCubemapArrayTextures) {
            Debug.LogError("System does not support cubemap array textures - this will not work!");

        _array = new CubemapArray(maps[0].width, maps.Length, maps[0].format, true);

        for (int i = 0; i < maps.Length; i++)
            for (int j = 0; j < 6; j++)
                Graphics.CopyTexture(maps[i], j, _array, 6*i+j);

        _material = GetComponent<Renderer>().material;

        _material.SetTexture("_CubeArray", _array);

    private void OnDestroy() {
        if (_material != null) {

On my machine this displays an error and warning in the console:

🛑 Shader error in 'hidden/preview/CustomFunction_DD7E970E': TextureCubeArray textures aren't supported on this target at Assets/ShaderEffects/CubeMapArray.cginc(1) (on d3d11)

⚠️ Shader warning in 'hidden/preview/CustomFunction_DD7E970E': 'TransformObjectToWorld': implicit truncation of vector type at line 85 (on d3d11)

But the shader still works correctly anyway. 😕 I'd love some insight into why that is and how to resolve or suppress those messages for peace of mind, but they don't seem to be an obstacle to solving the problem at least.

  • \$\begingroup\$ Works like a charm. If I figure out why those errors happen I'll let you know... \$\endgroup\$ – Weckar E. Mar 4 at 4:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.