Shader renders in Play Mode but not in build (Metal)

I wrote a volumetric fog shader that samples from a 3D texture, generated at runtime in a compute shader. In a Mac build, the 3D texture is seemingly not filled, even though in Editor Play Mode on a Mac it works perfectly fine – even though both presumably use Metal.

The texture is initialized here:

    private void GenerateFogTexture() {
        int worleyKernelHandle=fogComputeShader.FindKernel("CalcWorleyTexture3D");
        RenderTexture worleyTexture=new RenderTexture(128,128,0,RenderTextureFormat.ARGB32); //powers of 2 <-- I actually assign only RGB, does that matter?
        worleyTexture.dimension=UnityEngine.Rendering.TextureDimension.Tex3D;
        worleyTexture.volumeDepth=32;
        worleyTexture.enableRandomWrite=true;
        worleyTexture.Create();
        fogComputeShader.SetTexture(worleyKernelHandle,"worleyTexture",worleyTexture); //transfer data to GPU
        fogComputeShader.Dispatch(worleyKernelHandle,128/8,128/8,32/2); //number of threads specified here times number in compute shader should match pixel count
        worleyTexture.wrapMode=TextureWrapMode.Repeat;
        noiseMaterial.SetTexture("_WorleyTex",worleyTexture);
        int simplexKernelHandle=fogComputeShader.FindKernel("CalcSimplexTexture3D");
        RenderTexture simplexTexture=new RenderTexture(48,48,0,RenderTextureFormat.R8); //multiples of 6
        simplexTexture.dimension=UnityEngine.Rendering.TextureDimension.Tex3D;
        simplexTexture.volumeDepth=48;
        simplexTexture.enableRandomWrite=true;
        simplexTexture.Create();
        fogComputeShader.SetTexture(simplexKernelHandle,"simplexTexture",simplexTexture); //transfer data to GPU
        fogComputeShader.Dispatch(simplexKernelHandle,48/4,48/4,48/4); //number of threads specified here times number in compute shader should match pixel count
        simplexTexture.wrapMode=TextureWrapMode.Repeat;
        noiseMaterial.SetTexture("_SimplexTex",simplexTexture);
    } //GenerateFogTexture

And the compute shader is:

#pragma kernel CalcWorleyTexture3D
#pragma kernel CalcSimplexTexture3D

#include "Noise.cginc"

RWTexture3D<float3> worleyTexture; //rgb
RWTexture3D<float> simplexTexture; //single channel

[numthreads(8,8,2)]
void CalcWorleyTexture3D(uint3 id:SV_DispatchThreadID) {
    worleyTexture[id.xyz]=float3(WorleyNoise3d(0.125*id.xyz,int3(16,16,4)),
                                 WorleyNoise3d(0.25*id.xyz,int3(32,32,8)),
                                 WorleyNoise3d(0.5*id.xyz,int3(64,64,16)));
} //CalcWorleyTexture3D

[numthreads(4,4,4)]
void CalcSimplexTexture3D(uint3 id:SV_DispatchThreadID) {
    //simplexTexture[id.xyz]=SimplexNoise3dFbm(id.xyz);
    simplexTexture[id.xyz]=PeriodicSimplexNoise3d(id.xyz);
} //CalcSimplexTexture3D

The texture is sampled in a shader (NoisyFog) through a sampler3D with tex3D. The Editor does produce a warning, but I cannot make sense of why:
Metal: Shader[CosmoDM/NoisyFog]: Incompatible texture type [MTLTextureType2D] of texture bound at index 0, expected [MTLTextureType3D]

Does anyone know what causes the error, or why it works in the editor but not in the build?

Bumping in the hope anyone has an answer, was stuck on this for a week before posting so I’m really at a loss now…

Hi!
Can you post the CosmoDM/NoisyFog source?

Sure, here it is:

