From c78d38154cd7c6dfd7a7a65ce6af56c5a4c8570d Mon Sep 17 00:00:00 2001 From: altunenes Date: Thu, 14 Mar 2024 15:52:29 +0300 Subject: [PATCH] asahi2 --- Cargo.toml | 6 ++- shaders/asahi2.wgsl | 80 +++++++++++++++++++++++++++++ src/asahi2.rs | 122 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 shaders/asahi2.wgsl create mode 100644 src/asahi2.rs diff --git a/Cargo.toml b/Cargo.toml index 826bf83..c77324f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -311,4 +311,8 @@ path = "src/voronoiwgpu2.rs" [[bin]] name = "fluid" -path = "src/fluid.rs" \ No newline at end of file +path = "src/fluid.rs" + +[[bin]] +name = "asahi2" +path = "src/asahi2.rs" \ No newline at end of file diff --git a/shaders/asahi2.wgsl b/shaders/asahi2.wgsl new file mode 100644 index 0000000..858e7ec --- /dev/null +++ b/shaders/asahi2.wgsl @@ -0,0 +1,80 @@ +//see my shadertoy code: https://www.shadertoy.com/view/MX23Wz; +//note, I used petal polar GLSL function from the user BenoitArbelot, (2020): https://www.shadertoy.com/view/ttySz3 +// Global constants +const PI: f32 = 3.141592653589793; +struct TimeUniform { + time: f32, +}; +@group(1) @binding(0) +var u_time: TimeUniform; +fn rot(a: f32) -> mat2x2 { + return mat2x2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +fn DrawPetalPolar(uv: vec2, pos: vec2, size: f32, dir: vec2, colorDirection: f32) -> vec4 { + var dist: vec2 = uv - pos; + + let angle: f32 = -atan2(dir.y, dir.x); + dist = dist * (rot(angle) * 0.8); + + dist.x = dist.x - (size * 0.25); + + let r: f32 = length(dist) * 1.5; + let a: f32 = atan2(dist.y, dist.x); + + var f: f32 = -1.0; + if (a > PI * 0.5 || a < -PI * 0.5) { + f = size * cos(a * 2.0); + } + + let petalMask: f32 = smoothstep(0.0, -1.0, (r - f) / fwidth(r - f)); + + var color: vec3; + if (colorDirection > 0.0) { + color = mix(vec3(1.0, 1.0, 0.0), vec3(0.0, 0.0, 0.0), r / (size * 1.0)); + } else { + color = mix(vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 0.0), r / (size * 1.0)); + } + + return vec4(color, petalMask); +} + +@fragment +fn main(@builtin(position) FragCoord: vec4) -> @location(0) vec4 { + let resolution: vec2 = vec2(800.0, 450.0); + var uv: vec2 = 1.3 * (FragCoord.xy - 0.5 * resolution) / resolution.y; + let bgColor: vec3 = vec3(1.0, 1.0, 1.0); + var fragColor: vec4 = vec4(bgColor, 1.0); + + let petalSize: f32 = 0.40; + let space: f32 = (2.5 * PI / 15.0) * (1.0 + 0.2); + let phase: f32 = sin(u_time.time / 2.0) * PI; + + let left: vec2 = vec2(-0.5, 0.0); + let right: vec2 = vec2(0.5, 0.0); + + // Left side + for (var i: f32 = 0.0; i < 2.0 * PI; i = i + space) { + let pos: vec2 = left + vec2(cos(i), sin(i)) * 0.25; + let angle: f32 = i + phase; + let dir: vec2 = vec2(cos(angle), sin(angle)); + + let leftcolor: vec4 = DrawPetalPolar(uv, pos, petalSize, dir, 1.0); + fragColor = mix(fragColor, leftcolor, leftcolor.a); + } + + // Right side + for (var i: f32 = 0.0; i < 2.0 * PI; i = i + space) { + let pos: vec2 = right + vec2(cos(i), sin(i)) * 0.25; + let angle: f32 = i - phase; + let dir: vec2 = vec2(cos(angle), sin(angle)); + + let colors: vec4 = DrawPetalPolar(uv, pos, petalSize, dir, -1.0); + fragColor = mix(fragColor, colors, colors.a); + } + + return fragColor; +} diff --git a/src/asahi2.rs b/src/asahi2.rs new file mode 100644 index 0000000..64d3a6d --- /dev/null +++ b/src/asahi2.rs @@ -0,0 +1,122 @@ +use nannou::prelude::*; +struct Model { + bind_group: wgpu::BindGroup, + render_pipeline: wgpu::RenderPipeline, + vertex_buffer: wgpu::Buffer, + time_uniform: wgpu::Buffer, + time_bind_group: wgpu::BindGroup, +} +#[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).run(); +} +fn model(app: &App) -> Model { + let w_id = app.new_window().size(800, 450).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/asahi2.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::() as _), + }, + count: None, + }, + ], + label: Some("time_bind_group_layout"), + }); + let bind_group_layout = wgpu::BindGroupLayoutBuilder::new().build(device); + let bind_group = wgpu::BindGroupBuilder::new().build(device, &bind_group_layout); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Pipeline Layout"), + bind_group_layouts: &[&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::(&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::() 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"), + }); + Model { + bind_group, + vertex_buffer, + render_pipeline, + time_uniform, + time_bind_group, + } +} +fn view(app: &App, model: &Model, frame: Frame) { + let mut encoder = frame.command_encoder(); + let time = app.time as f32; + let time_bytes = time.to_ne_bytes(); + let binding = app.main_window(); + let queue = binding.queue(); + 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.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 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) } +} \ No newline at end of file