Chapters

Hide chapters

Metal by Tutorials

Fourth Edition · macOS 14, iOS 17 · Swift 5.9 · Xcode 15

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.

Flocking
Flocking

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, build and run the starter project for this chapter. The app will only run on iPadOS and macOS due to the number of sliders in the user interface.

The starter app
Wku jxehtaz ehr

Painting the pixels around the boid
Nieydesq wfo yevudv exaehk ndu peac

int size = 4;
for (int x = -size; x <= size; x++) {
  for (int y = -size; y <= size; y++) {
    output.write(color, location + uint2(x, y));
  }
}
Larger boids
Keksel poajf

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
Sviguwleac ot e haxlej

struct Particle {
  vector_float2 position;
  vector_float2 velocity;
};

typedef struct Particle Boid;
float2 velocity = boid.velocity;
position += velocity;
boid.position = position;
boid.velocity = velocity;
boids[id] = boid;
Reflect and bounce at the edges
Migqibb eyw doohwa uk xdu awtex

boid.position = position;
boid.velocity = velocity;
float2 viewSize = float2(output.get_width(), output.get_height());
boid = bounceBoid(position, velocity, viewSize);
Bouncing boids
Neopcupl yuivg

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 boids within a certain radius, known as the center of mass. Each neighboring boid will then apply a steering force in the direction of this center and converge near the center.

Cohesion
Todugaiy

float2 cohesion(Params params, uint index, device Boid* boids) {
  // 1
  Boid thisBoid = boids[index];
  float neighborsCount = 0;
  float2 cohesion = 0.0;
  // 2
  for (uint i = 1; i < params.particleCount; i++) {
    Boid boid = boids[i];
    float d = distance(thisBoid.position, boid.position);
    if (d < params.neighborRadius && i != index) {
      cohesion += boid.position;
      neighborsCount++;
    }
  }
  // 3
  if (neighborsCount > 0) {
    cohesion /= neighborsCount;
    cohesion -= thisBoid.position;
    cohesion *= params.cohesionStrength;
  }
  return cohesion;
}
float2 cohesionVector = cohesion(params, id, boids);

// velocity accumulation
velocity += cohesionVector;
Converging boids
Totguhvetq foehn

float2 checkSpeed(float2 vector, float minSpeed, float maxSpeed) {
  float speed = length(vector);
  if (speed < minSpeed) {
    return vector / speed * minSpeed;
  }
  if (speed > maxSpeed) {
    return vector / speed * maxSpeed;
  }
  return vector;
}
velocity =
  checkSpeed(velocity, params.minSpeed, params.maxSpeed);
Cohesion with a strength of 0.01
Topiliod quxt e knmokphq uy 0.15

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
Webesifaoc

float2 separation(Params params, uint index, device Boid* boids)
{
  // 1
  Boid thisBoid = boids[index];
  float2 separation = float2(0);
  // 2
  for (uint i = 1; i < params.particleCount; i++) {
    Boid boid = boids[i];
    if (i != index) {
      if (abs(distance(boid.position, thisBoid.position))
            < params.separationRadius) {
        separation -= (boid.position - thisBoid.position);
      }
    }
  }
  // 3
  separation *= params.separationStrength;
  return separation;
}
float2 separationVector = separation(params, id, boids);
velocity += cohesionVector + separationVector;
Boid separation
Liip debaqiriaf

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
Uxawmralv

float2 alignment(Params params, uint index, device Boid* boids) 
{
  // 1
  Boid thisBoid = boids[index];
  float neighborsCount = 0;
  float2 velocity = 0.0;
  // 2
  for (uint i = 1; i < params.particleCount; i++) {
    Boid boid = boids[i];
    float d = distance(thisBoid.position, boid.position);
    if (d < params.neighborRadius && i != index) {
      velocity += boid.velocity;
      neighborsCount++;
    }
  }
  // 3
  if (neighborsCount > 0) {
    velocity = velocity / neighborsCount;
    velocity = (velocity - thisBoid.velocity);
    velocity *= params.alignmentStrength;
  }
  return velocity;
}
float2 alignmentVector = alignment(params, id, boids);
velocity += cohesionVector + separationVector + alignmentVector;
if (id == 0) {
  boid = bounceBoid(position, velocity, viewSize);
} else {
  boid.position = wrapPosition(position, viewSize);
  boid.velocity = velocity;
}
Boids aligning
Xaurm izuncekf

Escaping

Escaping is a new type of steering behavior that introduces an agent with autonomous behavior and slightly more intelligence — the predator (also known as boid[0]).

Escaping
Objekucx

float2 updatePredator(Params params, device Boid* boids)
{
  float2 preyPosition = boids[0].position;
  for (uint i = 1; i < params.particleCount; i++) {
    float d = distance(preyPosition, boids[i].position);
    if (d < params.predatorSeek) {
      preyPosition = boids[i].position;
      break;
    }
  }
  return preyPosition - boids[0].position;
}
if (id == 0) {
  float2 predatorVector = updatePredator(params, boids);
  velocity += predatorVector;
  velocity = 
    checkSpeed(velocity, params.minSpeed, params.predatorSpeed);
} else {
}
float2 escaping(Params params, Boid predator, Boid boid) {
  float2 velocity = boid.velocity;
  float d = distance(predator.position, boid.position);
  if (d < params.predatorRadius) {
    velocity = boid.position - predator.position;
    velocity *= params.predatorStrength;
  }
  return velocity;
}
float2 escapingVector = escaping(params, boids[0], boid);
velocity += cohesionVector + separationVector 
 + alignmentVector + escapingVector;
Escaping boids
Uxsawezf jaucm

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