1
\$\begingroup\$

I am using radiosity method to compute the inter-reflected light within a room. The room is gridded into small patches and the light flux in lumen is calculated for each. This part is done. Now I want to change the colour of each patch so that the room surfaces show a continuous colour banding contours like this image, but have no clue how to this.

enter image description here

Update:

Here is a sample data for a room surface. The data is in this format: (x, y): value

\$\endgroup\$
5
  • \$\begingroup\$ You need to provide more information on your data. \$\endgroup\$
    – jgallant
    Commented Jun 4, 2016 at 15:43
  • \$\begingroup\$ Thanks Jon. The data is(for each surface sub patch) the ratio of the total flux received by the patch to the total lamp flux. \$\endgroup\$
    – ali
    Commented Jun 4, 2016 at 18:22
  • \$\begingroup\$ Thanks. Room surfaces are divided into grid squares of 0.3mx0.3m and the value for the centre of each grid cell is computed. Patches values vary between 0-5. The closer the surface to the source of light(ex. the window) the higher the value. Towards the end of the room values linearly go down to zero. \$\endgroup\$
    – ali
    Commented Jun 6, 2016 at 8:20
  • \$\begingroup\$ @ali just give Jon some sample data, what's so difficult about that? \$\endgroup\$
    – user35344
    Commented Jun 6, 2016 at 11:32
  • \$\begingroup\$ @Jon sorry guys I updated a link to sample data. \$\endgroup\$
    – ali
    Commented Jun 6, 2016 at 16:06

1 Answer 1

5
\$\begingroup\$

Here is a little help on getting you started with this rendering. This may not be the best way to accomplish this task however, it should work.

First I created a structure to hold your data for parsing from text file:

public struct Data {

    public Data(float x, float y, float value){
        X = x;
        Y = y;
        Value = value;
    }

    public float Value;
    public float X;
    public float Y;
}

I then initialized the color palette based on your above image (reversed because I messed up the ordering initially):

Color[] Colors;

private void InitColors()
{
    Colors = new Color[20];

    Colors [19] = new Color (230 / 255f, 29 / 255f, 0 / 255f, 1);
    Colors [18] = new Color (230 / 255f, 74 / 255f, 0 / 255f, 1);
    Colors [17] = new Color (230 / 255f, 119 / 255f, 0 / 255f, 1);
    Colors [16] = new Color (230 / 255f, 164 / 255f, 0 / 255f, 1);
    Colors [15] = new Color (230 / 255f, 207 / 255f, 0 / 255f, 1);
    Colors [14] = new Color (185 / 255f, 207 / 255f, 0 / 255f, 1);
    Colors [13] = new Color (140 / 255f, 207 / 255f, 0 / 255f, 1);
    Colors [12] = new Color (94 / 255f, 207 / 255f, 0 / 255f, 1);
    Colors [11] = new Color (49 / 255f, 207 / 255f, 23 / 255f, 1);
    Colors [10] = new Color (3 / 255f, 207 / 255f, 73 / 255f, 1);
    Colors [9] = new Color (0 / 255f, 207 / 255f, 173 / 255f, 1);
    Colors [8] = new Color (0 / 255f, 198 / 255f, 223 / 255f, 1);
    Colors [7] = new Color (0 / 255f, 153 / 255f,  230 / 255f, 1);
    Colors [6] = new Color (0 / 255f, 108 / 255f, 230 / 255f, 1);
    Colors [5] = new Color (0 / 255f, 63 / 255f, 230 / 255f, 1);
    Colors [4] = new Color (37 / 255f, 18 / 255f, 230 / 255f, 1);
    Colors [3] = new Color (82 / 255f, 0 / 255f, 230 / 255f, 1);
    Colors [2] = new Color (128 / 255f, 0 / 255f, 230 / 255f, 1);
    Colors [1] = new Color (173 / 255f, 0 / 255f, 230 / 255f, 1);
    Colors [0] = new Color (219 / 255f, 1 / 255f, 230 / 255f, 1);
}

I then wrote a parsing function to get the data from your text file into memory, and analyze parts of the data for future use:

private HashSet<float> XValues;
private HashSet<float> YValues;

private List<Data> DataList;

private float Min, MinX, MinY;
private float Max, MaxX, MaxY;

private void ParseData()
{
    Min = float.MaxValue;
    Max = float.MinValue;
    MinX = float.MaxValue;
    MaxX = float.MinValue;
    MinY = float.MaxValue;
    MaxY = float.MinValue;

    DataList = new List<Data> ();
    XValues = new HashSet<float> ();
    YValues = new HashSet<float> ();

    if (File.Exists ("data.txt")) {

        StreamReader file = new StreamReader ("data.txt");
        string line = "";

        while ((line = file.ReadLine ()) != null) {

            line = line.Replace("(", string.Empty);
            line = line.Replace(")", string.Empty);
            line = line.Replace(":", ",");
            string[] split = line.Split (',');

            float x = System.Convert.ToSingle(split [0]);
            float y =  System.Convert.ToSingle(split [1]);
            float value =  System.Convert.ToSingle(split [2]);

            Data data = new Data (x, y, value);

            Min = Mathf.Min (Min, value);
            Max = Mathf.Max (Max, value);
            MinX = Mathf.Min (MinX, x);
            MaxX = Mathf.Max (MaxX, x);
            MinY = Mathf.Min (MinY, y);
            MaxY = Mathf.Max (MaxY, y);

            XValues.Add (x);
            YValues.Add (y);

            DataList.Add (data);
        }

        file.Close ();
    }
}

