Diffusion

diffusion

This example shows how to use the AggregateNeighborhood function, in this case, to implement diffusion. In games, diffusion-type algorithms is useful to simulate the flow of gases, disease, and information. Programmers use diffusion on influence maps to help guide AI algorithms. Blurring is a form of diffusion applied on images, motion blur is a form of directed diffusion applied to an image sequence.

The AggregateNeighborhood function takes two parameters: the first is the grid, and the second is an aggregation function. The aggregation functions takes two parameters: the first is a point, and the second the neighbors of that point that belongs in the grid. In the example below, these points are used to access the “gas” grid, and sum all the values at those points, so that the aggregation function gives the average value of the neighborhood around a cell.

Note: To run the example below, you need the Unity web plugin.

Use the left and right mouse buttons to add or remove gas molecules from the grid.

[unity src=”808″]

Code

public class Diffusion : GLMonoBehaviour 
{
   public Cell cellPrefab;
   private PointyHexGrid grid;
   private PointyHexGrid gas;
   private IMap3D map;
   public GameObject root;

   private Vector2 cellDimensions = new Vector2(69, 80);

   private Color offColor = new Color(1, 1, 1, 0);

   public void Start()
   {   
      BuildGrid();
   }

   private void BuildGrid()
   {         
      grid = PointyHexGrid
         .FatRectangle(18, 21);

      gas = PointyHexGrid
         .FatRectangle(18, 21);

      map = new PointyHexMap(cellDimensions)
         .AnchorCellMiddelCenter()
         .WithWindow(ExampleUtils.ScreenRect)
         .AlignMiddelCenter(grid)
         .Scale(.9f) //for a small border
         .To3DXY();

      foreach(var point in grid)
      {         
         Cell cell = Instantiate(cellPrefab);

         cell.transform.parent = root.transform;
         cell.transform.localScale = Vector3.one;
         cell.transform.localPosition = map[point];

         cell.SetText("");
         cell.SetColor(offColor);

         grid[point] = cell;
         gas[point] = 0;
      }
   }

   float CalculateAverage(PointyHexPoint point, IEnumerable neighbors)
   {
      float sum = neighbors
         .Select(x => gas[x])
         .Aggregate((p, q) => p + q) + gas[point];

      return sum / (neighbors.Count() + 1);
   }

   public void Update()
   {
      Algorithms.AggregateNeighborhood<float, pointyhexpoint="">(gas, CalculateAverage); //This adds the 

      if(Input.GetMouseButton(0))
      {
         Vector3 worldPoint = ExampleUtils.ScreenToWorld_NGUI(root, Input.mousePosition);
         PointyHexPoint point = map[worldPoint];

         if(gas.Contains(point))
         {
            gas[point] = 2;
         }
      }

      if(Input.GetMouseButton(1))
      {
         Vector3 worldPoint = ExampleUtils.ScreenToWorld_NGUI(root, Input.mousePosition);
         PointyHexPoint point = map[worldPoint];

         if(gas.Contains(point))
         {
            gas[point] = -1;
         }
      }

      foreach(var point in gas)
      {
         UpdateCell(point);
      }
   }

   private Color Blend(float t, Color color1, Color color2)
   {
      float r = color1.r * (1 - t) + color2.r * t;
      float g = color1.g * (1 - t) + color2.g * t;
      float b = color1.b * (1 - t) + color2.b * t;
      float a = color1.a * (1 - t) + color2.a * t;

      return new Color(r, g, b, a);
   }

   private void UpdateCell(PointyHexPoint point)
   {
      Color newColor = Blend(gas[point], ExampleUtils.colors[4], ExampleUtils.colors[7]);
      grid[point].SetColor(newColor);
   }
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top