Chapters

Hide chapters

Metal by Tutorials

Third Edition · macOS 12 · iOS 15 · Swift 5.5 · Xcode 13

Section I: Beginning Metal

Section 1: 10 chapters
Show chapters Hide chapters

Section II: Intermediate Metal

Section 2: 8 chapters
Show chapters Hide chapters

Section III: Advanced Metal

Section 3: 8 chapters
Show chapters Hide chapters

18. Particle Behavior
Written by Caroline Begbie & Marius Horga

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

As you learned in the previous chapter, particles have been at the foundation of computer animation for years. In computer graphics literature, three major animation paradigms are well defined and have rapidly evolved in the last two decades:

  • Keyframe animation: Starting parameters are defined as initial frames, and then an interpolation procedure is used to fill the remaining values for in-between frames. You’ll cover this topic in Chapter 23, “Animation”.
  • Physically based animation: Starting values are defined as animation parameters, such as a particle’s initial position and velocity, but intermediate values are not specified externally. This topic was covered in Chapter 17, “Particle Systems”.
  • Behavioral animation: Starting values are defined as animation parameters. In addition, a cognitive process model describes and influences the way intermediate values are later determined.

In this chapter, you’ll focus on the last paradigm as you work through:

  • Velocity and bounds checking.
  • Swarming behavior.
  • Behavioral animation.
  • Behavioral rules.

By the end of the chapter, you’ll build and control a swarm exhibiting basic behaviors you might see in nature.

Behavioral Animation

You can broadly split behavioral animation into two major categories:

  • Cognitive behavior: This is the foundation of artificial life which differs from artificial intelligence in that AI objects do not exhibit behaviors or have their own preferences. It can range from a simple cause-and-effect based system to more complex systems, known as agents, that have a psychological profile influenced by the surrounding environment.
  • Aggregate behavior: Think of this as the overall outcome of a group of agents. This behavior is based on the individual rules of each agent and can influence the behavior of neighbors.

In this chapter, you’ll keep your focus on aggregate behavior.

There’s a strict correlation between the various types of aggregate behavior entities and their characteristics. In the following table, notice how the presence of a physics system or intelligence varies between entity types.

  • Particles are the largest aggregate entities and are mostly governed by the laws of physics, but they lack intelligence.
  • Flocks are an entity that’s well-balanced between size, physics and intelligence.
  • Crowds are smaller entities that are rarely driven by physics rules and are highly intelligent.

Working with crowd animation is both a challenging and rewarding experience. However, the purpose of this chapter is to describe and implement a flocking-like system, or to be more precise, a swarm of insects.

Swarming Behavior

Swarms are gatherings of insects or other small-sized beings. The swarming behavior of insects can be modeled in a similar fashion as the flocking behavior of birds, the herding behavior of animals or the shoaling behavior of fish.

The Starter Project

➤ In Xcode, open the starter project for this chapter. There are only a few files in this project.

The starter app
Lsa fvezvef amr

Painting the pixels around the boid
Liotseng cni teziqp iraozv tpa qoop

output.write(color, location + uint2(-1,  1));
output.write(color, location + uint2( 0,  1));
output.write(color, location + uint2( 1,  1));
output.write(color, location + uint2(-1,  0));
output.write(color, location + uint2( 1,  0));
output.write(color, location + uint2(-1, -1));
output.write(color, location + uint2( 0, -1));
output.write(color, location + uint2( 1, -1));
Larger boids
Fehsuy weurd

Velocity

Velocity is a vector made up of two other vectors: direction and speed. The speed is the magnitude or length of the vector, and the direction is given by the linear equation of the line on which the vector lies.

Properties of a vector
Qripetzouj an u kawyes

var velocity: float2
let velocity: float2 = [
  Float.random(in: -5...5),
  Float.random(in: -5...5)
]
pointer.pointee.velocity = velocity
float2 velocity;
float2 velocity = boid.velocity;
position += velocity;
boid.position = position;
boid.velocity = velocity;
boids[id] = boid;
Reflect and bounce at the edges
Yomxars ivh qookki oc tli uwpav

if (position.x < 0 || position.x > output.get_width()) {
  velocity.x *= -1;
}

if (position.y < 0 || position.y > output.get_height()) {
  velocity.y *= -1;
}
Bouncing boids
Luitfezc naofn

Behavioral Rules

There’s a basic set of steering rules that swarms and flocks can adhere to, and it includes:

Cohesion

Cohesion is a steering behavior that causes the boids to stay together as a group. To determine how cohesion works, you need to find the average position of the group, known as the center of gravity. Each neighboring boid will then apply a steering force in the direction of this center and converge near the center.

Cohesion
Gaxawoiq

constant float average = 100;
constant float attenuation = 0.1;
constant float cohesionWeight = 2.0;
float2 cohesion(
  uint index,
  device Boid* boids,
  uint particleCount)
{
  // 1
  Boid thisBoid = boids[index];
  float2 position = float2(0);
  // 2
  for (uint i = 0; i < particleCount; i++) {
    Boid boid = boids[i];
    if (i != index) {
      position += boid.position;
    }
  }
  // 3
  position /= (particleCount - 1);
  position = (position - thisBoid.position) / average;
  return position;
}
float2 cohesionVector =
    cohesion(id, boids, particleCount) * attenuation;

