3D Gravity Simulations and OpenCL

It has been a few years since I last was experimenting with OpenCL for gravity simulations.

At that time I made some mistakes with my code that resulted in not all of the objects being compared to all of the objects in the gravity calculations. For the purists this is not acceptable “How can you call it a gravity simulation if you are not using all objects in the calculations?!” The other opinion raised at the time was if it looks good enough, use the speed ups. None of the comments to my YouTube gravity videos were (in typical YouTube speak) “haha lol! looks fake! u no do gud gravity!”. So, if you are struggling with getting gravity working fast, try reducing the number of actual particle interactions.

Here is the latest updated CL kernel code….


__kernel void Gravity3DKernel(__global float4* pos, __global float4* vel, __global float4* acc, __global float4* mass, float mingravdist, float forcescalefactor, int startindex, int stopindex, int gridsize)
{
	int index=get_global_id(0)+startindex;
	float dx,dy,dz,distance,force;
	float positionx=pos[index].x;
	float positiony=pos[index].y;
	float positionz=pos[index].z;
	acc[index].x=0;
	acc[index].y=0;
	acc[index].z=0;
	for(int a=0; a<get_local_size(0); a++) {
		if (a!=index) {
				
			dx=pos[a].x-positionx;
			dy=pos[a].y-positiony;
			dz=pos[a].z-positionz;
				
			distance=sqrt(dx*dx+dy*dy+dz*dz);
			
			dx=dx/distance;
			dy=dy/distance;
			dz=dz/distance;
				
			force=1/(distance*distance+mingravdist*mingravdist)*forcescalefactor;
				
			acc[index].x+=dx*force;
			acc[index].y+=dy*force;
			acc[index].z+=dz*force;
		}
	}
	vel[index].x+=acc[index].x;
	vel[index].y+=acc[index].y;
	vel[index].z+=acc[index].z;
}


The kernel processes all of the 3d objects once using 1 of the other objects (passed as startindex).

You can call the kernel multiple times each frame/step of the simulation. If you want strictly accurate (and slow) gravity simulation results you call it inside a loop that sets startindex from 1 to the number of objects. In my experiments this is not necessary. If you want “good enough” nice looking gravity simulations then calling the kernel with as little as 10 different startindexes (use a set of objects spread out among all of them or just use a random set of 10 objects each frame).

Here is a recent 4K resolution example movie. This one used 1,000 objects out of 5,000,000 objects for the gravity calculations. The objects start by being randomly placed within an oblate spheroid. Their velocities are initialized so they are rotating around the center axis.

Jason.

Eroding Fractal Terrains with Virtual Raindrops

A long while back I added a very simplistic fractal terrain simulator to Visions of Chaos. I had an idea to try and add erosion simulation into the existing code to get some more realistic terrain shapes.

Generating the inital terrain

There are many ways to generate a terrain height array. For the terrain in this post I am using Perlin noise.

This is the 2D Perlin Noise image…

Fractal Terrain

…that is extruded to the following 3d terrain…

Fractal Terrain

An alternative method is to use 1/f Perlin Noise that creates this type of heightmap…

Fractal Terrain

..and this 3D terrain.

Fractal Terrain

Simulating erosion

Rather than try and replicate some of the much more complex simulators out there for wind and rain erosion (see for example here, here and here) I experimented with the simplest version I could come up with.

1. Take a single virtual rain drop and drop it to a random location on the terrain grid. Keep track of a totalsoil amount which starts at 0 when the drop is first dropped onto the terrain.
2. Look at its immediate 8 neighbors and find the lowest neighbor.
3. If no neighbors are lower deposit the remaining total soil carried and stop. This lead to large spikes as the totalsoil was too much. I since changed the drop rate to the same as the fixed depositrate. Technically this removes soil from the system, but the results are more realistic looking terrain.
4. Pick up a bit of the soil from the current spot (lower the terrain array at this point).

soilamount:=slope*erosionrate;
totalsoil:=totalsoil+soilamount;
heightarray[wx,wy]:=max(heightarray[wx,wy]-soilamount,0);

5. Move to the lowest neighbor point.
6. Deposit a bit of the carried soil at this location.

deposit:=soilamount*depositrate/slope;
heightarray[lx,ly]:=heightarray[lx,ly]+deposit;
totalsoil:=max(totalsoil-deposit,0);

7. Goto 1.

Repeat this for millions of drops.

The erosion and deposit steps (4 and 6 above) simulate the water flowing down hill, picking up and depositing soil as it goes.

To add some wind erosion you can smooth the height array every few thousand rain drops. I use a simple convolution blur every 5000 rain drops. This smooths the terrain out a little bit and can be thought of as wind smoothing the jagged edges of the terrain down a bit.

Erosion Movie

Here is a sample movie of the erosion process. This is a 13,500 frame 4K resolution movie. Each frame covers 10,000 virtual raindrops being dropped. This took days to render. 99% of the time is rendering the mesh with OpenGL. Simulating the raindrops is very fast.

and here are screenshots of every 2000th frame to show the erosion details more clearly.

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Fractal Terrain

Future ideas

The above is really just a quick experiment and I would like to spend more time on the more serious simulations of terrain generation and erosion. I have the book Texturing and Modeling, A Procedural Approach on my bookshelf and it contains many other terrain ideas.

Jason.