Assignment 058: Marbles - simple 3D physics simulation

The task is to implement a simple physical simulation in 3D: balls (marbles) moving in a homogeneous gravitational field, bouncing off of transparent walls and one another.

Marbles demo


The following components will need to be designed and implemented:

  • representation of 3D world - a set of balls (a fixed number of balls in the basic variant), their current locations, velocities, radii, colors, ... + walls of an "aquarium" constraining the balls' movement (sufficient to use fixed rectangles in the basic variant).
  • collision detection - algorithm detecting collisions among all objects in the scene. In our case it is the collision among all the balls (O(N2) tests) and among the balls and walls (M*N tests). N is the number of balls, M is the number of fixed walls. You may use a spatial data structure to accelerate the collision detection for an extra bonus.
  • dynamic simulation - homogeneous gravitational field + simple behavior upon the impact of two balls or a ball against a wall (in the simple variant, it is sufficient to ignore balls' rotation and implement only damped elastic response)
  • rendering - render the current state of the world in every frame. Better appearance can be achieved through the use of shaders, textures, etc.

Basic info

The project 058marbles from the grcis repository will serve as the basis. The application has a basic support of real-time simulation on the CPU and rendering using OpenGL.
The following classes (all in the file Marbles.cs) will need to be modified to implement the assignment:

  • MarblesWorld - world representation, most relevant methods: Reset( string param ) [re-]initialization of the simulation Simulate( double time ) calculates the world simulation up to a given time instant. The return value is an object containing rendering data, see below.
  • MarblesRenderData - rendering data representation, each instance is created inside of the method MarblesWorld.Simulate() and later it is not modified in any way or reused again. After the use (rendering) it is disposed of.
  • MarblesRenderer - performs the scene rendering according to the prepared data. Everything is taken care of by the method Render( OpenglState OGL, MarblesRenderData data ). How does it work: overwriting of data (coordinates) in the prepared VBO buffers set into the mode "BufferUsageHint.DynamicDraw"; buffers are mapped into the application memory and they are overwritten in the unsafe mode using pointers. The default implementation draws a single triangle instead of a ball - you will have to change this.
    The pilot implementation uses two simple shaders, similar to the ones from previous projects 086shader and 087fireworks.


You may read up on the elastic or inelastic collisions in most game development books or in Wikipedia (follow references). Read up for example here on the impact response. It is assumed that you will spend some time studying the problem yourself.

Technical details

One step of the physical simulation is run in the method Form1.Simulate(). Two variants of the simulation loops are implemented:

Synchronous: one simulation step is immediately followed by rendering one frame. This is implemented in the function Application_Idle(). When V-sync is on, the simulation and rendering speed are limited by the display refresh frequency (of course, you may turn VSync off).

Asynchronous: simulation and rendering are performed in two separate threads. If you turn on the asynchronous MT mode, the simulation will run at a maximum possible speed in a separate thread, employing 100% of one of your CPU cores (see Form1.SimulationLoop()). The rendering remains in the method Application_Idle() and it is usually driven by the display refresh (since the simulated scene will usually not represent a significant load for your GPU).


The project 058marbles has a "screencast" functionality, which allows to save individual frames in real-time to the disk (can be used later to assemble a video). The functionality of a transparent, independent screencast is implemented by the class OpenglSupport.Screencast. The screencast mode is enabled in the parameter line by setting screencast=true (to switch it off again, use screencast=false).

The frames are written to the disk in the PNG format. This mechanism is implemented asynchronously in a separate CPU thread and should not slow your program down. Should the disk be too slow to write the frames, the program will keep a queue of up to 500 unsaved frames. The current queue length is displayed as the number in parentheses in the program's status line. Should this number systematically increase, you computer may not be fast enough to save the frames and it may be better to switch the screencast off. We recommend using VSync in the screencast mode.


Bonus points will be awarded for any additional effort over the standard solution: dynamically added balls (they can be added or they can die off), more complex geometry of the collision scene, ball rotation and corresponding response, a more realistic imperfect-elastic collision, air friction (realistic ballistics), alternative interesting gravitational field (a la "Angry Birds Space"), a spatial data structure for faster collision detection (switching between the advanced and brute-force solution will be necessary to compare the speed), etc.


The due date is: 17. 2. 2019


Basis: 12 pts (simple but functional simulation, mandatory features are: ball-ball and ball-wall collisions, gravitational field),
further up to 10 pts: bonus for interesting extensions (see above)


Visual Studio project: 058marbles.
Make sure to always update the grcis repo before you start working on an assignment.

Source file

Modify an hand in the file: Marbles.cs (and potentially also the modified shader files)
Write your entire name in the function InitParams().

Copyright (C) 2012-2018 J.Pelikán and J.Krivánek, last change: 2019-05-09 17:52:59 +0200 (Thu, 09 May 2019)