Skip to content

Commit

Permalink
bugfix for egui interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
altunenes committed Apr 17, 2024
1 parent 6fbc30e commit 5333d1f
Show file tree
Hide file tree
Showing 3 changed files with 333 additions and 1 deletion.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -345,4 +345,8 @@ path = "src/nebula.rs"

[[bin]]
name = "pixelsum"
path = "src/pixelsum.rs"
path = "src/pixelsum.rs"

[[bin]]
name = "smoothneurons"
path = "src/smoothneurons.rs"
109 changes: 109 additions & 0 deletions shaders/smoothneurons.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
const PI: f32 = 3.141592653589793;
struct TimeUniform {
time: f32,
};
@group(1) @binding(0)
var<uniform> u_time: TimeUniform;
fn oscillate(minValue: f32, maxValue: f32, interval: f32, currentTime: f32) -> f32 {
return minValue + (maxValue - minValue) * 0.5 * (sin(2.0 * PI * currentTime / interval) + 1.0);
}
struct Params {
lambda: f32,
theta: f32,
alpha:f32,
sigma: f32,
gamma: f32,
blue:f32,
};
@group(0) @binding(1)
var<uniform> params: Params;
fn random(st: vec2<f32>) -> vec2<f32> {
let st_new: vec2<f32> = vec2<f32>(
dot(st, vec2<f32>(127.1, 311.7)),
dot(st, vec2<f32>(269.5, 183.3))
);
return -1.0 + 2.0 * fract(sin(st_new) * 43758.5453123);
}
fn noise(st: vec2<f32>) -> f32 {
let i: vec2<f32> = floor(st);
let f: vec2<f32> = fract(st);
let u: vec2<f32> = f * f * (3.0 - 2.0 * f);
return mix(mix(dot(random(i + vec2<f32>(0.0, 0.0)), f - vec2<f32>(0.0, 0.0)),
dot(random(i + vec2<f32>(1.0, 0.0)), f - vec2<f32>(1.0, 0.0)), u.x),
mix(dot(random(i + vec2<f32>(0.0, 1.0)), f - vec2<f32>(0.0, 1.0)),
dot(random(i + vec2<f32>(1.0, 1.0)), f - vec2<f32>(1.0, 1.0)), u.x), u.y);
}