Shader "CosmoDM/NoisyFog" { //Volumetric fog
    Properties {
        _FogColor("Fog color",Color)=(1,1,1,0)
        _FogHeight("Fog height",Float)=10 //thickness in units on top of water level
        _FogScale("Fog scale",Float)=0.004 //scale between world units and texture units, smaller means larger "clouds"
        _DepthScale("Depth scale",Float)=0.00001 //squared scale for thickening with distance
        _FogDensity("Fog density",Float)=0.01 //max optical depth per 1 unit
        _NumSteps("Number of steps",Int)=6
        _WorleyTex("Worley texture",3D)="" {}
        _SimplexTex("Simplex texture",3D)="" {}
    } //Properties

    SubShader {
        Tags { "RenderType"="Transparent" "Queue"="Transparent+1" "IgnoreProjector"="True" }
        LOD 200
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.5

            #include "UnityCG.cginc"

            static const float maxDist=128;
            float _WaterHeight=-7;

            struct appdata { //input
                float4 pos:POSITION; //vertex position
                //float2 uv:TEXCOORD0; //uv coordinates
            }; //appdata

            struct v2f { //output of vert, input to frag
                float4 pos:SV_POSITION; //clip space position (projected space)
                float3 worldPos:TEXCOORD1; //everything needs a semantic
                //float2 uv:TEXCOORD0;
            };

            fixed4 _FogColor;
            float _FogHeight;
            static float invFogHeight=1.0/_FogHeight;
            float _FogScale;
            float _DepthScale;
            float _FogDensity;
            int _NumSteps;
            static float invNumSteps=1.0/_NumSteps;
            sampler3D _WorleyTex;
            float4 _WorleyTex_ST;
            sampler3D _SimplexTex;
            float4 _SimplexTex_ST;

            // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
            // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
            // #pragma instancing_options assumeuniformscaling
            UNITY_INSTANCING_BUFFER_START(Props)
                // put more per-instance properties here
            UNITY_INSTANCING_BUFFER_END(Props)

            v2f vert(appdata i) {
                v2f o;
                o.pos=UnityObjectToClipPos(i.pos.xyz);
                o.worldPos=mul(unity_ObjectToWorld,i.pos).xyz;
                //o.uv=i.uv;
                return o;
            } //vert

            float4 frag(v2f i):SV_TARGET { //tells GPU to interpret the output float4 as an SV_TARGET
                float4 color=_FogColor;
                float3 dir=normalize(i.worldPos-_WorldSpaceCameraPos);
                float invDiry=maxDist;
                if (dir.y!=0) invDiry=1/dir.y;
                float waterDist=(_WaterHeight-i.worldPos.y)*invDiry;
                if (waterDist<=0) {
                    if (i.worldPos.y<_WaterHeight) waterDist=0;
                    else waterDist=maxDist;
                } //if
                float stepSize=waterDist*invNumSteps;
                float3 currentPos=i.worldPos;
                float3 offset1=float3(0,0.5*_Time.x,0);
                float3 offset3=float3(0,0.125*_Time.x,0);
                float fogAmount=0;
                for (int i=0; i<_NumSteps; ++i) {
                    float3 scaledPos=_FogScale*currentPos;
                    fogAmount+=0.333*(tex3D(_WorleyTex,scaledPos-offset1).r+
                                      tex3D(_WorleyTex,scaledPos-offset3).b+
                                      tex3D(_SimplexTex,scaledPos))*
                                      exp(-(currentPos.y-_WaterHeight)*invFogHeight)*
                                      exp((currentPos.x*currentPos.x+currentPos.z*currentPos.z)*_DepthScale);
                    currentPos+=stepSize*dir;
                } //for
                color.a=1-exp(-_FogDensity*fogAmount*stepSize);
                return color;
            } //frag
            ENDCG
        } //Pass
    } //Subshader
    FallBack "CosmoDM/WaterFog"
} //NoisyFog

Note that the loop and all that actually don’t matter for the Metal warning. If I set the output colour to any aspect of the sampled 3D textures, I get the same warning.

Not allowed to edit the post above, so new post… It now actually does work in the build in the same way as in the editor. All I changed was making the 3D textures properties as you see in the shader above, this somehow only mattered for the build… However, I still get the warning about receiving a 2D texture when 3D was expected.

This warning means “shader expects a 3D texture, but a 2D texture was bound”.
If you can’t spot anything like that in your code, I would suggest filing a bug report.