Skip to content

Commit

Permalink
distorted voronoi shader
Browse files Browse the repository at this point in the history
  • Loading branch information
altunenes committed Mar 4, 2024
1 parent 08d3d6b commit df1961a
Show file tree
Hide file tree
Showing 3 changed files with 290 additions and 1 deletion.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,8 @@ path = "src/neurons.rs"

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

[[bin]]
name = "voronoiwgpu"
path = "src/voronoiwgpu.rs"
83 changes: 83 additions & 0 deletions shaders/voronoiwgpu.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
@group(0) @binding(0) var tex: texture_2d<f32>;
@group(0) @binding(1) var tex_sampler: sampler;
struct TimeUniform {
time: f32,
};

@group(1) @binding(0)
var<uniform> u_time: TimeUniform;
const PI: f32 = 3.14;

fn hash3(p: vec3<f32>) -> vec3<f32> {
let q: vec3<f32> = vec3<f32>(
dot(p, vec3<f32>(127.1, 311.7, 189.2)),
dot(p, vec3<f32>(269.5, 183.3, 324.7)),
dot(p, vec3<f32>(419.2, 371.9, 128.5))
);
return fract(sin(q) * 43758.5453);
}

fn osc(minValue: f32, maxValue: f32, interval: f32, currentTime: f32) -> f32 {
return minValue + (maxValue - minValue) * 0.5 * (sin(2.0 * PI * currentTime / interval) + 1.0);
}

fn noise(x: vec3<f32>, v: f32) -> f32 {
let p: vec3<f32> = floor(x);
let f: vec3<f32> = fract(x);
let s: f32 = 1.0 + 444.0 * v;
var va: f32 = 0.0;
var wt: f32 = 0.0;
var k: i32 = -2;
while (k <= 1) {
var j: i32 = -2;
while (j <= 1) {
var i: i32 = -2;
while (i <= 1) {
let g: vec3<f32> = vec3<f32>(f32(i), f32(j), f32(k));
let o: vec3<f32> = hash3(p + g);
let r: vec3<f32> = g - f + o + 0.5;
let d: f32 = dot(r, r);
let w: f32 = pow(1.0 - smoothstep(0.0, 1.414, sqrt(d)), s);
va += o.z * w;
wt += w;
i += 1;
}
j += 1;
}
k += 1;
}
return va / wt;
}

fn fBm(p: vec3<f32>, v: f32) -> f32 {
var sum: f32 = 0.0;
let scramb: f32 = osc(0.0, 24.0, 20.0, u_time.time);
var amp: f32 = 1.0;
var mutable_p = p; // Copy the immutable parameter to a mutable variable
var i: i32 = 0;
while (i < 4) {
sum += amp * noise(mutable_p, v);
amp *= 0.5;
mutable_p *= 2.0; // Modify the mutable copy
i += 1;
}
return sum;
}

