Vulkano Two Uniforms
This is a Vulkano two uniforms example, which is based on Vulkano image example.
・first uniform : (set = 0, binding = 0) uniform sampler2D
・second uniform : (set = 0, binding = 1) uniform Data
#[macro_use] extern crate vulkano; extern crate vulkano_shaders; extern crate vulkano_win; extern crate winit; extern crate cgmath; extern crate image; use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer}; use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; use vulkano::descriptor::descriptor_set::PersistentDescriptorSet; use vulkano::device::{Device, DeviceExtensions}; use vulkano::format::Format; use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract}; use vulkano::image::{SwapchainImage, ImmutableImage, Dimensions}; use vulkano::instance::{Instance, PhysicalDevice}; use vulkano::pipeline::GraphicsPipeline; use vulkano::pipeline::viewport::Viewport; use vulkano::sampler::{Sampler, SamplerAddressMode, Filter, MipmapMode}; use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError}; use vulkano::swapchain; use vulkano::sync::{GpuFuture, FlushError}; use vulkano::sync; use vulkano_win::VkSurfaceBuild; use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent}; use image::ImageFormat; use std::sync::Arc; static WINDOW_NAME: &str = "Image Test"; static WIN_WIDTH: f64 = 700.0; static WIN_HEIGHT: f64 = 650.0; fn main() { let extensions = vulkano_win::required_extensions(); let instance = Instance::new(None, &extensions, None).unwrap(); let physical = PhysicalDevice::enumerate(&instance).next().unwrap(); println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); let mut events_loop = EventsLoop::new(); let surface = WindowBuilder::new() .with_dimensions(winit::dpi::LogicalSize {width:WIN_WIDTH, height:WIN_HEIGHT}) .with_title(WINDOW_NAME.to_string()) .build_vk_surface(&events_loop, instance.clone()).unwrap(); let window = surface.window(); let queue_family = physical.queue_families().find(|&q| q.supports_graphics() && surface.is_supported(q).unwrap_or(false) ).unwrap(); let device_ext = DeviceExtensions { khr_swapchain: true, .. DeviceExtensions::none() }; let (device, mut queues) = Device::new(physical, physical.supported_features(), &device_ext, [(queue_family, 0.5)].iter().cloned()).unwrap(); let queue = queues.next().unwrap(); // initial_dimensions -> dimensions let mut dimensions = if let Some(dimensions) = window.get_inner_size() { let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); [dimensions.0, dimensions.1] } else { return; }; let (mut swapchain, images) = { let caps = surface.capabilities(physical).unwrap(); let usage = caps.supported_usage_flags; let alpha = caps.supported_composite_alpha.iter().next().unwrap(); let format = caps.supported_formats[0].0; Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha, PresentMode::Fifo, true, None).unwrap() }; #[derive(Debug, Clone)] struct Vertex { position: [f32; 2] } impl_vertex!(Vertex, position); let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter( device.clone(), BufferUsage::all(), [ Vertex { position: [-0.5, -0.5 ] }, Vertex { position: [-0.5, 0.5 ] }, Vertex { position: [ 0.5, -0.5 ] }, Vertex { position: [ 0.5, 0.5 ] }, ].iter().cloned() ).unwrap(); // uniform buffer let uniform_buffer = vulkano::buffer::cpu_pool::CpuBufferPool::<fs::ty::Data> ::new(device.clone(), vulkano::buffer::BufferUsage::all()); let vs = vs::Shader::load(device.clone()).unwrap(); let fs = fs::Shader::load(device.clone()).unwrap(); let render_pass = Arc::new( single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, format: swapchain.format(), samples: 1, } }, pass: { color: [color], depth_stencil: {} } ).unwrap() ); let (texture, tex_future) = { let image = image::load_from_memory_with_format(include_bytes!("ume-300x200.png"), ImageFormat::PNG).unwrap().to_rgba(); let image_data = image.into_raw().clone(); ImmutableImage::from_iter( image_data.iter().cloned(), // note Dimensions: image dimensions Dimensions::Dim2d { width: 300, height: 200 }, Format::R8G8B8A8Srgb, queue.clone() ).unwrap() }; let sampler = Sampler::new(device.clone(), Filter::Linear, Filter::Linear, MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(); let pipeline = Arc::new(GraphicsPipeline::start() .vertex_input_single_buffer::<Vertex>() .vertex_shader(vs.main_entry_point(), ()) .triangle_strip() .viewports_dynamic_scissors_irrelevant(1) .fragment_shader(fs.main_entry_point(), ()) .blend_alpha_blending() .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap()); let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state); let mut recreate_swapchain = false; let mut previous_frame_end = Box::new(tex_future) as Box<GpuFuture>; let mut mouse_pressed = false; let mut mouse_position = [0.5, 0.5]; let mut center = [0.5, 0.5]; loop { previous_frame_end.cleanup_finished(); if recreate_swapchain { dimensions = if let Some(dimensions) = window.get_inner_size() { let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); [dimensions.0, dimensions.1] } else { return; }; let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) { Ok(r) => r, Err(SwapchainCreationError::UnsupportedDimensions) => continue, Err(err) => panic!("{:?}", err) }; swapchain = new_swapchain; framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state); recreate_swapchain = false; } // mouse position if mouse_pressed { //println!("position: {} {}", mouse_position[0] as u32, mouse_position[1] as u32); let uvx = 2.0/(dimensions[0] as f32)* mouse_position[0] - 0.5; let uvy = 2.0/(dimensions[1] as f32)* mouse_position[1] - 0.5; //println!("uv: {} {}", uvx, uvy); center = [uvx, uvy]; } // uniform buffer let uniform_buffer_subbuffer = { let uniform_data = fs::ty::Data { center: center, }; uniform_buffer.next(uniform_data).unwrap() }; let set = Arc::new(PersistentDescriptorSet::start(pipeline.clone(), 0) .add_sampled_image(texture.clone(), sampler.clone()).unwrap() .add_buffer(uniform_buffer_subbuffer).unwrap() .build().unwrap() ); let (image_num, future) = match swapchain::acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; } Err(err) => panic!("{:?}", err) }; let clear_values = vec!([0.0, 0.0, 0.0, 1.0].into()); let cb = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()) .unwrap() .begin_render_pass(framebuffers[image_num].clone(), false, clear_values).unwrap() .draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), set.clone(), ()).unwrap() .end_render_pass().unwrap() .build().unwrap(); let future = previous_frame_end.join(future) .then_execute(queue.clone(), cb).unwrap() .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) .then_signal_fence_and_flush(); match future { Ok(future) => { previous_frame_end = Box::new(future) as Box<_>; } Err(FlushError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>; } Err(e) => { println!("{:?}", e); previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>; } } let mut done = false; events_loop.poll_events(|ev| { match ev { winit::Event::WindowEvent { event: winit::WindowEvent::CursorMoved { position: winit::dpi::LogicalPosition {x, y}, .. }, ..} => { mouse_position = [x as f32, y as f32]; //if mouse_pressed { // println!("position: {} {}", mouse_position[0] as u32, mouse_position[1] as u32); //} }, winit::Event::WindowEvent { event: winit::WindowEvent::MouseInput { state: _state, button: _button, ..}, ..} => { mouse_pressed = _button == winit::MouseButton::Left && _state == winit::ElementState::Pressed; if mouse_pressed {println!("Mouse {:?} {:?}", _button, _state);} }, Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true, _ => () } }); if done { return; } } } /// This method is called once during initialization, then again whenever the window is resized fn window_size_dependent_setup( images: &[Arc<SwapchainImage<Window>>], render_pass: Arc<RenderPassAbstract + Send + Sync>, dynamic_state: &mut DynamicState ) -> Vec<Arc<FramebufferAbstract + Send + Sync>> { let dimensions = images[0].dimensions(); let viewport = Viewport { origin: [0.0, 0.0], dimensions: [dimensions[0] as f32, dimensions[1] as f32], depth_range: 0.0 .. 1.0, }; dynamic_state.viewports = Some(vec!(viewport)); images.iter().map(|image| { Arc::new( Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap() ) as Arc<FramebufferAbstract + Send + Sync> }).collect::<Vec<_>>() } mod vs { vulkano_shaders::shader!{ ty: "vertex", src: " #version 450 layout(location = 0) in vec2 position; layout(location = 0) out vec2 tex_coords; void main() { gl_Position = vec4(position, 0.0, 1.0); tex_coords = position + vec2(0.5); }" } } mod fs { vulkano_shaders::shader!{ ty: "fragment", src: " #version 450 layout(location = 0) in vec2 tex_coords; layout(location = 0) out vec4 f_color; layout(set = 0, binding = 0) uniform sampler2D tex; layout(set = 0, binding = 1) uniform Data { vec2 center; } uniforms; const float refractance = 1.4; const vec3 eyeVector = vec3(0., 0., -1.); const float r = 0.3; bool inCircle(vec2 position, vec2 center, float size) { float len = length(position - center); return (len < size)? true: false; } void main() { vec2 center = uniforms.center; vec2 new_coords = tex_coords - center; float length_xy = length(new_coords); float z = sqrt(pow(r,2) - pow(length_xy,2)); float sin_thetai = sqrt(pow(r,2) - pow(z,2)) / r; float thetai = asin(sin_thetai); float sin_thetar = sin_thetai / refractance; float thetar = asin(sin_thetar); float lxy = z*tan(thetai - thetar); float deltax = lxy*new_coords.x/length_xy; float deltay = lxy*new_coords.y/length_xy; vec2 uv = (inCircle(tex_coords, center, r)) ? tex_coords - vec2(deltax, deltay): tex_coords; f_color = texture(tex, uv); }" } }