Skip to content

Commit

Permalink
cellular automata working ish
Browse files Browse the repository at this point in the history
  • Loading branch information
arcadeperfect committed Dec 7, 2024
1 parent ad8c897 commit b04f785
Show file tree
Hide file tree
Showing 8 changed files with 362 additions and 32 deletions.
23 changes: 20 additions & 3 deletions src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ fn ui_system(
) {
// let mut radius = params.radius;

let z = 0;

egui::SidePanel::left("control_panel")
.resizable(false)
.default_width(600.0)
Expand All @@ -35,17 +37,32 @@ fn ui_system(
ui.label("radius");
ui.add(egui::Slider::new(&mut params.radius, 0.0..=1.).text("radius"));
ui.add(egui::Slider::new(&mut params.noise_amplitude, 0.0..=5.).text("amplitude"));
ui.add(egui::Slider::new(&mut params.noise_scale, 0.0..=2.).text("scale"));
ui.add(egui::Slider::new(&mut params.noise_scale, 0.0..=1.).text("frequency"));
ui.add(egui::Slider::new(&mut params.noise_offset, 0.0..=20.).text("offset"));
ui.add(egui::Slider::new(&mut params.power_bias, 0.0..=6.).text("power bias"));
ui.add(egui::Slider::new(&mut params.flatness, 0.0..=6.).text("flatness"));
ui.add(egui::Slider::new(&mut params.steepness, 0.0..=6.).text("steepness"));
ui.add(egui::Slider::new(&mut params.mix, 0.0..=1.).text("mix"));
ui.add(egui::Slider::new(&mut params.warp_amount, 0.0..=0.2).text("warp amount"));
ui.add(egui::Slider::new(&mut params.warp_scale, 1.0..=20.).text("warp scale"));
ui.horizontal(|ui| {
ui.label("war iterations");
ui.label("warp iterations");
ui.add(
egui::DragValue::new(&mut shader_configurator.shader_configs[1].iterations)
.range(0..=50),
.range(0..=50),
);
});
ui.add(egui::Slider::new(&mut params.noise_weight, 0.0..=1.).text("noise weight"));
ui.horizontal(|ui| {
ui.label("ca iterations");
ui.add(
egui::DragValue::new(&mut shader_configurator.shader_configs[3].iterations)
.range(0..=50),
);
});
ui.add(egui::Slider::new(&mut params.ca_thresh, 0.1..=20.).text("thresh"));
ui.add(egui::Slider::new(&mut params.ca_search_radius, 0.1..=6.).text("search radius"));

});
});
}
67 changes: 53 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ mod gui;

const GENERATE_CIRCLE_HANDLE: Handle<Shader> = Handle::weak_from_u128(13378847158248049035);
const DOMAIN_WARP_HANDLE: Handle<Shader> = Handle::weak_from_u128(23378847158248049035);
const PRE_CA_HANDLE: Handle<Shader> = Handle::weak_from_u128(23378547158240049035);
const CA_HANDLE: Handle<Shader> = Handle::weak_from_u128(23378547158248049035);
const EXTRACT_HANDLE: Handle<Shader> = Handle::weak_from_u128(33378847158248049035);
const UTIL_NOISE_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(14378847158248049035);
const UTIL_VECTOR_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(25378847158248049035);
Expand All @@ -35,8 +37,15 @@ struct ParamsUniform {
noise_scale: f32,
noise_amplitude: f32,
noise_offset: f32,
power_bias: f32,
flatness: f32,
steepness:f32,
mix:f32,
warp_amount: f32,
warp_scale: f32,
warp_scale: f32,
noise_weight: f32,
ca_thresh: f32,
ca_search_radius: f32
}

impl Default for ParamsUniform {
Expand All @@ -48,8 +57,15 @@ impl Default for ParamsUniform {
noise_scale: 1.0,
noise_amplitude: 1.0,
noise_offset: 0.0,
power_bias: 1.8,
flatness: 1.5,
steepness: 1.3,
mix: 0.5,
warp_amount: 0.0,
warp_scale: 0.0,
noise_weight: 0.53,
ca_thresh: 7.5,
ca_search_radius: 3.8
}
}
}
Expand Down Expand Up @@ -91,6 +107,7 @@ enum ComputeNodeLabel {
Compute1,
Compute2,
Compute3,
Compute4,
Final,
}