@fragment
fn main(@builtin(position) FragCoord: vec4<f32>, @location(0) tex_coords: vec2<f32>) -> @location(0) vec4<f32> {
let uv: vec2<f32> = FragCoord.xy / vec2<f32>(800.0, 600.0); // Assuming a resolution, replace with actual uniform if available
let p: vec2<f32> = uv * 2.0 - 1.0;
let rd: vec3<f32> = normalize(vec3<f32>(p.x, p.y, 1.0));
let pos: vec3<f32> = vec3<f32>(0.0, 0.0, 1.0) * u_time.time + rd * 10.0;

// Use fBm for UV distortion
let distortion: f32 = fBm(pos, 0.1) * 0.1;
let distortedUV: vec2<f32> = uv + vec2<f32>(distortion, distortion);

// Sample the texture with distorted UV coordinates
let texColor: vec4<f32> = textureSample(tex, tex_sampler, distortedUV);

// Output the color
return vec4<f32>(texColor.rgb, 1.0);
}
202 changes: 202 additions & 0 deletions src/voronoiwgpu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
use nannou::image;
use nannou::image::GenericImageView;
use nannou::prelude::*;
use std::path::PathBuf;
struct Model {
bind_group: wgpu::BindGroup,
render_pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
time_uniform: wgpu::Buffer,
time_bind_group: wgpu::BindGroup,
}
fn get_image_path(relative_path: &str) -> PathBuf {
let current_dir = std::env::current_dir().unwrap();
current_dir.join(relative_path)
}
#[repr(C)]
#[derive(Clone, Copy)]
struct Vertex {
position: [f32; 2],
}
//this time not triangles :-D
const VERTICES: [Vertex; 4] = [
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 img_path = get_image_path("images/ferris.jpg");
let image = image::open(img_path).unwrap();
let (img_w, img_h) = image.dimensions();
let w_id = app
.new_window()
.size(img_w, img_h)
.view(view)
.build()
.unwrap();
let window = app.window(w_id).unwrap();
let device = window.device();
let format = Frame::TEXTURE_FORMAT;
let msaa_samples = window.msaa_samples();
let vs_desc = wgpu::include_wgsl!("../shaders/verteximg.wgsl");
let fs_desc = wgpu::include_wgsl!("../shaders/voronoiwgpu.wgsl");
let vs_mod = device.create_shader_module(vs_desc);
let fs_mod = device.create_shader_module(fs_desc);
let texture = wgpu::Texture::from_image(&window, &image);
let texture_view = texture.view().build();
let sampler_desc = wgpu::SamplerBuilder::new().into_descriptor();
let sampler_filtering = wgpu::sampler_filtering(&sampler_desc);
let sampler = device.create_sampler(&sampler_desc);
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 texture_bind_group_layout = create_bind_group_layout(device, texture_view.sample_type(), sampler_filtering);
let bind_group_layout =
create_bind_group_layout(device, texture_view.sample_type(), sampler_filtering);
let bind_group = create_bind_group(device, &bind_group_layout, &texture_view, &sampler);
let pipeline_layout = create_pipeline_layout(device, &[&texture_bind_group_layout, &time_bind_group_layout]);
let render_pipeline = create_render_pipeline(
device,
&pipeline_layout,
&vs_mod,
&fs_mod,
format,
msaa_samples,
);
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_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"),
});
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_pipeline(&model.render_pipeline);
render_pass.set_bind_group(1, &model.time_bind_group, &[]);
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 create_bind_group_layout(
device: &wgpu::Device,
texture_sample_type: wgpu::TextureSampleType,
sampler_filtering: bool,
) -> wgpu::BindGroupLayout {
wgpu::BindGroupLayoutBuilder::new()
.texture(
wgpu::ShaderStages::FRAGMENT,
false,
wgpu::TextureViewDimension::D2,
texture_sample_type,
)
.sampler(wgpu::ShaderStages::FRAGMENT, sampler_filtering)
.build(device)
}
fn create_bind_group(
device: &wgpu::Device,
layout: &wgpu::BindGroupLayout,
texture: &wgpu::TextureView,
sampler: &wgpu::Sampler,
) -> wgpu::BindGroup {
wgpu::BindGroupBuilder::new()
.texture_view(texture)
.sampler(sampler)
.build(device, layout)
}
fn create_pipeline_layout(
device: &wgpu::Device,
bind_group_layouts: &[&wgpu::BindGroupLayout],
) -> wgpu::PipelineLayout {
let desc = wgpu::PipelineLayoutDescriptor {
label: None,
bind_group_layouts,
push_constant_ranges: &[],
};
device.create_pipeline_layout(&desc)
}
fn create_render_pipeline(
device: &wgpu::Device,
layout: &wgpu::PipelineLayout,
vs_mod: &wgpu::ShaderModule,
fs_mod: &wgpu::ShaderModule,
dst_format: wgpu::TextureFormat,
sample_count: u32,
) -> wgpu::RenderPipeline {
wgpu::RenderPipelineBuilder::from_layout(layout, vs_mod)
.fragment_shader(fs_mod)
.color_format(dst_format)
.add_vertex_buffer::<Vertex>(&wgpu::vertex_attr_array![0 => Float32x2])
.sample_count(sample_count)
.primitive_topology(wgpu::PrimitiveTopology::TriangleStrip)
.build(device)
}
fn vertices_as_bytes(data: &[Vertex]) -> &[u8] {
unsafe { wgpu::bytes::from_slice(data) }
}

0 comments on commit df1961a

Please sign in to comment.