Chris Donnelly
C++ Engine Developer (Systems) in Frankfurt Am Main, Germany
github chris-donnellyemail christdonnelly-phone@hotmail.co.ukemail LinkedInemail Youtube
« back to main page


Gravity Wells


Simulation & Concurrency / University of Hull, 2016-17
Multi-threaded and network-distributed physical simulation application


Contents Videos

A multithreaded distributed processing (masterless peer-to-peer) physical simulation app

Featuring live configurable simulation parameters, networking and thread frequencies


Gravity Wells Simulation

Gravity Wells Simulation

UI Controls

Real-time feedback and control via UI and external files


Context

A rigid-body physics simulation app featuring physically-affected spheres in a cylindrical container (circular, walled), where the user can use movable gravity wells, which repel and attract, based on the user's mouse input. Wells can be moved vertically (to a degree). Multiple app instances can connect (via a masterless peer-to-peer network) across a network, where each machine (or app instance) has its own gravity well, controlled from its networked machine. The remote wells all affect the balls in the scene, and ownership/contention of each ball is negotiated between machines (a ball affected by one well is owned by the machine owning the well; balls which are affected by multiple wells are shared). Balls will have differing physical properties (mass), which will be represented visually by colour (see below):


Differing ball mass

The different mass of each ball is visually represented as red/blue/green

Furthermore, the program will be tested for network error handling by software simulating packet loss.


See the project in action:




Specification

The application is written in C++11, and is developed for Microsoft Windows 10 (as a Win32 app), using OpenGL 1.0. Further libraries and specifications:


Hardware used (working on the same network):

  • Windows 10 PC, i7 (6th Gen) CPU, NVidia GeForce 980 graphics
  • Windows 10 Laptop, i5 (4th Gen) CPU, with NVidia GeForce 820M graphics
  • Windows 10 Laptop, i7 (2nd Gen) CPU, with NVidia GeForce 520M graphics

Implementation

The application itself requires numerous major components (and subsystems) to manage the multiple APIs and data flow; these components can be divided up into the following:


Main Application


Application Framework

The application class encapsulates Win32 functionality (such as window management and event response), and communicates with the connected Simulation, Networking and Rendering systems after loading configuration information during the message loop (the UI also allows the user to set simulation parameters; see Configuration).


Systems


Simulation

The Simulation system simulates the motion and properties of the balls and wells. An STL vector of the balls is passed to the simulation class to process. The simulation process uses the values specified by the configuration file (and UI) to calculate the movement and new positions (based on delta time). This runs on a designated thread (and core), with timing controls to operate at the user-specified frequency.

Three collision calculations are performed:

  • Ball vs Ball
  • Ball vs Floor (base of cylinder)
  • Ball vs Wall (wall of cylinder)

In the worst case scenario, each ball must be tested against every other ball in the area (spatial subdivision techniques can reduce the area, and distribution will further split up ball collections).

With no optimisations or subdivisions, a linear search through the ball array (of size n) requires n2-n collision checks (when removing the test of a ball against itself).

Number of balls

625 balls = 390 000 checks are performed

A 'log' of collisions needs to be kept to stop collisions doubling (in the case of balls A and B, we store a collision for AB, but not for BA) - the logic is calculated twice for the same two balls otherwise. A simple hashed value stores these the balls in a standard array to process collisions.

The simulation calculates the new ball positions/rotations for each collision in the log, accounting for the coefficient of restitution (labelled as elasticity) and gravitational forces (world and any local gravity wells). Rotation is calculated on the distance and direction moved (friction is not implemented in rotation).


Networking

The networking system (like the simulation and rendering systems) runs on a designated thread (and core), with timing controls (for user-specified frequency). This system oversees distribution of data via WinSock sockets.

Non-blocking sockets are implemented and polled for data (this is performed at the frequency specified by the user). Packets with instructions such as 'ping' and 'join' were implemented (simple one-byte values) to build and maintain the network infastructure, and 'ball' packets described small groups of ball data (typically < 16). I used small to medium-sized packets to transmit batches of ball data, with the aim of sending smaller packets at a greater frequency (if the network frequency setting allows it).

Loaded configuration files will contain a list of target machines to connect with (the application will detect which address is its own external IP and will skip the outgoing connection to this address).

Each application is a peer/client node with the exception of the first running instance - this is the master peer (not a server) which begins the network construction. On a connection request, the accepting machine will validate the address, and will perform a basic handshake with the requesting machine. Once the handshake is complete, the requesting machine address is passed to all other connected machines, and a handshake is made, building a 'star' topology.

Peer list

List of connected machines (machine's external IP not included)

The application stores each connected machine address in a 32-bit integer (simply storing each IPv4 octet as a consecutive byte), creating a unique ID which is used as the key in an std::map of sockets. Ths structure of the networking system allows for a large number of machines (except any local network restrictions) which can be connected (during development in computing lab conditions, six machines were connected by simply adding their IP numbers to the config files).

Movement of each machine's gravity well is also broadcast across the network from each application to all its connected counterparts. This is performed at the rate of the Windows Processing loop (WndProc), and uses a small packet.


Rendering

The rendering system (like the simulation and networking systems) runs on a designated thread (and core), with timing controls (for user-specified frequency). It uses OpenGL for Windows to render the scene (using the OpenGL functions of AntTweakBar). Graphical fidelity was out of scope for this project, so rendering was made to be barebones, to focus on other systems.


Configuration

The configuration system loads configuration data from file and passes the appropriate system.

Example file contents:

    listenport	9175
    arenasize	150
    ballcount	625
    simulationhz	800
    graphicshz	120
    networkhz	800
    
    address 192 168 0 101 9175
    address 192 168 0 102 9175
    address 192 168 0 103 9175
    address 192 168 0 104 9175
    					

Configuration file contents

token explanation
listenport Port number to accept connections on
arenasize Size of the arena geometry (and collisable area)
ballcount Total number of balls to 'spawn' - this must be a square number
simulationhz Desired operating frequency for Simulaton system
graphicshz Desired operating frequency for Graphics system
networkhz Desired operating frequency for Networking system
address Space-separated IPv4 address and trailing port number to connect to (multiple entries)

Note: Some values can be later changed in the UI


Additional Notes

OpenGL 1.0 was used for fast development, a graphical framework was not immediately available.