How to get particle index id from unlit shader

I have a particle system with X particles, and I need to access each particle’s index from an unlit shader. Preferably from 0 to X-1

How would I go about this? I tried the VertexID custom vertex stream but I don’t think that’s correct.

I also heard about using SV_InstanceID, but I have no idea how to access this value in the vert shader. Any help is greatly appreciated.

It’ll be VertexID / 4.

Just add:
uint VertexID : SV_VertexID;
to your appdata Vertex input struct in the shader.

1 Like

It worked! Thank you so much.

1 Like

I’m having trouble using VertexID. It definitely gives an index value, but it doesn’t seem to correspond to the particle system. I’m trying to output a 200x200 rectangle of particles, with a gradient that goes from black to red with each subsequent particle.

I have a particle system that immediately emits 40,000 particles at start, with an Infinite lifetime.

In the particle system vertex shader I have the following code:

v2f o;
int size = 200;
uint particle_id = v.VertexID/4;

float2 pos= float2(particle_id % size, particle_id / size) / float2(size, size);

o.color = float4(float(particle_id) / 40000, 0,0,1);
v.vertex.xyz += pos;

In the uploaded screenshot, you can see that it doesn’t reach the full red value. Is there something I’m doing wrong?

6506292--732810--Screenshot 2020-11-09 125934.png

Shouldn’t you assign the pos instead of adding it to v.vertex.xyz?

Hard to say what the problem might be from only that small bit of shader code though.

Here’s the full shader. If you could take a quick look I’d really appreciate it.

When I assign pos to vertex.xyz nothing shows up, but when I add it then the particles appear. I’m not really sure why it’s doing that. If it matters, I’m using Unity 2019.4.12.

Shader "Unlit/PointCloudShaderDebug"
{
    Properties
    {
        _MainTex ("Particle Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" "RenderType"="Opaque" }
        LOD 100
     
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_particles
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                fixed4 color : COLOR;
                float2 uv : TEXCOORD0;
                uint VertexID : SV_VertexID;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 uv : TEXCOORD0;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                int size = 200;
                uint particle_id = v.VertexID/4;

                float2 pos = float2(particle_id % size, particle_id / size) / float2(size, size);

                o.color = float4(float(particle_id) / float(size*size), 0,0,1);

                v.vertex.xyz += float3(pos.x, pos.y, 0);

                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                return i.color * tex2D(_MainTex, i.uv);
            }
            ENDCG
        }
    }
}

@richardkettlewell And what if we have mesh particles with different amount of vertexes?

The incoming vertex contains the default positional data. It looks like you are replacing it with vertex data that would put all particles at 0,0,0 in the world.

Probably the correct solution is to use the Custom Vertex Streams feature in the renderer module, send the Center stream in, and set v.vertex as Center.xyz + float3(pos.x, pos.y, 0).

Sorry what is your question?

Your answer to ParticleID is to / 4 the VertexID. But if we have mesh-based particles with different amount of vertexes for each mesh, then how do we get ParticleID? I assume meshes are selected randomly for each particle.

Hmm that’s not so easy.
We have a custom vertex stream called MeshIndex. So you can use that to know which mesh the vertex belongs to, so you can use the appropriate mesh count. You’d have to pass the mesh counts in a Vector4 or something.

Or if you’re using a gpu instanced shader, the particle ID would be available as the InstanceID. Custom instanced particle shaders are quite advanced to set up tho, and only work on certain hardware.