A downloadable game

Welcome Back to my fourth contribution to @Sableraph's creative coding challenge!

This weeks topic: Remix
With the extra add on challenge to remix an existing project.

So i chose this as an opportunity to add some more experiments to the slime mold simulation i made some time ago (https://justanotheranotheruser.itch.io/slimemold-particle-simulation) And i highly advise to read the previous blog to understand how the simulation works at its core.

The content of today's blog post:

  • Adding Blur to the simulation
  • Adding particles with different Colors and modifying their behavior
  • Adding sampling textures to determine an agents initial Color
  • Decoupling an agents id color and display color

Adding Blur to the simulation:

Previously, an agent would leave a simple 1 pixel wide trail behind that would evaporate over time and that could be detected by another agents sampling zones. In clusters of many agents, this was sufficient to  have them find a path and follow leading each other but when single agents were distributed over larger distances, the thin trails would make it difficult for other agents to detect them. Blurring the texture with each frame in addition to the existing evaporation of the trail makes it easier for agents to detect trails to follow.



Adding particles with different Colors and modifying their behavior:

A thing i wanted to do for a long time is adding agents that have different colors.
The idea was that each color would act as its own tribe by having agents follow similar colors to itself and avoiding colors different to the own.
The easiest approach is to take the three most distinctive colors in the RGB color space: Red (#FF0000), green (#00FF00) and blue (#0000FF).

To modify the behavior of the agents to go towards colors of the same kind, the most elegant way i found is to think about colors as a 3 dimensional vector where each value r, g, and b corresponds to the three parts of a vector x, y and z.

To determine how similar two colors are to each other, one simply takes the dot product between the two vectors that the colors define. 

By the properties of the dot product, two Vectors that point in a similar direction have a dot product close to 1 while two vectors that are close to perpendicular to each other have a dot product close to 0. 
The code for sensing in a particular area looks like this:

float3 agentColorVector = float3(agent.color.r, agent.color.g, agent.color.b);
float3 pixelColorVector = float3(val.r, val.g, val.b);
value = max(value, dot(pixelColorVector, agentColorVector));

after some experimenting and tweaking, i decided to add the max() function instead of taking the average of all pixels in the sampled area to ensure that the agent will turn towards the most dominant trail.

An important thing to note is that all agents do behave the same no matter the color. Their only difference is which color they follow. An interesting idea to explore is to alternate the agents behavior so that it reacts differently to multiple colors and creating a sort of hunter-pray scenario where for example green avoids red but red follows green, maybe that is something for future me.


Adding sampling textures to determine an agents initial Color:

The obvious approach to expand on the idea with multiple colors is to add more colors. One way would have been to give each agent a random rgb value rather then decide between full red full green or full blue. But a more interesting approach is to take an image and have the agent sample its initial color from that image based on the agents starting position. 

To achieve this, the agent spawning code was modified to have two nested loops, one for the x and one for the y position. and since the simulation supports up to 1,000,000 agents while running smoothly, the image size was fixed at 1000 by 1000 pixels.

When initiating, one agent is created for each pixel within that 1000 by 1000 big frame and its color is set to the corresponding value of the image's color at that position. 

The following video shows what this looks like with a picture i took a few days ago. The images saturation was increased to amplify the effect:


Decoupling an agents id color and display color:

The results of the multiple colors from an image works quite well. However, over time it will always result in the colors averaging out. This is because the dot product amplifies similar colors but ignoring colors that are different. Because of that, every color is drawn towards white/gray tones since they have sufficient high values in all color channels to have an affect on all other colors which results in them taking over the entire canvas.

To fix this, it first helps to reduce the color palette back to the original 3 colors, full red, full green and full blue. This is done by taking the most dominant color channel in each pixel, setting that to the max value of 1 and the remaining two color channels are set to 0. 

But because the right image is visually not very pleasing to look at, each agent has an idColor which is the color from the right image, and a visual color from the left image.

When running, the shader will use the idColor to determine the behavior of the agent while maintaining the left image to have a visually more pleasing outcome that is rendered to the canvas.

As a second step, the algorithm for sensing is modified to avoid different colors rather then simply avoiding them:

sum += pixelColor.r * (agent.idColor.r - 0.5);
sum += pixelColor.g * (agent.idColor.g - 0.5);
sum += pixelColor.b * (agent.idColor.b - 0.5);

each color channel from the idColor can either be 0 or 1, by subtracting 0.5 it is either -  0.5 or + 0.5.
Multiplying the corresponding color channels together like this will result in a positive value that gets added to the sum if the colors are similar and a negative value when the colors are not:

Example 1 with a orange pixelColor and a red idColor

pixelColor: float3(1, 0.5, 0)
idColor: float3(1, 0, 0)
1 * (1 - 0.5) = 0.5
0.5 * (0 - 0.5) = -0.25
0 * (0 - 0.5) = 0
sum += (0.5 - 0.25) -> sum += 0.25

Example 2 with a light blue pixelColor and a red idColor

pixelColor: float3(0, 0.5, 1)
idColor: float3(1, 0, 0) 
0 * (1 - 0.5) = 0
0.5 * (0 - 0.5) = -0.25 
1 * (0 - 0.5) = -0.5 
sum += (-0.5 - 0.25) -> sum += -0.75

This way, the agent will avoid colors that are different to its own, which results in clearer color separation overall:



Honorable mention to the errors i made along the way that lead to some interesting visual outcomes:

Both of these were created due to some error when i tried to implement a Gaussian blur to the simulation.

attempt to add gaussian blur number 2

Leave a comment

Log in with itch.io to leave a comment.