Now it is easy to convert the parsed data into a Dataset that we can use:

private Data[,] Data;

private void GenerateDataSet()
{
    Data = new Data[XValues.Count, YValues.Count];

    for (int x = 0; x < XValues.Count; x++) {
        for (int y = 0; y < YValues.Count; y++) {
            Data [x, y] = DataList [x + y * XValues.Count];
        }
    }   
}

If we visualize this data now, we get the following:

enter image description here

In order to smooth this out, we are going to add values in between and interpolate based on the distance between known node values:

float[,] Interpolated;

private void Interpolate()
{
    int steps = 25;

    Interpolated = new float[Data.GetLength (0) * steps, Data.GetLength (1) * steps];

    for (int y = 0; y < Interpolated.GetLength (1) - steps; y++) {

        for (int x = 0; x < Interpolated.GetLength (0) - steps; x++) {

            int x1 = x / steps;
            int x2 = x1 + 1;
            int y1 = y / steps;
            int y2 = y1 + 1;

            float distance1 = (new Vector2 (x, y) - new Vector2 (x1 * steps, y1 * steps)).magnitude;
            float distance2 = (new Vector2 (x, y) - new Vector2 (x1 * steps, y2 * steps)).magnitude;
            float distance3 = (new Vector2 (x, y) - new Vector2 (x2 * steps, y1 * steps)).magnitude;
            float distance4 = (new Vector2 (x, y) - new Vector2 (x2 * steps, y2 * steps)).magnitude;

            float value1 = Data [x1, y1].Value;
            float value2 = Data [x1, y2].Value;
            float value3 = Data [x2, y1].Value;
            float value4 = Data [x2, y2].Value;

            int totalCount = 0;

            int count = steps - (int)distance1;
            count = Mathf.Max (count, 0);
            float total = value1 * count;
            totalCount += count;

            count = steps - (int)distance2;
            count = Mathf.Max (count, 0);
            total += value2 * count;
            totalCount += count;

            count = steps - (int)distance3;
            count = Mathf.Max (count, 0);
            total += value3 * count;
            totalCount += count;

            count = steps - (int)distance4;
            count = Mathf.Max (count, 0);
            total += value4 * count;
            totalCount += count;

            total = total / (float)totalCount;

            Interpolated [x, y] = total;
        }
    }
}

Now if we draw this interpolated data, we get something that looks a lot more like what you are trying to output. Here is the Texture generation code that was used:

public Texture2D GetHeatMapTexture()
{
    int width = Interpolated.GetLength (0);
    int height = Interpolated.GetLength (1);

    var texture = new Texture2D (width, height);
    var pixels = new Color[width * height];

    for (var x = 0; x < width; x++)
    {
        for (var y = 0; y < height; y++)
        {               
            float value = Interpolated [x,y];

            float normalized = (value - Min) / (Max - Min);
            normalized *= Colors.Length;
            int colorValue = (int)normalized;
            colorValue = Mathf.Clamp (colorValue, 0, 19);

            pixels [x + y * width] = Colors [colorValue];
        }
    }

    texture.SetPixels(pixels);
    texture.wrapMode = TextureWrapMode.Clamp;
    texture.filterMode = FilterMode.Point;
    texture.Apply();
    return texture;
}

And here is what it looks like with your provided dataset:

enter image description here

There are probably better ways to accomplish this result, but at least this can provide you with a way to at least get started doing what it is you are trying to do.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Thanks Jon this is amazing; and sorry I didn't appreciate your asking for sample data first. \$\endgroup\$
    – ali
    Commented Jun 6, 2016 at 20:00
  • \$\begingroup\$ No problem at all. The problem looked like fun to tackle, so that is why I was asking for it. Let me know if you have any questions about the above implementation. \$\endgroup\$
    – jgallant
    Commented Jun 6, 2016 at 20:07
  • \$\begingroup\$ I believe in Java you can initialize a color with all integers out of 255, so you can get rid of the division. \$\endgroup\$
    – Kyranstar
    Commented Jun 21, 2016 at 16:55
  • \$\begingroup\$ @Kyranstar The code above is not java, it is C#. More specifically it is utilizing the Unity Color class. You will of course have to port this code to whatever platform it is you are developing with. \$\endgroup\$
    – jgallant
    Commented Jun 21, 2016 at 16:56
  • \$\begingroup\$ Oh sorry, I didn't look closely enough. \$\endgroup\$
    – Kyranstar
    Commented Jun 21, 2016 at 16:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .