How would you create a data-driven gradient "overlay"?

I am trying to acheive something similar to this image, in a RTS game. I have about 100,000 data points I am trying to blend colors between to visually represent a sort of heatmap, if you will. All values are between 0 and 1. Each “point” on the map has a data item that is between 0 and 1 and I’d like to have values over a certain threshold turn yellow or similar, and then get darker orange/red as the value increases.

I have tried so many different things including writing my own shader, using meshes and spawning them at each location, but I cant get the same effect. Does anyone have a link to a tutorial that could help?

are your data-points arranged in a regular grid or are they located at random (and randomly spaced) locations?

They are in a grid. And that is one of the issues I’m having. I tried doing this with both meshes and shaders but I can’t get anything close to the image above. Either it looks “too grid-like” and everything is perfectly symmetrical, whereas the image above is not fully uniform and has some nice transparency/fall of as it gets near the edges, or everything is very repetitive looking.

I’ll give an example - I followed the alan zucconi heatmap tutorial located here, which has been talked about a lot on this forum:
https://www.alanzucconi.com/2016/01/27/arrays-shaders-heatmaps-in-unity3d/

And when I follow that, since my data is arranged in a grid, and in his shader he is doing a calculation of distance from each point to get a “weight” of the heat, it results in these perfectly symmetrical repeating circles across the map because of the circular radius and distance from my grid points. It doesn’t look good. It looks nothing like the image above. Because in his tutorial he is using randomly generated points and weights that give it that random look, and my data is laid out in a grid it becomes very repetitive looking.

I tried just throwing some random extra points into my array that is sent to the shader to give it some randomness, but the problem with that is there is a limit to the amount of data that can be in the array. I think its 1,023 points. I dont have any extra to work with. I already need multiple arrays just to hold all the data I need for the size of my map to show the entire heatmap. It also isnt a true representation of the data if I’m including fake data to make it look more natural.

you mean you’re passing your data points as uniform array to the shader? why not as a texture or as vertex attributes?

Can you show one of your results? it might be easier to help you how to fix what you already have

Sure,
Here is one example from the tutorial above. Again, the issue is the fact that in his tutorial the “intensity” and location of the points is randomized. With my grid its laid out in a uniform way so its making the whole thing look like its perfectly symetrical.

I posted the code for the shader below. I believe what its doing, is for each pixel its looping through each data point and getting the radius + intensity and then adding it to the “h” value to determine what color to make the texture.

In the shader code you can see there is a “dist” calculation that is essentially calculating, for each pixel, the distance to these points, which is making everything be circular, if that makes sense. Picture a circle of a “dist” radius around each item in the _Point array so when it checks each pixel the distance within that radius is always close enough to make it a color.

There is also a c# sharp script where I am passing the array values with radius, location, and intensity of each point. So you can see in this image the more intense items are in the center and I pass in less intensity in the surrounding grid tiles.

7889404--1004080--upload_2022-2-11_10-17-3.png

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

// Alan Zucconi
// www.alanzucconi.com
Shader "Hidden/Heatmap" {
        Properties{
            _HeatTex("Texture", 2D) = "white" {}
        }
            SubShader{
            Tags{ "Queue" = "Transparent" }
            Blend SrcAlpha OneMinusSrcAlpha // Alpha blend

            Pass{
            CGPROGRAM
#pragma vertex vert        
#pragma fragment frag

        struct vertInput {
            float4 pos : POSITION;
        };

        struct vertOutput {
            float4 pos : POSITION;
            fixed3 worldPos : TEXCOORD1;
        };

        vertOutput vert(vertInput input) {
            vertOutput o;
            o.pos = UnityObjectToClipPos(input.pos);
            o.worldPos = mul(unity_ObjectToWorld, input.pos).xyz;
            return o;
        }

        float random (float2 uv)
        {
            return frac(sin(dot(uv,float2(12.9898,78.233)))*43758.5453123);
        }

        uniform int _Points_Length = 0;
        uniform float4 _Points[1000];        // (x, y, z) = position
        uniform float4 _Properties[1000];    // x = radius, y = intensity

        sampler2D _HeatTex;

        half4 frag(vertOutput output) : COLOR{
            // Loops over all the points
            half h = 0;
        for (int i = 0; i < _Points_Length; i++)
        {
            // Calculates the contribution of each point
            half di = distance(output.worldPos, _Points[i].xyz);
            //half di_y = distance(output.worldPos.y, _Points[i].y);
            //half di_x = distance(output.worldPos.x, _Points[i].x);


            half ri = _Properties[i].x;
            half hi = 1 - saturate(di / ri);

            h += hi * _Properties[i].y;
            //h += hi * (_Properties[i].y / 5);
        }

        // Converts (0-1) according to the heat texture
        h = saturate(h);
        half4 color = tex2D(_HeatTex, fixed2(h, 0.5f));
        return color;
        }
            ENDCG
        }
        }
            Fallback "Diffuse"
    }

I also tried another method just placing planes of different colors at each data point but the problem is there is no gradient transition between them. It’s just large squares of different colors all over the place.

Would you happen to have a link or example to how I could accomplish this with a vertex attributes or texture as you described above?

I’d love to get away from needing to pass this array (_Points in above script) in of tens of thousands of data points and have the shader have to loop through them all. It doesnt seem very efficient.