Skip to content

Commit

Permalink
fake fluid shader and resize textures
Browse files Browse the repository at this point in the history
  • Loading branch information
altunenes committed Mar 11, 2024
1 parent 6510ff0 commit 05583e0
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,7 @@ path = "src/voronoiwgpu.rs"
[[bin]]
name = "voronoiwgpu2"
path = "src/voronoiwgpu2.rs"

[[bin]]
name = "fluid"
path = "src/fluid.rs"
Binary file removed images/crab.png
Binary file not shown.
Binary file modified images/ferris.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/rusty.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions shaders/fluid.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@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;
@fragment
fn main(@builtin(position) FragCoord: vec4<f32>, @location(0) tex_coords: vec2<f32>) -> @location(0) vec4<f32> {
let resolution: vec2<f32> = vec2<f32>(800.0, 600.0);
var uv: vec2<f32> = (FragCoord.xy * 3.0 - resolution) / min(resolution.x, resolution.y);
var col: vec3<f32> = vec3<f32>(0.0, 0.0, 0.0);
let frequency: f32 = 1.0;
for (var j: f32 = 0.0; j < 2.2; j = j + 1.0) {
for (var i: f32 = 1.0; i < 5.0; i = i + 1.0) {
uv.x = uv.x + (0.2 / (i + j) * sin(i * atan(u_time.time) * 2.0 * uv.y + (u_time.time * 0.1) + i * j));
uv.y = uv.y + (1.0 / (i + j) * cos(i * 0.6 * uv.x + (u_time.time * 0.12) + i * j));

let angle: f32 = u_time.time * 0.01;
let rotation: mat2x2<f32> = mat2x2<f32>(cos(angle), -sin(angle), sin(angle), cos(angle));
uv = rotation * uv;
}

let texColor: vec3<f32> = textureSample(tex, tex_sampler, uv).xyz;

let lenSq: f32 = atan(uv.y);
let col1: vec3<f32> = 0.1 + 0.5 * cos(frequency * (5.0 + u_time.time) + vec3<f32>(0.0, 0.5, 5.0) + PI * vec3<f32>(5.0 * lenSq));
let col2: vec3<f32> = 0.2 + 0.1 * cos(frequency * (1.1 + u_time.time) + PI * vec3<f32>(lenSq));
let col3: vec3<f32> = 0.2 + 3.1 * cos(frequency * (1.0 + u_time.time) + vec3<f32>(1.0, 0.5, 0.0) + PI * vec3<f32>(2.0 * sin(lenSq)));

col = col + texColor * (col1 + col2 + col3 + col3);
}
col = col / 9.0;

let bg: vec3<f32> = vec3<f32>(1.0, 1.0, 1.0);
col = mix(col, bg, 1.0 - smoothstep(0.0, abs(sin(u_time.time * 0.05) * 3.0), length(uv) - 0.1));

return vec4<f32>(col, 1.0);
}
196 changes: 196 additions & 0 deletions src/fluid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
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],
}
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/rusty.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/fluid.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 05583e0

Please sign in to comment.