Skip to content

Instantly share code, notes, and snippets.

@voldien
Last active February 11, 2025 08:03
Show Gist options
  • Save voldien/e98ac65251664f007f208921687cffe9 to your computer and use it in GitHub Desktop.
Save voldien/e98ac65251664f007f208921687cffe9 to your computer and use it in GitHub Desktop.
Game of Life Compute Shader without any conditions - OpenGL/Vulkan
#version 460
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_compute_shader : enable
#extension GL_EXT_control_flow_attributes : enable
layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
layout(set = 0, binding = 0, r8ui) uniform restrict readonly uimage2D previousCellsTexture;
layout(set = 0, binding = 1, r8ui) uniform restrict writeonly uimage2D currentCellsTexture;
layout(set = 0, binding = 2, rgba8) uniform restrict writeonly image2D renderTexture;
/* Cell Alive lookup table. */
const int GOFLUT[9] = {0, 0, 1, 1, 0, 0, 0, 0, 0};
/* Cell Dead lookup table. */
const int GOFLUTDEAD[9] = {0, 0, 0, 1, 0, 0, 0, 0, 0};
const int KernelAliveMatrix[9] = {1, 1, 1, 1, 0, 1, 1, 1, 1};
/* Custom color for each possible neighbor combination. */
const vec3 color[9] = {vec3(0, 0, 0), vec3(0, 1, 0), vec3(1, 0, 0), vec3(0, 0, 1), vec3(0, 1, 1),
vec3(0.4, 0.3, 0.4), vec3(0.1, 0, 1), vec3(0.1, 1, 0), vec3(0, 0, 0)};
/* Game of Life without any conditions. */
void main() {
/* */
if (any(greaterThan(gl_GlobalInvocationID.xy, imageSize(renderTexture)))) {
return;
}
/* Get pixel coordinate. */
const ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
/* Get current cell state, alive or dead, clamped. */
const uint cell = min(imageLoad(previousCellsTexture, pixel_coords).r, 1);
/* Sum of all neighbors alive state. */
uint sum = 0;
/* Check Each cell on the kernel. sums the number of alive cells. */
[[unroll]] for (int y = -1; y <= 1; y++) {
[[unroll]] for (int x = -1; x <= 1; x++) {
const uint index = (x + 1) + (y + 1) * 3;
/* Compute neighbor cell, wrap around edge. */
const ivec2 offsetCordinate = (pixel_coords + ivec2(x, y)) % imageSize(previousCellsTexture);
/* */
sum += min(imageLoad(previousCellsTexture, offsetCordinate).r, 1) * KernelAliveMatrix[index];
}
}
/* Compute if cell is alive. */
const uint IsDeadCell = uint(step(float(cell), 0.5));
/* Sum of cell alive state and dead cell state. */
const uint result = (GOFLUT[sum] * cell) + GOFLUTDEAD[sum] * IsDeadCell;
/* Update the current cell state. */
imageStore(currentCellsTexture, pixel_coords, uvec4(result));
/* Apply gamma correction. */
const vec3 finalColor = color[sum];
/* Update the render texture in order to display as a texture. */
imageStore(renderTexture, pixel_coords, vec4(finalColor.rgb, 1));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment