compute-shaders icon indicating copy to clipboard operation
compute-shaders copied to clipboard

Learning compute shaders in public, in Godot 4

Experiments with Compute Shaders

Projects within:

Slime Life
image image

How this could be useful to you

  • Has a couple of rather different examples leveraging compute shaders (both 2D)
  • Has a special ComputeManager that creates nice abstraction on top of Godot Compute Shader RenderingDevice pattern.

So, what is this ComputeManager?

ComputeManager

The abstraction layer I built to dramatically simplify the complexity of compute shaders, from my perspective.

I can only keep so much complexity in my head, and this approach simplifies so much.

  • (Almost) No thinking about how to turn data in C# into data GLSL will understand - essentially, only use struct with primitive fields, or lists of them.
  • Write any number of pipelines which will be sequentially executed when you call execute() on the ComputeManager
  • You can signify buffers with ids, for example, from an enum to simplify your code and not deal with Rid.
  • Easily read from, update, or clear buffers using the above ids pattern.

Notes

  • Currently only supports StructuredBuffer, but could easily be extended to others with the same pattern.
  • Currently does not support using a portion of a buffer (all or nothing), but again, easy to modify this.
  • You can always dip down to the lower layer of abstraction (Godot layer).

Example

Writing pipelines using this pattern is easy.

This is a slightly simplified version of what is in Slime.cs.

It's a multi-pipeline / multi-shader compute pipeline and easily fits on a screen.

public override void _Ready() {
    computeManager = new ComputeManager();

    // Prepare our texture that represents the world
    var trailMapImage = Image.Create(width, height, false, Image.Format.Rgba8);
    trailMapDisplayTexture = ImageTexture.CreateFromImage(trailMapImage);
    trailMapReadData = trailMapImage.GetData();
    
    // Main Pipeline
    computeManager
        .AddPipeline("res://Slime/slime.glsl", agentManager.settings.numAgents, 1, 1)
        .StoreAndAddStep((int) Buffers.Agents, agentManager.InitializeAgents())
        .StoreAndAddStep((int) Buffers.AgentParams, agentManager.settings)
        .StoreAndAddStep((int) Buffers.TrailMapReadData, trailMapReadData)
        .StoreAndAddStep((int) Buffers.TrailMapWriteData, trailMapReadData)
        .Build();

    // Diffuse Pipeline
    computeManager
        .AddPipeline("res://Slime/slime_diffuse.glsl", (uint) (width * height), 1, 1)
        .StoreAndAddStep((int) Buffers.DiffuseParams, diffusionManager.settings)
        .AddStep((int) Buffers.TrailMapWriteData)
        .AddStep((int) Buffers.TrailMapReadData)
        .Build();
    
    displayTexture = GetNode<Sprite>("Sprite").Texture as ImageTexture;
}

public override void _Process(double delta) {
    time += delta;

    // Because of our double buffer + swap + double buffer, we're back to TrailMapWriteData
    computeManager.UpdateBuffer((int) Buffers.TrailMapWriteData, trailMapReadData);

    computeManager.UpdateBuffer((int) Buffers.AgentParams, agentManager.settings with {
        delta = (float) delta, time = (float) time,
    });

    computeManager.UpdateBuffer((int) Buffers.DiffuseParams, diffusionManager.settings with {
        delta = (float) delta
    });

    // Execute the pipeline
    computeManager.Execute();

    trailMapReadData = computeManager.GetDataFromBuffer((int) Buffers.TrailMapReadData);

    // Update the texture
    displayTexture.Update(
        Image.CreateFromData(width, height, false, Image.Format.Rgba8, trailMapReadData)
    );
}

Slime

Heavily used: Coding Adventure: Ant and Slime Simulations by Sebastian Lague for learning / foundation.

Updates:

  • [x] Added mouse behavior to allow drawing slime

image

Life

Heavily inspired by: https://particle-life.com/

Todo

  • [ ] Spend more time on this one to figure out how to optimize the behavior.
    • Right now it compares every particle to every other particle while executing the compute shader, which is crazy.
  • [ ] Add a UI for modifying the Attraction Matrix and how many types of particles there are.

Not sure that using MultiMesh2D is the right approach either.

image