God-Machine/Assets/Compute Shaders/automata.acompute

140 lines
No EOL
3.9 KiB
Text

#kernel Seed
#kernel Automaton
#kernel Blit
#extension GL_ARB_gpu_shader_int64 : require
layout(rgba8, set = 0, binding = 0) uniform image2D _RenderTarget;
layout(r16f, set = 0, binding = 2) uniform image2D _AutomatonFrom;
layout(r16f, set = 0, binding = 3) uniform image2D _AutomatonTo;
layout(binding = 1) uniform UniformBufferObject {
vec4 _Exposure;
};
layout(push_constant, std430) uniform Params {
uint64_t _UpperLeftMask;
uint64_t _UpperRightMask;
uint64_t _LowerLeftMask;
uint64_t _LowerRightMask;
};
float pseudo(vec2 v) {
v = fract(v/128.)*128. + vec2(-64.340622, -72.465622);
return fract(dot(v.xyx * v.xyy, vec3(20.390625, 60.703125, 2.4281209)));
}
[numthreads(8, 8, 1)]
void Seed() {
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
vec2 seeds = vec2(0.0, 0.0);
float seed = pseudo(vec2(float(uv.x) * 0.1 + seeds.x, float(uv.y) * 0.1 + seeds.x * 3));
if (seed < 0.75) seed = 0.0;
else seed = 1.0;
imageStore(_AutomatonFrom, uv, vec4(seed));
}
uint64_t encode_tile_to_uint(ivec2 uv) {
uint64_t tile_bits = 0;
for (int y = 0; y < 8; ++y) {
for (int x = 0; x < 8; ++x) {
uint bit_index = x + y * 8; // Convert to 1D index in 64 bit uint
ivec2 world_coords = uv + ivec2(-x, -y);
uint64_t cell_value = int(imageLoad(_AutomatonFrom, world_coords % 512).r);
tile_bits |= (cell_value << bit_index);
}
}
return tile_bits;
}
uint sum_uint_bits(uint64_t i) {
uint sum = 0;
while (i != 0) {
sum += uint(i & 1);
i >>= 1;
}
return sum;
}
[numthreads(8, 8, 1)]
void Automaton() {
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
int cell = int(imageLoad(_AutomatonFrom, uv).r);
uint64_t top_row_mask = 18374686479671623680UL;
uint64_t left_column_mask = 9259542123273814144UL;
// GAME OF LIFE
// uint64_t upper_left_mask = 770;
// uint64_t upper_right_mask = 49216 & ~(left_column_mask);
// uint64_t lower_left_mask = 144959613005987840UL & ~(top_row_mask);
// uint64_t lower_right_mask = 4665729213955833856UL & ~(top_row_mask | left_column_mask);
// BUGS
// uint64_t upper_left_mask = 69540876599103UL;
// uint64_t upper_right_mask = 278163506396412UL & ~(left_column_mask);
// uint64_t lower_left_mask = 4557430888798814208UL & ~(top_row_mask);
// uint64_t lower_right_mask = 18229723555195256832UL & ~(top_row_mask | left_column_mask);
uint64_t upper_left_mask = _UpperLeftMask;
uint64_t upper_right_mask = _UpperRightMask & ~(left_column_mask);
uint64_t lower_left_mask = _LowerLeftMask & ~(top_row_mask);
uint64_t lower_right_mask = _LowerRightMask & ~(top_row_mask | left_column_mask);
uint64_t upper_left_quadrant_bits = encode_tile_to_uint(uv) & upper_left_mask;
uint64_t upper_right_quadrant_bits = encode_tile_to_uint(uv + ivec2(7, 0)) & upper_right_mask;
uint64_t lower_left_quadrant_bits = encode_tile_to_uint(uv + ivec2(0, 7)) & lower_left_mask;
uint64_t lower_right_quadrant_bits = encode_tile_to_uint(uv + ivec2(7, 7)) & lower_right_mask;
uint neighbor_count = 0;
neighbor_count += sum_uint_bits(upper_left_quadrant_bits);
neighbor_count += sum_uint_bits(upper_right_quadrant_bits);
neighbor_count += sum_uint_bits(lower_left_quadrant_bits);
neighbor_count += sum_uint_bits(lower_right_quadrant_bits);
// for (int x = -1; x <= 1; ++x) {
// for (int y = -1; y <= 1; ++y) {
// if (x == 0 && y == 0) continue;
// ivec2 texcoords = uv + ivec2(x, y);
// texcoords = texcoords % 512;
// neighbor_count += int(imageLoad(_AutomatonFrom, texcoords).r);
// }
// }
if (neighbor_count <= 1) cell = 0;
if (neighbor_count == 3) cell = 1;
if (neighbor_count >= 4) cell = 0;
// if (neighbor_count <= 33) cell = 0;
// if (34 <= neighbor_count && neighbor_count <= 45) cell = 1;
// if (58 <= neighbor_count && neighbor_count <= 121) cell = 0;
imageStore(_AutomatonTo, uv, vec4(cell));
}
[numthreads(8, 8, 1)]
void Blit() {
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
float automata = imageLoad(_AutomatonTo, uv / 2).r;
imageStore(_RenderTarget, uv, vec4(automata, 0, 0, 1.0));
}