Skip to content

About

aseassignment25-26-Oshersh15 created by GitHub Classroom

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Interactive Flocking Simulation using Reynolds’ Boids Model (Python, PySide6, OpenGL)

Project Overview

This project implements an interactive 3D flocking simulation inspired by Craig Reynolds’ Boids model (SIGGRAPH, 1987). The system simulates a group of autonomous agents (“boids”) that exhibit natural collective behaviour through three simple local rules: separation, alignment, and cohesion.

The final artefact allows the user to interact with the flock in real time through a graphical interface and direct manipulation in the scene. An attractor can be created and dragged with the mouse to guide the flock’s movement, while static obstacles can be placed and removed to influence the flock’s path and formation.

The primary focus of the project is on modular system design, real-time interaction, and performance-aware simulation rather than purely visual fidelity.

flock_preview.1.mp4

Features

  • Real-time flocking simulation based on Reynolds’ three-rule model:
    • Separation - avoid crowding nearby boids
    • Alignment - match the average heading of neighbours
    • Cohesion - steer towards the local group centre
  • Interactive user interface:
    • Adjustable sliders for flocking rule weights
    • Boid size control
    • Obstacle strength control
    • Boid count adjustment
  • Direct scene interaction:
    • Left mouse button - create and drag an attractor point
    • Right mouse button - place or remove static obstacles
    • Button to clear all obstacles at once
  • World bounds force to keep the flock within the visible simulation area
  • Performance optimisation using a spatial grid for neighbour lookup
  • Unit testing with pytest for behaviour and system validation

Technology Stack

  • Language: Python
  • UI Framework: PySide6 (Qt for Python)
  • Rendering: OpenGL via PyNGL (NCCA Graphics Library)
  • Math & Vectors: ncca.ngl.vec3.Vec3
  • Testing: Pytest

System Design

The project follows a modular, object-oriented structure:

Core Classes

Boid

Represents a single agent in the simulation.

Stores:

  • Position, velocity, and acceleration vectors
  • Maximum speed and steering force
  • Rule weights for separation, alignment, and cohesion
  • Orientation for smooth visual heading

Responsibilities:

  • Compute steering forces
  • Apply flocking behaviours
  • Update motion and orientation

Flock

Manages the collection of boids.

Responsibilities:

  • Add and remove boids dynamically
  • Maintain a spatial grid for efficient neighbour lookup
  • Apply global parameters such as obstacle strength
  • Update all boids per frame

Attractor

Represents a user-controlled target point that boids steer towards when active.

Obstacle

Represents a static repulsion object with a position and radius that generates avoidance forces in nearby boids.

Simulation Manager (MainWindow)

Handles:

  • OpenGL rendering
  • UI signal connections
  • Mouse input
  • World projection and coordinate conversion
  • Main update loop
classDiagram
    class Boid {
        +Vec3 position
        +Vec3 velocity
        +Vec3 acceleration
        +float sep_weight
        +float ali_weight
        +float cohesion_weight
        +update()
        +apply_behaviours()
        +separation()
        +alignment()
        +cohesion()
        +avoid_obstacles()
        +world_bounds_force()
    }

    class Flock {
        +List<Boid> boids
        +float obstacle_strength
        +float cell_size
        +Map grid
        +update()
        +add_boid()
        +get_neighbours()
        +build_grid()
    }

    class MainWindow {
        +Flock flock
        +List<Obstacle> obstacles
        +Attractor attractor
        +update_boid_count()
        +update_separation()
        +update_alignment()
        +update_cohesion()
        +update_obstacle_strength()
        +screen_to_world()
    }

    class Attractor {
        +Vec3 pos
    }

    class Obstacle {
        +Vec3 position
        +float radius
        +contains_point()
    }

    MainWindow "1" --> "1" Flock
    Flock "1" --> "*" Boid
    MainWindow "1" --> "0..1" Attractor
    MainWindow "1" --> "0..*" Obstacle
Loading

Algorithm Overview

The simulation is based on Craig Reynolds’ Boids algorithm, where each boid computes a new steering force at every frame based on nearby flockmates.

For each boid:

  1. Neighbour Detection

