Grass Compute shader appearing pink in mobile.

I have been trying out a grass compute shader by minionsart from patreon and it works awesome in pc but even though my mobile supports compute shaders, The grass appears pink on a sphere with no wind sway while it should have been all over a plane moving with the wind. if the shader code is important in analyzing this, please tell me.
Here are some images…



Did you try in windows standalone build?
If not there put the shader in always included shaders

1 Like

Mobile often can’t handle as many thread groups etc as desktop. My guess is you exceeded a limit. SystenInfo has methods to check all the limits for the platform.

1 Like

Yes but the shader works fine when put in unity remote in my mobile but when i build the games apk, this happens.

It works fine in the windows standalone build.

and by the way, I use URP (LWRP)

URP or LWRP?
And what unity version? Tried the latest lts already?

Oh wait, do you use vulkan? openGL doesn’t support compute shaders well

Just in case you’re not aware Unity Remote doesn’t actually run your application on your mobile device. Instead it’s running your application on your PC and simply passing the rendered output of the PC to the mobile device and the inputs of the mobile device back to the PC.

You could also check Shader.isSupported

You should check the device logs - there should be a message that details what didn’t work out.

I use URP unity 2021.3.4f1 and after you posted this, i found that vulcan wasn’t added to my graphics api list in project settings so when I tried to put it on, unity crashed.

Oh… I didn’t know that since i’m a beginner to developing to mobile.

I will try that.

Yes you are right… I found the device log via command prompt and this is the error GLSL link error: The number of vertex shader storage blocks (1) is greater than the maximum number allowed (0). How do I fix this?

You can’t fix this using this shader. The message says “your GPU cannot read data from ComputeBuffers in Vertex Shaders”. You’ll need a different implementation of the effect.
You can check whether it’s supported on the given hardware by checking https://docs.unity3d.com/ScriptReference/SystemInfo-maxComputeBufferInputsVertex.html

The error above is from one of the grass shader files. Here is the code.

