I've had this idea kicking around in my head for years. The gist of it was "what if I made a simulation of gravity using cellular automata". Well, I finally got around to doing so. I'll give some technical details after, but here are some images of what came about:

This shows two fields blending together.

A heart-shaped block of mass causing interference patterns with itself.

Four "black holes" that developed.

Ended up fixing the blending of colors to get better spectrums.

It's just neat!

This inspires terrain generation.

The next few are just pretty:

Here are a few videos of it in action:

Technical details:
Mass and gravity are modeled as two 2D fields. The user inputs mass particles with a given mass, determined by the Divisor input (MaxMass / Divisor). As the simulation runs, it updates the gravity and mass fields based on each other. The mass field is conserved, meaning no particles will ever "disappear". The gravity field is calculated from the mass field and itself.

For each gravity cell, it looks at the mass field, and sets the gravity to MassValue shifted right by 3. It then takes the average of the gravity from all adjacent cells, and adds that to the current gravity from the mass field.

For each mass cell, it looks at the adjacent gravity field cells as well as its own gravitation field cell. It orders them by strength, and randomly picks the strongest gravitation to "fall" towards. This could mean "falling" toward its own cell, thus not moving. If a cell (other than itself) occupies the cell it tries to fall toward, it falls toward another random cell with the same gravitation strength. If all cells with the highest gravitational strength are occupied, it goes to the next strongest gravitational strength. It does this until there are no other cells, in which case it stays put.

You can find the code to this, and incidentally lots of other little toys I've made over the years, in my github: https://github.com/merthsoft/MooseLib/tree/main/GravityCa

If you want to play with it, here's a download link: https://merthsoft.com/GravityCA/Gravity.zip
Requires .net 8, should run anywhere with a .net 8 runtime (Windows, Mac, many Linuxes).

Controls:
Space - toggles simulation running or paused
Left click to add a mass with the current divisor
Right click to remove mass
Mose wheel adjusts the divisor
0 - Grayscale palette
1 - Rainbow palette
2- Two rainbows
3 - Three rainbows
4 - Four rainbows
5 - Six rainbows
6 - Eight rainbows
7 - Twelve rainbows
8 - Sixteen rainbows
9 - I dunno like sixhundred rainbows or somthing like that

1 through 0 on the number ROW (not numpad) will change the number of values used to render the gravity.

T - Draw debug text
M - Toggle mass renderer
G - Toggle gravity renderer
B - Toggle blending the colors between values

Z - Zero-out mass field
X - Zero-out gravity field
R - Randomly fill .01% of the remaining open mass field with the current divisor
F - Fill the mass field with the current divisor
I wasn't planning on revisiting this, but I ended up doing some work on it. It functions similarly, but there's been lots of optimizations and improvements. Here's a video:

Here's the code:
https://github.com/merthsoft/MooseLib/tree/main/GravityCa

Here's some stills:

This is a composite of the above two:

This one's my favorite so far:
I haven't looked into how this works much but the artifacts in the second, third, and fourth images remind me a lot of the sorts of problems you get because of the numeric instabilities inherent to erosion simulation.
I think you mean the dotting? Those are VERY high density mass spots that are driving the gravitational field very high at that point. In this iteration, I added a "vacuum energy" model. This causes lots of chaos, but a side effect is that the initial masses start to get very dense as they eat up all the newly spawning mass, which causes "stars" as seen there.
I added a 3D render mode. Lets you see black holes in action:

There's a release on github if you want to play with it:
https://github.com/merthsoft/MooseLib/releases/tag/gravity

Keys are:
https://github.com/merthsoft/MooseLib/blob/v0.6a/GravityCa/GravityGame.cs#L98

The 3D camera controls are bad right now.
Some more progress made:

Better camera controls. That's being controlled with a controller.

And a cube mode:

Question:
I want to accomplish two more things with the 3D renderer next:
1) More efficiently generate/reuse the VertexBuffer
2) Connect the cells when rendering (meaning, share vertices between adjacent cells)

The way I do the rendering right now, each time it renders, I then:

Code:
``` Assume VertexBuffer is TriangleList of VertexPositionColor Clear VertexBuffer For each (x,y) in the grid     Get the gravity as a percent     Get the color for the gravity based on that percent     Insert into VertexBuffer Quad made of triangles (x, percent * 100, y) - (x + 1, percent*100, y + 1) with color ```

What I would like to do is on startup:

Code:
``` Assume VertexBuffer is TriangleList of VertexPositionColor // If possible, prefer TraingleStrip Pre-build VertexBuffer with Triangles such that it creates a flat plane of transparent nodes connected to approximate a 2D grid of 1x1 cells ```

And then each render:

Code:
``` For each (x,y) in the grid     Get the gravity as a percent     Get the color for the gravity based on that percent     Update appropriate vertices in VertexBuffer         color = color         y = percent * 100 ```