// velocity accumulation
velocity += cohesionVector * cohesionWeight;
Converging boids
Sihvagtugr heafx

Separation

Separation is another steering behavior that allows a boid to stay a certain distance from nearby neighbors. This is accomplished by applying a repulsion force to the current boid when the set threshold for proximity is reached.

Separation
Noceyudiil

constant float limit = 20;
constant float separationWeight = 1.0;
float2 separation(
  uint index,
  device Boid* boids,
  uint particleCount)
{
  // 1
  Boid thisBoid = boids[index];
  float2 position = float2(0);
  // 2
  for (uint i = 0; i < particleCount; i++) {
    Boid boid = boids[i];
    if (i != index) {
      if (abs(distance(boid.position, thisBoid.position))
            < limit) {
        position =
            position - (boid.position - thisBoid.position);
      }
    }
  }
  return position;
}
float2 separationVector = separation(id, boids, particleCount)
  * attenuation;
velocity += cohesionVector * cohesionWeight
  + separationVector * separationWeight;
Boid separation
Wiek tuvatezeez

Alignment

Alignment is the last of the three steering behaviors Reynolds used for his flocking simulation. The main idea is to calculate an average of the velocities for a limited number of neighbors. The resulting average is often referred to as the desired velocity.

Alignment
Edutkqubb

constant float neighbors = 8;
constant float alignmentWeight = 3.0;
float2 alignment(
  uint index,
  device Boid* boids,
  uint particleCount)
{
  // 1
  Boid thisBoid = boids[index];
  float2 velocity = float2(0);
  // 2
  for (uint i = 0; i < particleCount; i++) {
    Boid boid = boids[i];
    if (i != index) {
      velocity += boid.velocity;
    }
  }
  // 3
  velocity /= (particleCount - 1);
  velocity = (velocity - thisBoid.velocity) / neighbors;
  return velocity;
}
float2 alignmentVector = alignment(id, boids, particleCount)
  * attenuation;
velocity += cohesionVector * cohesionWeight
  + separationVector * separationWeight
  + alignmentVector * alignmentWeight;
Boids aligning
Gainl ofalqoyr

Escaping

Escaping is a new type of steering behavior that introduces an agent with autonomous behavior and slightly more intelligence — the predator.

Escaping
Oykijiwf

constant float escapingWeight = 0.01;
constant float predatorWeight = 10.0;
float2 escaping(Boid predator, Boid boid) {
  return -predatorWeight * (predator.position - boid.position)
            / average;
}
Boid boid = boids[id];
Boid predator = boids[0];
Boid boid;
if (id != 0) {
  boid = boids[id];
}
if (id == 0) {
  color = half4(1.0, 0.0, 0.0, 1.0);
  location = uint2(boids[0].position);
}
// 1
if (predator.position.x < 0
     || predator.position.x > output.get_width()) {
  predator.velocity.x *= -1;
}
if (predator.position.y < 0
     || predator.position.y > output.get_height()) {
  predator.velocity.y *= -1;
}
// 2
predator.position += predator.velocity / 2.0;
boids[0] = predator;
float2 escapingVector = escaping(predator, boid) * attenuation;
velocity += cohesionVector * cohesionWeight
  + separationVector * separationWeight
  + alignmentVector * alignmentWeight
  + escapingVector * escapingWeight;
Escaping boids
Ecvejaxx leaqb

Dampening

Dampening is the last steering behavior you’ll looking at in this chapter. Its purpose is to dampen the effect of the escaping behavior, because at some point, the predator will stop its pursuit.

constant float dampeningWeight = 1.0;
float2 dampening(Boid boid) {
  // 1
  float2 velocity = float2(0);
  // 2
  if (abs(boid.velocity.x) > limit) {
    velocity.x += boid.velocity.x / abs(boid.velocity.x)
                       * attenuation;
  }
  if (abs(boid.velocity.y) > limit) {
    velocity.y = boid.velocity.y / abs(boid.velocity.y)
                       * attenuation;
  }
  return velocity;
}
float2 dampeningVector = dampening(boid) * attenuation;
velocity += cohesionVector * cohesionWeight
  + separationVector * separationWeight
  + alignmentVector * alignmentWeight
  + escapingVector * escapingWeight
  + dampeningVector * dampeningWeight;
Dampening keeps the boids together
Fedxenecj goalb xga jeehx qaterhas

Key Points

  • You can give particles behavioral animation by causing them to react with other particles
  • Swarming behavior has been widely researched. The Boids simulation describes basic movement rules.
  • The behavioral rules for boids include cohesion, separation and alignment.
  • Adding a predator to the particle mass requires an escaping algorithm.

Where to Go From Here?

In this chapter, you learned how to construct basic behaviors and apply them to a small flock. Continue developing your project by adding a colorful background and textures for the boids. Or make it a 3D flocking app by adding projection to the scene. When you’re done, add the flock animation to your engine. Whatever you do, the sky is the limit.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now