Rust Vulkano プロジェクト( https://github.com/vulkano-rs/vulkano ) の triangle サンプルです。
マウスで簡単にズームや回転が出来るように、ArcBallCamera( arcball crate) を追加しています。
実行結果
スタート時
zoom ( マウスホイールのアップ・ダウン )
rotation ( 左ボタンのドラッグ )
pan ( 右ボタンのドラッグ )
プログラム
#![allow(dead_code)] #[macro_use] extern crate vulkano; #[macro_use] extern crate vulkano_shader_derive; extern crate winit; extern crate vulkano_win; extern crate arcball; extern crate cgmath; use vulkano_win::VkSurfaceBuild; use vulkano::buffer::BufferUsage; use vulkano::buffer::CpuAccessibleBuffer; use vulkano::command_buffer::AutoCommandBufferBuilder; use vulkano::command_buffer::DynamicState; use vulkano::device::Device; use vulkano::framebuffer::Framebuffer; use vulkano::framebuffer::Subpass; use vulkano::instance::Instance; use vulkano::instance::PhysicalDevice; use vulkano::pipeline::GraphicsPipeline; use vulkano::pipeline::viewport::Viewport; use vulkano::swapchain; use vulkano::swapchain::PresentMode; use vulkano::swapchain::SurfaceTransform; use vulkano::swapchain::Swapchain; use vulkano::swapchain::AcquireError; use vulkano::swapchain::SwapchainCreationError; use vulkano::sync::now; use vulkano::sync::GpuFuture; use std::sync::Arc; use std::mem; fn main() { // Instance let instance = { // instance extension let extensions = vulkano_win::required_extensions(); //println!("extensions {:?}", extensions); Instance::new(None, &extensions, None).expect("failed to create Vulkan instance") }; // Physical Device let physical = PhysicalDevice::enumerate(&instance).next().expect("no device available"); //println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); // Window let mut events_loop = winit::EventsLoop::new(); let window = winit::WindowBuilder::new() .with_dimensions(800, 600) .with_title(format!("Vulkano Triangle")) .build_vk_surface(&events_loop, instance.clone()).unwrap(); // Vulkan Device // queue family let queue_family = physical.queue_families() .find(|&q| q.supports_graphics() && window.surface().is_supported(q).unwrap_or(false)) .expect("couldn't find a graphical queue family"); // Device and queues let (device, mut queues) = { // device extension let device_ext = vulkano::device::DeviceExtensions { khr_swapchain: true, .. vulkano::device::DeviceExtensions::none() }; // Device and queues Device::new(physical, physical.supported_features(), &device_ext, [(queue_family, 0.5)].iter().cloned()).expect("failed to create device") }; // let queue = queues.next().unwrap(); // dimension let mut dimensions; // Swapchain and images let (mut swapchain, mut images) = { // Surface capabilities let caps = window.surface().capabilities(physical) .expect("failed to get surface capabilities"); // dimension dimensions = caps.current_extent.unwrap(); // composite alpha let alpha = caps.supported_composite_alpha.iter().next().unwrap(); // format let format = caps.supported_formats[0].0; // Swapchain and images Swapchain::new(device.clone(), window.surface().clone(), caps.min_image_count, format, dimensions, 1, caps.supported_usage_flags, &queue, SurfaceTransform::Identity, alpha, PresentMode::Fifo, true, None).expect("failed to create swapchain") }; // vertex buffer let vertex_buffer = { #[derive(Debug, Clone)] struct Vertex { position: [f32; 2] } impl_vertex!(Vertex, position); CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ Vertex { position: [-0.5, -0.25] }, Vertex { position: [0.0, 0.5] }, Vertex { position: [0.25, -0.1] } ].iter().cloned()).expect("failed to create buffer") }; // uniform buffer let uniform_buffer = vulkano::buffer::cpu_pool::CpuBufferPool::<vs::ty::Data> ::new(device.clone(), vulkano::buffer::BufferUsage::all()); let vs = vs::Shader::load(device.clone()).expect("failed to create shader module"); let fs = fs::Shader::load(device.clone()).expect("failed to create shader module"); // render pass 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()); // pipeline let pipeline = Arc::new(GraphicsPipeline::start() .vertex_input_single_buffer() .vertex_shader(vs.main_entry_point(), ()) .triangle_list() .viewports_dynamic_scissors_irrelevant(1) .fragment_shader(fs.main_entry_point(), ()) .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap()); // framebuffer let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None; // 下の「if framebuffers.is_none() { }」がないとき: error: type annotations needed let mut recreate_swapchain = false; let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>; //println!("window size {},{}", dimensions[0], dimensions[1]); let persp_proj:cgmath::Matrix4<f32> = cgmath::perspective(cgmath::Deg(65.0), dimensions[0] as f32 / dimensions[1] as f32, 0.01, 100.0); let mut arcball_camera = { let look_at = cgmath::Matrix4::look_at(cgmath::Point3::new(0.0, 0.0, 2.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, 1.0, 0.0)); arcball::ArcballCamera::new(&look_at, 0.05, 4.0, [dimensions[0] as f32, dimensions[1] as f32]) }; // let mut arcball_camera_mat4: [[f32;4];4] = arcball_camera.get_mat4().into(); //println!("arcball camera mat4: {:?}", arcball_camera_mat4); let mut mouse_pressed = [false, false]; let mut prev_mouse: Option<(f64,f64)> = None; loop { previous_frame_end.cleanup_finished(); // recreate swapchain (if it needs ) if recreate_swapchain { dimensions = window.surface().capabilities(physical) .expect("failed to get surface capabilities") .current_extent.unwrap(); let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) { Ok(r) => r, Err(SwapchainCreationError::UnsupportedDimensions) => { continue; }, Err(err) => panic!("{:?}", err) }; mem::replace(&mut swapchain, new_swapchain); mem::replace(&mut images, new_images); framebuffers = None; recreate_swapchain = false; } // recreate framebuffers (framebuffers contains an Arc on the old swapchain) if framebuffers.is_none() { let new_framebuffers = Some(images.iter().map(|image| { Arc::new(Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()) }).collect::<Vec<_>>()); mem::replace(&mut framebuffers, new_framebuffers); } let proj = (persp_proj * arcball_camera.get_mat4()).into(); let uniform_buffer_subbuffer = { let uniform_data = vs::ty::Data { proj : proj, }; uniform_buffer.next(uniform_data).unwrap() }; let set = Arc::new(vulkano::descriptor::descriptor_set::PersistentDescriptorSet::start(pipeline.clone(), 0) .add_buffer(uniform_buffer_subbuffer).unwrap() .build().unwrap() ); let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; }, Err(err) => panic!("{:?}", err) }; let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap() .begin_render_pass(framebuffers.as_ref().unwrap()[image_num].clone(), false, vec![[0.0, 0.0, 1.0, 1.0].into()]).unwrap() // draw .draw(pipeline.clone(), DynamicState { line_width: None, viewports: Some(vec![Viewport { origin: [0.0, 0.0], dimensions: [dimensions[0] as f32, dimensions[1] as f32], depth_range: 0.0 .. 1.0, }]), scissors: None, }, vertex_buffer.clone(), set.clone(), ()).unwrap() .end_render_pass().unwrap() .build().unwrap(); let future = previous_frame_end.join(acquire_future) .then_execute(queue.clone(), command_buffer).unwrap() .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) .then_signal_fence_and_flush().unwrap(); previous_frame_end = Box::new(future) as Box<_>; let mut done = false; events_loop.poll_events(|ev| { match ev { winit::Event::WindowEvent { event: winit::WindowEvent::MouseMoved { position: (x, y), ..}, ..} if prev_mouse.is_none() => { prev_mouse = Some((x, y)); }, winit::Event::WindowEvent { event: winit::WindowEvent::MouseMoved { position: (x, y), .. }, ..} => { //println!("MouseMoved {},{}", x, y); let prev = prev_mouse.unwrap(); if mouse_pressed[0] { arcball_camera.rotate(cgmath::Vector2::new(prev.0 as f32, prev.1 as f32), cgmath::Vector2::new(x as f32, y as f32)); arcball_camera_mat4 = arcball_camera.get_mat4().into(); println!("rotate mat4: {:?}", arcball_camera_mat4); } else if mouse_pressed[1] { let mouse_delta = cgmath::Vector2::new((x - prev.0) as f32, -(y - prev.1) as f32); arcball_camera.pan(mouse_delta, 0.16); arcball_camera_mat4 = arcball_camera.get_mat4().into(); println!("pan mat4: {:?}", arcball_camera_mat4); } prev_mouse = Some((x, y)); }, winit::Event::WindowEvent { event: winit::WindowEvent::MouseInput { state: _state, button: _button, ..}, ..} => { //println!("button {:?}", button); if _button == winit::MouseButton::Left { mouse_pressed[0] = _state == winit::ElementState::Pressed; } else if _button == winit::MouseButton::Right { mouse_pressed[1] = _state == winit::ElementState::Pressed; } }, winit::Event::WindowEvent { event: winit::WindowEvent::MouseWheel { delta: winit::MouseScrollDelta::LineDelta(_, y), .. }, ..} => { //println!("ScrollDelta {}", y); arcball_camera.zoom(y, 0.1); arcball_camera_mat4 = arcball_camera.get_mat4().into(); println!("zoom mat4: {:?}", arcball_camera_mat4); }, winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => done = true, _ => () } }); if done { return; } } } mod vs { #[derive(VulkanoShader)] #[ty = "vertex"] #[src = " #version 450 layout(location = 0) in vec2 position; layout(set = 0, binding = 0) uniform Data { mat4 proj; } uniforms; void main() { gl_Position = uniforms.proj * vec4(position, 0.0, 1.0); } "] struct Dummy; } mod fs { #[derive(VulkanoShader)] #[ty = "fragment"] #[src = " #version 450 layout(location = 0) out vec4 f_color; void main() { f_color = vec4(1.0, 0.0, 0.0, 1.0); } "] struct Dummy; }
Cargo.toml
[package] name = "triangle-arcball" version = "0.1.0" authors = ["xxxxxx"] [dependencies] vulkano = "0.7.2" vulkano-shader-derive = "0.7.2" vulkano-win = "0.7.2" cgmath = "0.15.0" image = "0.14.0" winit = "0.7.0" time = "0.1.37" arcball = "0.3.0"