Last active
February 11, 2025 08:03
-
-
Save voldien/e98ac65251664f007f208921687cffe9 to your computer and use it in GitHub Desktop.
Game of Life Compute Shader without any conditions - OpenGL/Vulkan
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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