How it works...

The compute shader starts by defining the number of invocations per work group using the layout specifier:

layout( local_size_x = 1000 ) in; 

This specifies 1000 invocations per work group in the x dimension. You can choose a value for this that makes the most sense for the hardware you're running. Just make sure to adjust the number of work groups appropriately. The default size for each dimension is one so we don't need to specify the size of the y and z directions.

Then, we have a set of uniform variables that define the simulation parameters. Gravity1 and Gravity2 are the strengths of the two black holes (G, in the preceding equation), and BlackHolePos1 and BlackHolePos2 are their positions. ParticleInvMass is the inverse of the mass of each particle, which is used to convert force to acceleration. Finally, DeltaT is the time-step size, which is used in the Euler method for the integration of the equations of motion.

The buffers for position and velocity are declared next. Note that the binding values here match those that we used on the OpenGL side when initializing the buffers.

Within the main function, we start by determining the index of the particle for which this invocation is responsible for. Since we're working with a linear list of particles, and the number
of particles is the same as the number of shader invocations, what we want is the index within the global range of invocations. This index is available via the built-in
gl_GlobalInvocationID.x input variable. We use the global index here because it is the index within the entire buffer that we need, not the index within our work group, which would only reference a portion of the entire array.

Next, we retrieve the position and velocity from their buffers, and compute the force due to each black hole, storing the sum in the force variable. Then, we convert the force to acceleration and update the particle's position and velocity using the Euler method. We write to the same location from which we read previously. Since invocations do not share data, this is safe.

In the render routine, we invoke the compute shader (step 2 in the How to do it... section), defining the number of work groups per dimension. In the compute shader, we specified a work group size of 1000. Since we want one invocation per particle, we divide the total number of particles by 1000 to determine the number of work groups.

Finally, in step 3, before rendering the particles, we need to invoke a memory barrier to ensure that all compute shader writes have fully executed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.172.252