fn fbm(p: vec2<f32>) -> f32 {
var value: f32 = 0.0;
var amplitude: f32 = 0.5;
var p_var: vec2<f32> = p;
for (var i: i32 = 0; i < 5; i++) {
value += amplitude * noise(p_var);
p_var *= 2.0;
amplitude *= 0.5;
}
return value;
}
fn rotate2D(r: f32) -> mat2x2<f32> {
return mat2x2<f32>(cos(r), -sin(r), sin(r), cos(r));
}
@fragment
fn main(@builtin(position) FragCoord: vec4<f32>) -> @location(0) vec4<f32> {
let resolution: vec2<f32> = vec2<f32>(800.0, 450.0);
var uv: vec2<f32> = (FragCoord.xy / resolution.xy) - vec2<f32>(0.5, 0.5 * resolution.y / resolution.x);
var col: vec3<f32> = vec3<f32>(0.0, 0.0, 0.0);
let t: f32 = u_time.time;
let xVal4: f32 = oscillate(0.5, 0.51, 15.0, t);

var n: vec2<f32> = vec2<f32>(0.0, 0.0);
var q: vec2<f32>;
var N: vec2<f32> = vec2<f32>(0.0, 0.0);
var p: vec2<f32> = uv + t / 20.0;
var S: f32 = 15.0;
let m: mat2x2<f32> = rotate2D(xVal4);
var branchFactor: f32 = 1.85;

for(var j: i32 = 0; j < 40; j = j + 1){
p *= m;
n *= m;
q = p * S + f32(j) + n + t;

n += branchFactor * sin(q);
N += branchFactor * cos(q) / S * 2.5;
branchFactor *= 1.3 * atan(0.975);

S *= params.theta * tanh(3.45);
}

let pulse: f32 = sin(params.blue * t + length(p) + fbm(vec2<f32>(t * 0.1, length(p) * 2.1))) * 0.1 + params.blue;

let colorOffset: vec3<f32> = vec3<f32>(
params.lambda * smoothstep(0.4, 5.0, sin(n.x)),
params.alpha * smoothstep(3.0, 5.0, sin(n.y)),
params.sigma * smoothstep(0.0, 1.0, cos(n.x))
);

let flowColorChange: vec3<f32> = vec3<f32>(
1.5 * cos(3.0 * t + N.x),
0.5 * sin(3.0 * t + N.y),
1.5 * cos(3.0 * t + N.y)
);

let flowIntensity: vec3<f32> = vec3<f32>(
0.001 / length(0.3 * N),
smoothstep(0.1, 1.0, N.x),
smoothstep(1.5, 1.0, N.y)
);

col = (vec3<f32>(1.5 * pulse, 1.0 * pulse, 3.1 * pulse) * colorOffset + flowColorChange + flowIntensity) * ((1.0 * N.x + 1.0 * N.y + 0.001) + 0.0015 / length(1.0 * N));

let axonPulse: f32 = sin(t + length(p) * 10.0) * 0.5 + 0.5;
let axonColor: vec3<f32> = vec3<f32>(1.2, 0.7, 1.0);

let axonEffect: vec3<f32> = smoothstep(0.1, 2.55, axonPulse) * axonColor;

col += axonEffect;

return vec4<f32>(col,1.0);
}
219 changes: 219 additions & 0 deletions src/smoothneurons.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
use nannou::prelude::*;
use nannou_egui::{self, egui, Egui};
struct Model {
render_pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
time_uniform: wgpu::Buffer,
time_bind_group: wgpu::BindGroup,
params_uniform: wgpu::Buffer,
params_bind_group: wgpu::BindGroup,
settings:Settings,
egui:Egui,
}
struct Settings {
lambda: f32,
theta: f32,
alpha:f32,
sigma: f32,
gamma:f32,
blue:f32,
show_ui: bool,
}
#[repr(C)]
#[derive(Clone, Copy)]
struct Vertex {
position: [f32; 2],
}
const VERTICES: [Vertex; 6] = [
Vertex { position: [-1.0, -1.0] },
Vertex { position: [ 1.0, -1.0] },
Vertex { position: [-1.0, 1.0] },
Vertex { position: [ 1.0, -1.0] },
Vertex { position: [ 1.0, 1.0] },
Vertex { position: [-1.0, 1.0] },
];
fn main() {
nannou::app(model)
.update(update)
.run();
}
fn update(app: &App, model: &mut Model, update: Update) {
let egui = &mut model.egui;
egui.set_elapsed_time(update.since_start);
let ctx = egui.begin_frame();
if app.keys.down.contains(&Key::H) {
model.settings.show_ui = !model.settings.show_ui;
}
egui::Window::new("Shader Settings").show(&ctx, |ui| {
ui.add(egui::Slider::new(&mut model.settings.lambda, 1.0..=35.0).text("l"));
ui.add(egui::Slider::new(&mut model.settings.theta, -1.0..=4.5).text("t"));
ui.add(egui::Slider::new(&mut model.settings.alpha, 0.0..=5.0).text("a"));
ui.add(egui::Slider::new(&mut model.settings.sigma, -PI..=PI).text("r"));
ui.add(egui::Slider::new(&mut model.settings.gamma, -5.0..=5.0).text("g"));
ui.add(egui::Slider::new(&mut model.settings.blue, -PI..=PI).text("b"));

});
let params_data = [model.settings.lambda, model.settings.theta,model.settings.alpha, model.settings.sigma,model.settings.gamma,model.settings.blue];
let params_bytes = bytemuck::cast_slice(&params_data);
app.main_window().queue().write_buffer(&model.params_uniform, 0, &params_bytes);
}
fn raw_window_event(app: &App, model: &mut Model, event: &nannou::winit::event::WindowEvent) {
model.egui.handle_raw_event(event);
if let nannou::winit::event::WindowEvent::KeyboardInput { input, .. } = event {
if let (Some(nannou::winit::event::VirtualKeyCode::F), true) =
(input.virtual_keycode, input.state == nannou::winit::event::ElementState::Pressed)
{
let window = app.main_window();
let fullscreen = window.fullscreen().is_some();
window.set_fullscreen(!fullscreen);
}
}
}
fn model(app: &App) -> Model {
let w_id = app.new_window().raw_event(raw_window_event).
size(512, 512).view(view).build().unwrap();
let window = app.window(w_id).unwrap();
let device = window.device();
let format = Frame::TEXTURE_FORMAT;
let sample_count = window.msaa_samples();
let vs_desc = wgpu::include_wgsl!("../shaders/vs.wgsl");
let fs_desc = wgpu::include_wgsl!("../shaders/smoothneurons.wgsl");
let vs_mod = device.create_shader_module(vs_desc);
let fs_mod = device.create_shader_module(fs_desc);
let vertices_bytes = vertices_as_bytes(&VERTICES[..]);
let usage = wgpu::BufferUsages::VERTEX;
let vertex_buffer = device.create_buffer_init(&BufferInitDescriptor {
label: None,
contents: vertices_bytes,
usage,
});
let time_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: wgpu::BufferSize::new(std::mem::size_of::<f32>() as _),
},
count: None,
},
],
label: Some("time_bind_group_layout"),
});
let params_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("params_bind_group_layout"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: wgpu::BufferSize::new((std::mem::size_of::<f32>() * 6) as _),
},
count: None,
}],
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Pipeline Layout"),
bind_group_layouts: &[&params_bind_group_layout, &time_bind_group_layout],
push_constant_ranges: &[],
});
let render_pipeline = wgpu::RenderPipelineBuilder::from_layout(&pipeline_layout, &vs_mod)
.fragment_shader(&fs_mod)
.color_format(format)
.add_vertex_buffer::<Vertex>(&wgpu::vertex_attr_array![0 => Float32x2])
.sample_count(sample_count)
.build(device);
let time_uniform = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Time Uniform Buffer"),
size: std::mem::size_of::<f32>() as wgpu::BufferAddress,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let time_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &time_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: time_uniform.as_entire_binding(),
},
],
label: Some("time_bind_group"),
});
let settings = Settings {
lambda:25.0,
theta:1.5,
alpha:0.2,
sigma:1.2,
gamma:0.31,
blue:0.5,
show_ui:true,
};
let params_data = [settings.lambda, settings.theta, settings.alpha,settings.sigma,settings.gamma,settings.blue];
let params_bytes = bytemuck::cast_slice(&params_data);
let params_uniform = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Params Uniform"),
contents: params_bytes,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let params_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &params_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 1,
resource: params_uniform.as_entire_binding(),
},
],
label: Some("params_bind_group"),
});
let window = app.window(w_id).unwrap();
let egui = Egui::from_window(&window);
Model {
params_bind_group,
settings,
params_uniform,
egui,
vertex_buffer,
render_pipeline,
time_uniform,
time_bind_group,
}
}
fn view(app: &App, model: &Model, frame: Frame) {
let draw = app.draw();
draw.background().color(BLACK);
let time = app.time;
let time_bytes = time.to_ne_bytes();
let binding = app.main_window();
let queue = binding.queue();
{
let mut encoder = frame.command_encoder();
queue.write_buffer(&model.time_uniform, 0, &time_bytes);
let mut render_pass = wgpu::RenderPassBuilder::new()
.color_attachment(frame.texture_view(), |color| color)
.begin(&mut encoder);
render_pass.set_bind_group(0, &model.params_bind_group, &[]);
render_pass.set_bind_group(1, &model.time_bind_group, &[]);
render_pass.set_pipeline(&model.render_pipeline);
render_pass.set_vertex_buffer(0, model.vertex_buffer.slice(..));
let vertex_range = 0..VERTICES.len() as u32;
let instance_range = 0..1;
render_pass.draw(vertex_range, instance_range);
}
if model.settings.show_ui {
model.egui.draw_to_frame(&frame).unwrap();
}
if app.keys.down.contains(&Key::Space) {
let file_path = app
.project_path()
.expect("failed to locate project directory")
.join("frames")
.join(format!("{:0}.png", app.elapsed_frames()));
app.main_window().capture_frame(file_path);
}
}
fn vertices_as_bytes(data: &[Vertex]) -> &[u8] {
unsafe { wgpu::bytes::from_slice(data) }
}

0 comments on commit 5333d1f

Please sign in to comment.