Shader "Custom/GrassComputeHLSL"
{
    Properties
    {
        [Toggle(BLEND)] _BlendFloor("Blend with floor", Float) = 0
        _Fade("Top Fade Offset", Range(-1,10)) = 0
        _AmbientAdjustment("Ambient Adjustment", Range(-1,10)) = 0
    }
   
    HLSLINCLUDE
    // Include some helper functions
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
   
    // This describes a vertex on the generated mesh
    struct DrawVertex
    {
        float3 positionWS; // The position in world space
        float2 uv;
        float3 diffuseColor;
    };
   
    // A triangle on the generated mesh
    struct DrawTriangle
    {
        float3 normalOS;
        DrawVertex vertices[3]; // The three points on the triangle
    };
   
    // A buffer containing the generated mesh
    StructuredBuffer<DrawTriangle> _DrawTriangles;
   
    struct v2f
    {
        float4 positionCS : SV_POSITION; // Position in clip space
        float2 uv : TEXCOORD0;          // The height of this vertex on the grass blade
        float3 positionWS : TEXCOORD1; // Position in world space
        float3 normalWS : TEXCOORD2;   // Normal vector in world space
        float3 diffuseColor : COLOR;
        float fogFactor : TEXCOORD5;
    };
   
    float4 _TopTint;
    float4 _BottomTint;
    float _Fade;
    float4 _PositionMoving;
    float _OrthographicCamSize;
    float3 _OrthographicCamPos;
    uniform sampler2D _TerrainDiffuse;
    float _AmbientAdjustment;
    // ----------------------------------------
   
    // Vertex function
   
    // -- retrieve data generated from compute shader
    v2f vert(uint vertexID : SV_VertexID)
    {
        // Initialize the output struct
        v2f output = (v2f)0;
       
        // Get the vertex from the buffer
        // Since the buffer is structured in triangles, we need to divide the vertexID by three
        // to get the triangle, and then modulo by 3 to get the vertex on the triangle
        DrawTriangle tri = _DrawTriangles[vertexID / 3];
        DrawVertex input = tri.vertices[vertexID % 3];
       
        output.positionCS = TransformWorldToHClip(input.positionWS);
        output.positionWS = input.positionWS;
       
        float3 faceNormal = GetMainLight().direction * tri.normalOS;
        output.normalWS = TransformObjectToWorldNormal(faceNormal, true);
        float fogFactor = ComputeFogFactor(output.positionCS.z);
        output.fogFactor = fogFactor;
        output.uv = input.uv;
       
        output.diffuseColor = input.diffuseColor;
       
        return output;
    }
   
    // ----------------------------------------
   
    // Fragment function
   
    half4 frag(v2f i) : SV_Target
    {
        // For Shadow Caster Pass
        #ifdef SHADERPASS_SHADOWCASTER
            return 0;
        #else
            // For Color Pass
            // rendertexture UV for terrain blending
            float2 uv = i.positionWS.xz - _OrthographicCamPos.xz;
            uv = uv / (_OrthographicCamSize * 2);
            uv += 0.5;
           
            // get ambient color from environment lighting
            float4 ambient =float4(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w,1); //float4(ShadeSH9(float4(0,0,1,1)),0);
           
            float shadow = 0;
            #if BLEND
                shadow = 1;               
            #endif
           
           
            half4 shadowCoord = TransformWorldToShadowCoord(i.positionWS);
           
            #if _MAIN_LIGHT_SHADOWS_CASCADE || _MAIN_LIGHT_SHADOWS
                Light mainLight = GetMainLight(shadowCoord);
                shadow = mainLight.shadowAttenuation;
            #else
                Light mainLight = GetMainLight();
            #endif
           
            // extra point lights support
            float3 extraLights;
            int pixelLightCount = GetAdditionalLightsCount();
            for (int j = 0; j < pixelLightCount; ++j) {
                Light light = GetAdditionalLight(j, i.positionWS, half4(1, 1, 1, 1));
                float3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
                extraLights += attenuatedLightColor;
               
            }
            // fade over the length of the grass
            float verticalFade = saturate(i.uv.y + _Fade);
            extraLights *= verticalFade;
            // colors from the tool with tinting from the grass script
            float4 baseColor = lerp(_BottomTint , _TopTint,verticalFade) * float4(i.diffuseColor, 1);
            // get the floor map
            float4 terrainForBlending = tex2D(_TerrainDiffuse, uv);
           
            float4 final = float4(0,0,0,0);
            #if BLEND     
                _TopTint = _TopTint * ambient; 
                // tint the top blades and add in light color            
                terrainForBlending = lerp(terrainForBlending,terrainForBlending+ ( _TopTint* float4(i.diffuseColor, 1)) , verticalFade);
                final = lerp((terrainForBlending)  * shadow , terrainForBlending, shadow); 
                // add in ambient and attempt to blend in with the shadows
                final += lerp((ambient * terrainForBlending) * _AmbientAdjustment, 0,shadow);
            #else
                final = baseColor;
                // add in shadows
                final *= shadow;
                // if theres a main light, multiply with its color and intensity          
                final *= float4(mainLight.color,1);        
               
                // add in ambient
                final += (ambient * baseColor) ;
            #endif
            final += float4(extraLights,1);
            // fog
            float fogFactor = i.fogFactor;
            // Mix the pixel color with fogColor.
            final.rgb = MixFog(final.rgb, fogFactor);        
            return final;
           
        #endif  // SHADERPASS_SHADOWCASTER
    }
    ENDHLSL
   
    SubShader {
        // UniversalPipeline needed to have this render in URP
        Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "IgnoreProjector" = "True" }
       
        // Forward Lit Pass
        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode" = "UniversalForward" }
            Cull Off // No culling since the grass must be double sided
           
            HLSLPROGRAM
            // Signal this shader requires a compute buffer
            #pragma prefer_hlslcc gles
            #pragma exclude_renderers d3d11_9x
            #pragma target 5.0
           
            // Lighting and shadow keywords
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
            #pragma multi_compile _ _ADDITIONAL_LIGHTS
            #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
            #pragma multi_compile _ _SHADOWS_SOFT
            #pragma multi_compile_fog
            #pragma shader_feature BLEND
            // Register our functions
            #pragma vertex vert
            #pragma fragment frag
           
            ENDHLSL
        }
       
        // Shadow Casting Pass
        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode" = "ShadowCaster" }
            ZWrite On
            ZTest LEqual
            Cull Off
           
            HLSLPROGRAM
            // Signal this shader requires geometry function support
            #pragma prefer_hlslcc gles
            #pragma exclude_renderers d3d11_9x
            #pragma target 5.0
           
            // Support all the various light  ypes and shadow paths
            #pragma multi_compile_shadowcaster
           
            // Register our functions
            #pragma vertex vert
            #pragma fragment frag
           
            // A custom keyword to modify logic during the shadow caster pass
            #define SHADERPASS_SHADOWCASTER
           
            #pragma shader_feature_local _ DISTANCE_DETAIL
           
            ENDHLSL
        }
    }
}

Oh ok then… I will try to change the implementation.

Using vulkan under android might fix this right?

@codevisionary005 did you add vulkan under android or desktop? You can use it for android and use automatic for desktop

@DevDunk Right, it should work on Vulkan if the ComputeBuffer is read-only.

1 Like

One alternative is to use a RenderTexture instead of a ComputeBuffer. They are less flexible to work with, but reading from textures on vertex shaders should be supported on ES 3.0 and up.

2 Likes

I tried to, but wheneven I add vulcan, Unity crashes.

The ComputeBuffer is read-only but as I said earlier, I couldn’t add vulcan since unity crashes.

Do you have any resources for RenderTexture? Because i’m new to shader programming and i’m do not know if it could help me generate grass blades as the computebuffer does.

But unity shouldn’t crash if you change the android API. Unity itself should still run in dx11 in that case. Do make a bug report (after trying the latest LTS of your unity version) for it since it shouldn’t happen

Good news. After @DevDunk told me to try the latest LTS of my unity version, I tried it. It didn’t work, but then I tried 2021.3.0f1 which is a version older than what I currently use, The shader now works!:smile: Thank you for all your help, I will be changing the thread’s tag to resolved.

1 Like