Expand All @@ -107,9 +124,13 @@ impl Plugin for GpuReadbackPlugin {
iterations: 5,
},
ShaderConfig {
shader_handle: DOMAIN_WARP_HANDLE,
shader_handle: PRE_CA_HANDLE,
iterations: 1,
},
ShaderConfig {
shader_handle: CA_HANDLE,
iterations: 16,
},
];

app.insert_resource(ShaderConfigurator { shader_configs });
Expand Down Expand Up @@ -140,6 +161,18 @@ impl Plugin for GpuReadbackPlugin {
"shaders/domain_warp.wgsl",
Shader::from_wgsl
);
load_internal_asset!(
app,
CA_HANDLE,
"shaders/ca.wgsl",
Shader::from_wgsl
);
load_internal_asset!(
app,
PRE_CA_HANDLE,
"shaders/pre_ca_noise.wgsl",
Shader::from_wgsl
);
load_internal_asset!(
app,
EXTRACT_HANDLE,
Expand All @@ -149,11 +182,9 @@ impl Plugin for GpuReadbackPlugin {
}

fn finish(&self, app: &mut App) {

let shader_configs = app.world().resource::<ShaderConfigurator>().clone();

let render_app = app.sub_app_mut(RenderApp);

let render_app = app.sub_app_mut(RenderApp);

render_app.insert_resource(shader_configs);

Expand Down Expand Up @@ -194,6 +225,13 @@ impl Plugin for GpuReadbackPlugin {
is_final: false,
},
);
render_graph.add_node(
ComputeNodeLabel::Compute4,
ComputeNode {
pipeline_index: 3,
is_final: false,
},
);

// Add final pass
render_graph.add_node(
Expand All @@ -207,7 +245,8 @@ impl Plugin for GpuReadbackPlugin {
// Add edges between nodes
render_graph.add_node_edge(ComputeNodeLabel::Compute1, ComputeNodeLabel::Compute2);
render_graph.add_node_edge(ComputeNodeLabel::Compute2, ComputeNodeLabel::Compute3);
render_graph.add_node_edge(ComputeNodeLabel::Compute3, ComputeNodeLabel::Final);
render_graph.add_node_edge(ComputeNodeLabel::Compute3, ComputeNodeLabel::Compute4);
render_graph.add_node_edge(ComputeNodeLabel::Compute4, ComputeNodeLabel::Final);
}
}

Expand Down Expand Up @@ -355,7 +394,7 @@ struct ShaderConfigurator {
#[derive(Resource)]
struct ComputePipelines {
layout: BindGroupLayout,
pipeline_configs: Vec<CachedComputePipelineId>,
pipeline_configs: Vec<CachedComputePipelineId>,
final_pass: CachedComputePipelineId,
}

Expand Down Expand Up @@ -413,16 +452,18 @@ impl FromWorld for ComputePipelines {
}
}

fn prepare_bind_group_selection(mut commands: Commands, pipelines: Res<ComputePipelines>, shader_configurator: Res<ShaderConfigurator>) {
fn prepare_bind_group_selection(
mut commands: Commands,
pipelines: Res<ComputePipelines>,
shader_configurator: Res<ShaderConfigurator>,
) {
let mut selectors = HashMap::new();
let mut total_iterations = 0;
let mut node: u32 = 0;



for _ in &pipelines.pipeline_configs {
let mut node_selections = Vec::new();

let i = shader_configurator.shader_configs[node as usize].iterations;
for _ in 0..i {
node_selections.push(total_iterations % 2);
Expand Down Expand Up @@ -459,7 +500,6 @@ impl render_graph::Node for ComputeNode {
let encoder = render_context.command_encoder();
let selectors = world.resource::<BindGroupSelection>();
let shader_configurator = world.resource::<ShaderConfigurator>();


if self.is_final {
if let Some(pipeline) = pipeline_cache.get_compute_pipeline(pipelines.final_pass) {
Expand Down Expand Up @@ -488,9 +528,8 @@ impl render_graph::Node for ComputeNode {

if let Some(pipeline) = pipeline_cache.get_compute_pipeline(pipeline_id) {
let iters = shader_configurator.shader_configs[self.pipeline_index].iterations;
println!("new node");

for iteration in 0..iters {
println!("iters: {}", iters);
encoder.push_debug_group(&format!(
"Compute pass {} iteration {}",
self.pipeline_index, iteration
Expand Down
140 changes: 140 additions & 0 deletions src/shaders/ca.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
struct Params {
dimensions: u32,
radius: f32,
noise_seed: u32,
noise_scale: f32,
noise_amplitude: f32,
noise_offset: f32,
power_bias: f32,
flatness: f32,
steepness: f32,
mix: f32,
warp_amount: f32,
warp_scale: f32,
noise_weight: f32,
ca_thresh: f32,
ca_search_radius: f32
}

fn get_weighted_neighbor_count(x: i32, y: i32, radius: f32) -> f32 {
var found = 0.0;
let dim = i32(params.dimensions);
let r = i32(ceil(radius));

for(var i = -r; i <= r; i++) {
for(var j = -r; j <= r; j++) {
let dist_sq = f32(i * i + j * j);
if (dist_sq > radius * radius) {
continue;
}

if(i == 0 && j == 0) {
continue;
}

let new_x = x + i;
let new_y = y + j;

if(new_x < 0 || new_x >= dim || new_y < 0 || new_y >= dim) {
// found += 1.0; // Treat out-of-bounds as walls
continue;
}

let new_pos = vec2<i32>(new_x, new_y);
let v = textureLoad(input_texture, new_pos).a;

// Weight by distance from center
let weight = 1.0 - sqrt(dist_sq) / radius;
found += v * weight;
}
}
return found;
}



@group(0) @binding(0) var<uniform> params: Params;
@group(0) @binding(1) var input_texture: texture_storage_2d<rgba32float, read>;
@group(0) @binding(2) var output_texture: texture_storage_2d<rgba32float, write>;

// @compute @workgroup_size(16, 16)
// fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
// let x = global_id.x;
// let y = global_id.y;

// if (x >= params.dimensions || y >= params.dimensions) {
// return;
// }

// let upos = vec2<i32>(i32(x), i32(y));
// let current = textureLoad(input_texture, upos);

// let nze = current.a;

// let scaled_radius = params.ca_search_radius * (8.0 / (f32(params.dimensions) / 128.0));
// let neighbor_weight = get_weighted_neighbor_count(i32(x), i32(y), scaled_radius);

// let base_threshold = params.ca_thresh * (scaled_radius / 4.0);

// // Increased stability bias for more persistence
// let stability_bias = 0.25;
// let threshold = select(
// base_threshold,
// base_threshold * (1.0 - stability_bias),
// nze > 0.5
// );

// // Wider transition zone
// let transition_width = 0.2 * base_threshold;
// let diff = neighbor_weight - threshold;

// // Use the transition value directly instead of as a selector
// let transition = 1.0 - smoothstep(-transition_width, transition_width, diff);

// // Strong bias toward maintaining current state unless transition is significant
// let persistence = 0.7;
// let v = select(
// transition,
// nze,
// abs(nze - transition) < persistence
// );

// var result = current.x - nze;
// result = clamp(result, 0., 1.);

// textureStore(output_texture, upos, vec4f(result, current.y, current.z, nze));
// }

@compute @workgroup_size(16, 16)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let x = global_id.x;
let y = global_id.y;

if (x >= params.dimensions || y >= params.dimensions) {
return;
}

let upos = vec2<i32>(i32(x), i32(y));
let current = textureLoad(input_texture, upos);

let nze = current.a;

// let result = nze;

// let caves = 1.0;

let nbs = get_weighted_neighbor_count(i32(x), i32(y), params.ca_search_radius);

var caves = select(
0.,
1.,
nbs > params.ca_thresh
);

var result = current.r - caves;

// // result = current.z - result;
// result = clamp (result, 0., 1.);

textureStore(output_texture, upos, vec4f(current.x, current.y, current.z, caves));
}
9 changes: 6 additions & 3 deletions src/shaders/domain_warp.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ struct Params {
noise_scale: f32,
noise_amplitude: f32,
noise_offset: f32,
warp_amount: f32, // Controls the intensity of the warping
warp_scale: f32, // Controls the scale of the noise used for warping
power_bias: f32,
flatness: f32,
steepness:f32,
mix:f32,
warp_amount: f32,
warp_scale: f32,
}

@group(0) @binding(0) var<uniform> params: Params;
Expand All @@ -34,7 +38,6 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
return;
}


let upos = vec2<i32>(i32(x), i32(y));

// // Just output solid red to verify shader is running
Expand Down
5 changes: 4 additions & 1 deletion src/shaders/extract.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {

let current = textureLoad(input_texture, upos);

textureStore(output_texture, upos, vec4f(1.- current.x,current.y,current.z,1.));
var r = current.r - current.a;
r = clamp(r, 0., 1.);

textureStore(output_texture, upos, vec4f(r,current.y,current.z,1.));
}
Loading

0 comments on commit b04f785

Please sign in to comment.