I'm just not quite sure how to pre-generate the TriangleStrip (ideally) to accomplish the look I want and then the translation of (x, y) into appropriate VertexBuffer coordinates (I assume there will be several that I need to update per cell).
If you share vertices your quads will have internal color variation - if you want to keep the internal "flat shaded" effect you have now, then unfortunately you either have to duplicate vertices, or write some funky shader code to compute the color dynamically from the geometry GPU-side at render time.
What kind of internal color variation would occur? If it's a matter of blending between node colors, that would actually be able to save me some computation so might be useful. If it introduces more weirdness, that may even be a plus in terms of artistic usage.
I've got a few different ways to render it in 3D now. [url=https://imgur.com/a/JWJvbgk]here's an album[/img] of images and a sample of the deformed sheet:

And a demo:

And a download:
https://github.com/merthsoft/MooseLib/releases/tag/Gravity-v0.7a
It will blend between the node colors, however, it will only interpolate between the 3 colors of each triangle, so you will have a visible stripe along the diagonal edge through the center of each square cell.
Oh interesting. Probably not what I want. Ultimately, I was able to get the look I wanted (the deformed sheet), but it involves me doing a bunch of processing and still drawing an independent quad per cell. Basically just taking averages. This works fine, and I'm not up against any resource constraints (100FPS and 500MB memory--it's fine). I'm well under my default 100,000 node count.

Two things I need to consider:
1) Would it be better to generate the texture and use that instead of node colors? Would that allow me to share nodes without the issue you described? I'm assuming not, which implies to me it is indeed most efficient to just use PositionColor instead of PositionColorTexture.

2) I'm currently using "User Indexed Primitives". I think it would be more efficient to use graphics device vertex buffer.

Further thing I would like to do that I'm not quite sure how:
Build meshes for the topologies we have. Would be cool to have it be a torus when it's on a torus, be a sphere when it's on a sphere. And even further, being able to choose which geometry and which topology independently. That's a matter of knowing which edges connect where, so I think I can just use the mapping methods I already have at edge points, but there's probalby a more efficient wya.
I modified the simulation so that how much mass can exist at any given point is based on the gravity at that point. Here's a cool image from that and some 3D renders of that image:

And some videos of it in action:

When I first made this, I built it in a library I built on top of Monogame designed to make quick prototyping easy. It accomplished that, but that library is now impeding development. So, I pulled it out into its own repo. You can now find the code here:
https://github.com/merthsoft/GravityCa

A release is available that contains both the cross-platform OpenGL version and the Windows DirectX version:
https://github.com/merthsoft/GravityCa/releases/tag/v0.9a
merthsoft wrote:

Two things I need to consider:
1) Would it be better to generate the texture and use that instead of node colors? Would that allow me to share nodes without the issue you described? I'm assuming not, which implies to me it is indeed most efficient to just use PositionColor instead of PositionColorTexture.

you can generate uv coordinates which will avoid the issue and give you smooth interpolation. I don't think it should be any slower to generate a texture at roughly the same resolution as the grid itself.

merthsoft wrote:

2) I'm currently using "User Indexed Primitives". I think it would be more efficient to use graphics device vertex buffer.

Yes - using graphics device buffers is probably the most important performance improvement you can make here

merthsoft wrote:

Further thing I would like to do that I'm not quite sure how:
Build meshes for the topologies we have. Would be cool to have it be a torus when it's on a torus, be a sphere when it's on a sphere. And even further, being able to choose which geometry and which topology independently. That's a matter of knowing which edges connect where, so I think I can just use the mapping methods I already have at edge points, but there's probalby a more efficient wya.

the mesh topology would be pretty easy to do, but presumably you also want to remap the geometry into roughly that topology so you don't have giant triangles stretching across the whole screen?
[quote=elfprince]
you can generate uv coordinates which will avoid the issue and give you smooth interpolation. I don't think it should be any slower to generate a texture at roughly the same resolution as the grid itself.
[/quote]
Cool. I've already got the texture renderer (that's how the 2d one works--generate a texture and draw that. It's definitely way faster than the 3d one right now (I'm pretty sure under the hood it draws 2 triangles, but I've never actually looked into it). Then I can have it fill the buffers only when you switch render mode and then just update the coordinates to reflect the gravity/mass. Texture coords should never change. I'll maybe get to that eventually given:

Quote:
Yes - using graphics device buffers is probably the most important performance improvement you can make here

This will be my first next step. From what I've read this is indeed quite a meaningful difference, so good to have your confirmation.

Quote:
but presumably you also want to remap the geometry into roughly that topology so you don't have giant triangles stretching across the whole screen?

Yeah, and I'm not sure how to do that. But that's a more far off concern.

After switchign to device buffers, my plan is to get mouse input back to working appropriately. I want the user to be able to input mass in the 3D renderer from the mouse like they can in the 2D mode. understand how to cast a ray from the mouse to a plane, but unfortunately I don't necessarily have a flat plane, so i need to figure out intersection with the geometry in the buffers.

Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

»
» All times are UTC - 5 Hours

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Advertisement