compute_shader.glsl 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. #[compute]
  2. #version 460
  3. // Instruct the GPU to use 8x8x1 = 64 local invocations per workgroup.
  4. layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
  5. // Prepare memory for the image, which will be both read and written to
  6. // `restrict` is used to tell the compiler that the memory will only be accessed
  7. // by the `heightmap` variable.
  8. layout(r8, binding = 0) restrict uniform image2D heightmap;
  9. // `readonly` is used to tell the compiler that we will not write to this memory.
  10. // This allows the compiler to make some optimizations it couldn't otherwise.
  11. layout(rgba8, binding = 1) restrict readonly uniform image2D gradient;
  12. // This function is the GPU counterpart of `compute_island_cpu()` in `main.gd`.
  13. void main() {
  14. // Grab the current pixel's position from the ID of this specific invocation ("thread").
  15. ivec2 coords = ivec2(gl_GlobalInvocationID.xy);
  16. ivec2 dimensions = imageSize(heightmap);
  17. // Calculate the center of the image.
  18. // Because we are working with integers ('round numbers') here,
  19. // the result will be floored to an integer.
  20. ivec2 center = dimensions / 2;
  21. // Calculate the smallest distance from center to edge.
  22. int smallest_radius = min(center.x, center.y);
  23. // Calculate the distance from the center of the image to the current pixel.
  24. float dist = distance(coords, center);
  25. // Retrieve the range of the gradient image.
  26. int gradient_max_x = imageSize(gradient).x - 1;
  27. // Calculate the gradient index based on the distance from the center.
  28. // `mix()` functions similarly to `lerp()` in GDScript.
  29. int gradient_x = int(mix(0.0, float(gradient_max_x), dist / float(smallest_radius)));
  30. // Retrieve the gradient value at the calculated position.
  31. ivec2 gradient_pos = ivec2(gradient_x, 0);
  32. vec4 gradient_color = imageLoad(gradient, gradient_pos);
  33. // Even though the image format only has the red channel,
  34. // this will still return a vec4: `vec4(red, 0.0, 0.0, 1.0)`
  35. vec4 pixel = imageLoad(heightmap, coords);
  36. // Multiply the pixel's red channel by the gradient's red channel
  37. // (or any RGB channel, they're all the same except for alpha).
  38. pixel.r *= gradient_color.r;
  39. // If the pixel is below a certain threshold, this sets it to 0.0.
  40. // The `step()` function is like `clamp()`, but it returns 0.0 if the value is
  41. // below the threshold, or 1.0 if it is above.
  42. //
  43. // This is why we multiply it by the pixel's value again: to get the original
  44. // value back if it is above the threshold. This shorthand replaces an `if`
  45. // statement, which would cause branching and thus potentially slow down the
  46. // shader.
  47. pixel.r = step(0.2, pixel.r) * pixel.r;
  48. // Store the pixel back into the image.
  49. // WARNING: make sure you are writing to the same coordinate that you read from.
  50. // If you don't, you may end up writing to a pixel, before that pixel is read
  51. // by a different invocation and cause errors.
  52. imageStore(heightmap, coords, pixel);
  53. }