Nearby boids are identified within a fixed radius using a spatial grid. This reduces the computational cost compared to checking every boid in the flock.

  1. Force Calculation Three steering vectors are computed:
  • Separation vector
  • Alignment vector
  • Cohesion vector
  1. Weighting and Combination Each vector is scaled by a user-controlled weight and combined into a final acceleration force.
  2. Additional Forces
  • Attractor steering force (if active)
  • Obstacle avoidance force
  • World bounds force to keep boids within the visible region
  1. Motion Update The resulting acceleration is applied to velocity, clamped to a maximum speed, and then applied to position.

Performance Considerations

To avoid the O(n²) cost of checking every boid against every other boid, the system uses a spatial hashing grid. The simulation space is divided into square cells, and each boid is assigned to a cell based on its position. When searching for neighbours, only boids in the current cell and the eight surrounding cells are considered.

This reduces neighbour queries to approximately O(n) per frame and allows the simulation to scale to several hundred boids while maintaining real-time performance.

Additional rendering optimisations include:

  • Reusing a single boid mesh for all instances
  • Dynamic level-of-detail adjustments for boid geometry
  • Skipping heading updates on alternating frames to reduce per-frame trigonometric cost

Despite these optimisations, Python loop overhead remains the main performance bottleneck for flock sizes above several hundred boids.

Development Process

Initial Implementation

The project began with a basic implementation of the three flocking rules using vector math and a simple update loop. Early versions exhibited correct behaviour but suffered from visual instability and boids leaving the simulation area.

Stability Improvements

A world bounds force was added to gently steer boids back into the visible region instead of abruptly reversing their direction. Orientation smoothing was introduced to prevent visual “flipping” when boids changed direction sharply.

UI Integration

The interface was built using a .ui file designed in Qt Designer and loaded dynamically. Sliders were connected to simulation parameters through PySide6 signal-slot connections, allowing real-time adjustment of flocking behaviour.

Because Qt sliders only support integer values, all inputs are mapped to floating-point ranges internally using scaling factors.

Obstacle System

Static obstacles were added as interactive objects placed with the right mouse button. These generate repulsion forces in nearby boids, allowing the user to shape the flock’s movement path dynamically.

Optimisation Phase

A spatial grid was implemented to reduce neighbour lookup cost. This significantly improved performance at higher boid counts and allowed the simulation to remain responsive beyond 300-400 agents.

Testing Strategy

The project follows a test-driven Development (TDD) approach using pytest.

Tests validate:

  • Neighbour detection logic
  • Behaviour force calculations
  • Class interactions between Boid and Flock
  • Stability of steering outputs under controlled conditions

This ensures changes to optimisation or behaviour weighting do not silently break simulation logic.

Limitations and Future Work

  • Performance ceiling: Python loop overhead limits scalability beyond approximately 500–700 boids in real time. A future improvement would be to align spatial cell size with interaction radius to eliminate most per-frame distance checks entirely.
  • Visual fidelity: The scene uses unlit, flat-shaded geometry. A lighting model and textured meshes would significantly improve realism.
  • Predator system: Adding a secondary agent type that the flock avoids could introduce more complex emergent behaviour.
  • GPU acceleration: Offloading neighbour and force calculations to a compute shader or NumPy-based vectorisation would greatly improve performance at scale.

Interaction Guide

  • Left Mouse Button (Hold and Drag) - Create and move an attractor
  • Right Mouse Button - Place or remove obstacles
  • Clear Obstacles Button - Remove all obstacles from the scene
  • Sliders - Adjust flocking rule weights and visual parameters in real time

References

Reynolds, C. W. (1987). Flocks, herds and schools: A distributed behavioral model. Computer Graphics, 21(4), 25–34. https://www.red3d.com/cwr/boids/

Qt Company. (2023). QSlider class (Qt Widgets 6.6). https://doc.qt.io/qt-6/qslider.html

Teschner, M., Heidelberger, B., Müller, M., Pomeranets, D., & Gross, M. (2003). Optimized spatial hashing for collision detection of deformable objects. Proceedings of Vision, Modeling, and Visualization. https://matthias-research.github.io/pages/publications/tetraederCollision.pdf

Reynolds, C. W. (1999). Steering behaviors for autonomous characters. https://www.red3d.com/cwr/steer/

Treuille, A., Cooper, S., & Popović, Z. (2006). Continuum crowds. ACM SIGGRAPH. https://grail.cs.washington.edu/projects/crowd-flows/

SimonDev. (2020, November 30). Spatial Hash Grids & Tales from Game Development. YouTube. https://www.youtube.com/watch?v=sx4IIQL0x7c

About

aseassignment25-26-Oshersh15 created by GitHub Classroom

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages