Changing Shader values during runtime

Hi everyone, I’m very new to working with Shaders but what I’m trying to do is change an index by using the _Time that is provided which will cycle through different textures in a 2DTextureArray and make the shader almost like an animation. I can change the index in the inspector when Unity runs and it functions properly, but I can’t figure out where to change the _index value in the code. This is for an assignment and it must be done in the Shader since I’m not allowed to use outside scripts to modify these values. Any help would be appreciated, thanks!

Here is the code:

Shader "Custom/AnimationShader"
{
    Properties
    {
        _index ("Texture Index", Float) = 0.0
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _NormalTex ("Normal Map", 2D) = "bump" {}
        _NormalMapIntensity("Normal Intensity", Range(0,1)) = 1
        //Lava 2D array stuff
        _LavaArray("Lava Array", 2DArray) = "" {}
        _LavaSliceRange ("Slices", Range(0,16)) = 9
        _LavaUVScale ("UVScale", Float) = 1.0
        //Normal mapping array stuff
        _NormalMapArray("Normal Map Array", 2DArray) = "" {}
        _NormalMapSliceRange ("Slices", Range(0,16)) = 9
        _NormalMapUVScale ("UVScale", Float) = 1.0
    }
    SubShader
    {
    Pass
    {
    Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        //#pragma surface surf Standard
        #pragma vertex vert
        #pragma fragment frag
        // texture arrays are not available everywhere,
        // only compile shader on platforms where they are
        #pragma require 2darray
        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 4.0//want 4.0 to support for loops

        #include "UnityCG.cginc"

        sampler2D _MainTex;
        sampler2D _NormalTex;
        float4 _MainTint;

        struct Input
        {
            float2 uv_NormalTex;
            float2 uv_MainTex;
        };

        // vertex input: position, UV
        struct appdata {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
        };

        struct v2f
        {
            float3 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
        };

        float _LavaSliceRange;
        float _LavaUVScale;
        float _index;

        v2f vert (appdata v) {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex );
            //This is where I was trying to change the value of _index, it's just kind of pseudocode of how I would do it
            float resetTime = 30;
            float zero = 0;
            for(resetTime; resetTime >= zero;resetTime--)
            {
                _index++;
                if (_index >= 9)
                {
                    _index = 0;
                }
                o.uv = float3( v.texcoord.xy, _index );
            }
            return o;
        }
           
        UNITY_DECLARE_TEX2DARRAY(_LavaArray);
        UNITY_DECLARE_TEX2DARRAY(_NormalMapArray);
       

        half4 frag (v2f i) : SV_Target
        {
            float3 texUVZ = float3(i.uv[0],i.uv[1],_index); //making the float3 with the uv coordinates and the index of the 2d texture array

            return UNITY_SAMPLE_TEX2DARRAY(_LavaArray,texUVZ); //macro that samples the texture array with a float3 UV, and the z component being the array element index
        }

        // 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)

        ENDCG
        }
    }
    FallBack "Diffuse"
}

You can’t do what you’re trying to do. This simply isn’t how shaders work.

Each invocation of the shader, which is once for each vertex for the vertex shader stage, and once for each on screen pixel for the fragment shader stage, runs with a copy of the data. While you can “modify” the _Index value in the shader, in reality you’re modifying a local value that’s a copy of _Index for that unique invocation, and the value is thrown out as soon as that vertex or fragment is finished. Generally speaking the data that comes into a shader is a temporary copy and the only output is either those that are then passed onto the fragment shader from the vertex shader via the interpolator semantics (the stuff defined in the v2f struct), or as the on screen pixel color. That’s it.

Technically you can use a compute buffer bound as a RWStructredBuffer to read and write data to it from anywhere in the shader, but there’s caveats to that, and for something like a Surface Shader you’ll be incrementing that value once for every vertex in your mesh.

Instead what you want to do is calculate the current index from the _Time.y directly. If you have 9 total indices (0 through 8), and you want it to iterate through each index every 30 seconds, then you can do something like this:

float resetTime = 30;
float maxIndex = 9;
float index = floor(fmod(_Time.y / resetTime, maxIndex));
o.uv = float3(v.texcoord.xy, index);