Skip to content
Snippets Groups Projects
Unverified Commit 6bdd6c04 authored by John Hunter's avatar John Hunter :minidisc:
Browse files

various overhauls to data formats

parent fc455c91
No related branches found
No related tags found
No related merge requests found
#version 450 #version 450
layout(location=0)in vec3 fragColor; layout(location=0)in vec3 normal;
layout(location=0)out vec4 f_color; layout(location=0)out vec4 f_color;
const vec3 light=normalize(vec3(4,6,8)); layout(set=0,binding=0)uniform Data{
vec4[32]pos;
vec4[32]col;
uint light_count;
}uniforms;
void main(){ void main(){
f_color=vec4(vec3(dot(fragColor,light))*.5+.5,1.); vec3 accum=vec3(0.,0.,0.);
for(int i=0;i<uniforms.light_count;i++)
{
accum+=uniforms.col[i].xyz*((dot(normalize(normal),uniforms.pos[i].xyz)*.5)+.5);
}
f_color=vec4(accum,1.);
} }
\ No newline at end of file
use egui::{Color32, Frame, Id, ScrollArea, TextEdit, TextStyle}; use egui::{
plot::{Line, Plot, PlotPoints},
Color32, Frame, Id, ScrollArea, TextEdit, TextStyle,
};
use egui_winit_vulkano::Gui; use egui_winit_vulkano::Gui;
use crate::objects::{Light, Mesh};
fn sized_text(ui: &mut egui::Ui, text: impl Into<String>, size: f32) { fn sized_text(ui: &mut egui::Ui, text: impl Into<String>, size: f32) {
ui.label(egui::RichText::new(text).size(size)); ui.label(egui::RichText::new(text).size(size));
} }
...@@ -17,6 +22,11 @@ Vulkan(o) is hard, that I know... ...@@ -17,6 +22,11 @@ Vulkan(o) is hard, that I know...
pub struct GState { pub struct GState {
pub cursor_sensitivity: f32, pub cursor_sensitivity: f32,
pub move_speed: f32, pub move_speed: f32,
pub meshes: Vec<Mesh>,
pub lights: Vec<Light>,
pub fps: [f64; 128],
} }
impl Default for GState { impl Default for GState {
...@@ -24,6 +34,11 @@ impl Default for GState { ...@@ -24,6 +34,11 @@ impl Default for GState {
Self { Self {
cursor_sensitivity: 1.0, cursor_sensitivity: 1.0,
move_speed: 1.0, move_speed: 1.0,
meshes: vec![],
lights: vec![],
fps: [0.0; 128],
} }
} }
} }
...@@ -40,11 +55,37 @@ pub fn gui_up(gui: &mut Gui, state: &mut GState) { ...@@ -40,11 +55,37 @@ pub fn gui_up(gui: &mut Gui, state: &mut GState) {
sized_text(ui, "Settings", 32.0); sized_text(ui, "Settings", 32.0);
}); });
ui.separator(); ui.separator();
ui.vertical_centered(|ui| { egui::ScrollArea::vertical().show(ui, |ui| {
//ui.heading("Camera Control"); ui.vertical_centered(|ui| {
ui.add(egui::Slider::new(&mut state.cursor_sensitivity, 0.0..=2.0).text("Mouse Sensitivity")); ui.heading("Camera Control");
ui.add(egui::Slider::new(&mut state.move_speed, 0.0..=2.0).text("Movement Speed")); ui.add(egui::Slider::new(&mut state.cursor_sensitivity, 0.0..=2.0).text("Mouse Sensitivity"));
}); ui.add(egui::Slider::new(&mut state.move_speed, 0.0..=2.0).text("Movement Speed"));
ui.heading("Meshes");
for mesh in &mut state.meshes {
ui.label(mesh.name.clone());
ui.add(egui::Slider::new(&mut mesh.pos.x, -100.0..=100.0).text("Position.x"));
ui.add(egui::Slider::new(&mut mesh.pos.y, -100.0..=100.0).text("Position.y"));
ui.add(egui::Slider::new(&mut mesh.pos.z, -100.0..=100.0).text("Position.z"));
ui.add(egui::Slider::new(&mut mesh.rot.x.0, 0.0..=360.0).text("Rotation.x"));
ui.add(egui::Slider::new(&mut mesh.rot.y.0, 0.0..=360.0).text("Rotation.y"));
ui.add(egui::Slider::new(&mut mesh.rot.z.0, 0.0..=360.0).text("Rotation.z"));
}
ui.heading("Lights");
for light in &mut state.lights {
ui.label("Light");
ui.add(egui::Slider::new(&mut light.pos.x, -100.0..=100.0).text("Position.x"));
ui.add(egui::Slider::new(&mut light.pos.y, -100.0..=100.0).text("Position.y"));
ui.add(egui::Slider::new(&mut light.pos.z, -100.0..=100.0).text("Position.z"));
ui.add(egui::Slider::new(&mut light.colour.x, 0.0..=1.0).text("Colour.r"));
ui.add(egui::Slider::new(&mut light.colour.y, 0.0..=1.0).text("Colour.g"));
ui.add(egui::Slider::new(&mut light.colour.z, 0.0..=1.0).text("Colour.b"));
}
let fps: PlotPoints = state.fps.iter().enumerate().map(|(x,y)| [x as f64,*y]).collect::<Vec<_>>().into();
let line = Line::new(fps);
ui.heading("FPS");
Plot::new("fps").view_aspect(2.0).show(ui, |plot_ui| plot_ui.line(line));
});
});
}); });
}); });
} }
...@@ -24,13 +24,19 @@ use obj::{LoadConfig, ObjData}; ...@@ -24,13 +24,19 @@ use obj::{LoadConfig, ObjData};
use rodio::{source::Source, Decoder, OutputStream}; use rodio::{source::Source, Decoder, OutputStream};
use std::io::Cursor; use std::io::Cursor;
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
use vulkano::buffer::CpuBufferPool;
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::DeviceOwned;
use vulkano::format::Format; use vulkano::format::Format;
use vulkano::image::AttachmentImage; use vulkano::image::AttachmentImage;
use vulkano::memory::allocator::StandardMemoryAllocator; use vulkano::memory::allocator::{MemoryUsage, StandardMemoryAllocator};
use vulkano::pipeline::graphics::depth_stencil::DepthStencilState; use vulkano::pipeline::graphics::depth_stencil::DepthStencilState;
use vulkano::pipeline::graphics::rasterization::CullMode; use vulkano::pipeline::graphics::rasterization::CullMode;
use vulkano::pipeline::graphics::rasterization::FrontFace::Clockwise; use vulkano::pipeline::graphics::rasterization::FrontFace::Clockwise;
use vulkano::pipeline::PipelineBindPoint;
use vulkano::shader::ShaderModule;
use vulkano::swapchain::{PresentMode, SwapchainPresentInfo}; use vulkano::swapchain::{PresentMode, SwapchainPresentInfo};
use vulkano::VulkanLibrary; use vulkano::VulkanLibrary;
use winit::event::{DeviceEvent, DeviceId, ElementState, MouseButton, VirtualKeyCode}; use winit::event::{DeviceEvent, DeviceId, ElementState, MouseButton, VirtualKeyCode};
...@@ -70,8 +76,12 @@ use winit::{ ...@@ -70,8 +76,12 @@ use winit::{
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
use crate::gui::*;
mod gui; mod gui;
use crate::gui::*;
mod objects;
use crate::objects::*;
pub type MemoryAllocator = StandardMemoryAllocator;
fn main() { fn main() {
// The first step of any Vulkan program is to create an instance. // The first step of any Vulkan program is to create an instance.
...@@ -81,7 +91,7 @@ fn main() { ...@@ -81,7 +91,7 @@ fn main() {
// All the window-drawing functionalities are part of non-core extensions that we need // All the window-drawing functionalities are part of non-core extensions that we need
// to enable manually. To do so, we ask the `vulkano_win` crate for the list of extensions // to enable manually. To do so, we ask the `vulkano_win` crate for the list of extensions
// required to draw to a window. // required to draw to a window.
let library = VulkanLibrary::new().unwrap(); let library = VulkanLibrary::new().expect("Vulkan is not installed???");
let required_extensions = vulkano_win::required_extensions(&library); let required_extensions = vulkano_win::required_extensions(&library);
// Now creating the instance. // Now creating the instance.
...@@ -284,50 +294,6 @@ fn main() { ...@@ -284,50 +294,6 @@ fn main() {
.unwrap() .unwrap()
}; };
const OBJ: &[u8] = include_bytes!("bunny.obj");
let buny = ObjData::load_buf_with_config(OBJ, LoadConfig::default()).unwrap();
let polys = &buny.objects[0].groups[0].polys;
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
// We now create a buffer that will store the shape of our triangle.
// We use #[repr(C)] here to force rustc to not do anything funky with our data, although for this
// particular example, it doesn't actually change the in-memory representation.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 3],
normal: [f32; 3],
}
impl_vertex!(Vertex, position, normal);
let vertices = polys
.iter()
.flat_map(|p| {
p.0.iter()
.map(|v| Vertex {
position: buny.position[v.0],
normal: v
.2
.and_then(|vt| Some(buny.normal[vt]))
.unwrap_or([0.0, 0.0, 0.0]),
})
.collect::<Vec<Vertex>>()
})
.collect::<Vec<Vertex>>();
let vertex_buffer = CpuAccessibleBuffer::from_iter(
&memory_allocator,
BufferUsage {
vertex_buffer: true,
..BufferUsage::empty()
},
false,
vertices,
)
.unwrap();
// The next step is to create the shaders. // The next step is to create the shaders.
// //
// The raw shader creation API provided by the vulkano library is unsafe for various // The raw shader creation API provided by the vulkano library is unsafe for various
...@@ -344,7 +310,7 @@ fn main() { ...@@ -344,7 +310,7 @@ fn main() {
// //
// A more detailed overview of what the `shader!` macro generates can be found in the // A more detailed overview of what the `shader!` macro generates can be found in the
// `vulkano-shaders` crate docs. You can view them at https://docs.rs/vulkano-shaders/ // `vulkano-shaders` crate docs. You can view them at https://docs.rs/vulkano-shaders/
mod vs { mod mesh_vs {
vulkano_shaders::shader! { vulkano_shaders::shader! {
ty: "vertex", ty: "vertex",
src: " src: "
...@@ -363,7 +329,7 @@ fn main() { ...@@ -363,7 +329,7 @@ fn main() {
void main() { void main() {
mat4 worldview = pc.view * pc.world; mat4 worldview = pc.view * pc.world;
v_normal = normalize(transpose(inverse(mat3(worldview))) * normal); v_normal = normal; //normalize(transpose(inverse(mat3(worldview))) * normal);
gl_Position = pc.proj * worldview * vec4(position*1000.0, 1.0); gl_Position = pc.proj * worldview * vec4(position*1000.0, 1.0);
} }
", ",
...@@ -375,19 +341,26 @@ fn main() { ...@@ -375,19 +341,26 @@ fn main() {
} }
} }
mod fs { mod mesh_fs {
vulkano_shaders::shader! { vulkano_shaders::shader! {
ty: "fragment", ty: "fragment",
path: "src/frag.glsl" path: "src/frag.glsl",
types_meta: {
use bytemuck::{Pod, Zeroable};
#[derive(Clone, Copy, Zeroable, Pod, Debug)]
},
} }
} }
let vs = vs::load(device.clone()).unwrap(); let mesh_vs = mesh_vs::load(device.clone()).unwrap();
let fs = fs::load(device.clone()).unwrap(); let mesh_fs = mesh_fs::load(device.clone()).unwrap();
/*let uniform_buffer = /*let uniform_buffer =
CpuBufferPool::<vs::ty::PushConstantData>::uniform_buffer(memory_allocator);*/ CpuBufferPool::<vs::ty::PushConstantData>::uniform_buffer(memory_allocator);*/
let memory_allocator = Arc::new(MemoryAllocator::new_default(device.clone()));
// At this point, OpenGL initialization would be finished. However in Vulkan it is not. OpenGL // At this point, OpenGL initialization would be finished. However in Vulkan it is not. OpenGL
// implicitly does a lot of computation whenever you draw. In Vulkan, you have to do all this // implicitly does a lot of computation whenever you draw. In Vulkan, you have to do all this
// manually. // manually.
...@@ -439,33 +412,6 @@ fn main() { ...@@ -439,33 +412,6 @@ fn main() {
) )
.unwrap(); .unwrap();
// Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
// program, but much more specific.
let pipeline = GraphicsPipeline::start()
// We have to indicate which subpass of which render pass this pipeline is going to be used
// in. The pipeline will only be usable from this particular subpass.
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
// We need to indicate the layout of the vertices.
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
// The content of the vertex buffer describes a list of triangles.
.input_assembly_state(InputAssemblyState::new())
// A Vulkan shader can in theory contain multiple entry points, so we have to specify
// which one.
.vertex_shader(vs.entry_point("main").unwrap(), ())
// Use a resizable viewport set to draw over the entire window
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
// See `vertex_shader`.
.fragment_shader(fs.entry_point("main").unwrap(), ())
.depth_stencil_state(DepthStencilState::simple_depth_test())
.rasterization_state(RasterizationState {
front_face: Fixed(Clockwise),
cull_mode: Fixed(CullMode::Back),
..RasterizationState::default()
})
// Now that our builder is filled, we call `build()` to obtain an actual pipeline.
.build(device.clone())
.unwrap();
// Dynamic viewports allow us to recreate just the viewport when the window is resized // Dynamic viewports allow us to recreate just the viewport when the window is resized
// Otherwise we would have to recreate the whole pipeline. // Otherwise we would have to recreate the whole pipeline.
let mut viewport = Viewport { let mut viewport = Viewport {
...@@ -479,8 +425,10 @@ fn main() { ...@@ -479,8 +425,10 @@ fn main() {
// //
// Since we need to draw to multiple images, we are going to create a different framebuffer for // Since we need to draw to multiple images, we are going to create a different framebuffer for
// each image. // each image.
let mut framebuffers = window_size_dependent_setup( let ([mut mesh_pipeline], mut framebuffers) = window_size_dependent_setup(
&memory_allocator, &memory_allocator,
&mesh_vs,
&mesh_fs,
&images, &images,
render_pass.clone(), render_pass.clone(),
&mut viewport, &mut viewport,
...@@ -524,9 +472,18 @@ fn main() { ...@@ -524,9 +472,18 @@ fn main() {
stream_handle.play_raw(source.convert_samples()).unwrap(); stream_handle.play_raw(source.convert_samples()).unwrap();
*/ */
let rotation_start = Instant::now(); let mut render_start = Instant::now();
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
//let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); let uniform_buffer = CpuBufferPool::<mesh_fs::ty::Data>::new(
memory_allocator.clone(),
BufferUsage {
uniform_buffer: true,
..BufferUsage::empty()
},
MemoryUsage::Upload,
);
// Create an egui GUI // Create an egui GUI
let mut gui = Gui::new_with_subpass( let mut gui = Gui::new_with_subpass(
...@@ -561,6 +518,19 @@ fn main() { ...@@ -561,6 +518,19 @@ fn main() {
d: false, d: false,
}; };
gstate.meshes.push(load_obj(
&memory_allocator,
&mut Cursor::new(PLATONIC_SOLIDS[0].1),
PLATONIC_SOLIDS[0].0.to_string(),
));
gstate
.lights
.push(Light::new([4., 6., 8.], [1., 1., 8.], 0.01));
gstate
.lights
.push(Light::new([-4., 6., -8.], [8., 4., 1.], 0.01));
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
if let Event::WindowEvent { event: we, .. } = &event { if let Event::WindowEvent { event: we, .. } = &event {
if !gui.update(we) { if !gui.update(we) {
...@@ -613,12 +583,23 @@ fn main() { ...@@ -613,12 +583,23 @@ fn main() {
.. ..
} => { } => {
if looking { if looking {
camforward.x -= Deg(delta.1 as f32) * gstate.cursor_sensitivity; camforward.x -= Deg(delta.1 as f32) * gstate.cursor_sensitivity * 0.3;
camforward.y += Deg(delta.0 as f32) * gstate.cursor_sensitivity; camforward.y += Deg(delta.0 as f32) * gstate.cursor_sensitivity * 0.3;
camforward.x = camforward.x + Deg(360f32) % Deg(360f32);
camforward.y = camforward.y + Deg(360f32) % Deg(360f32);
} }
//println!("AXISM {:?}", delta); //println!("AXISM {:?}", delta);
} }
Event::RedrawEventsCleared => { Event::RedrawEventsCleared => {
for i in 1..gstate.fps.len() {
gstate.fps[i - 1] = gstate.fps[i];
}
gstate.fps[gstate.fps.len() - 1] =
1.0 / (Instant::now() - render_start).as_secs_f64();
render_start = Instant::now();
// Do not draw frame when screen dimensions are zero. // Do not draw frame when screen dimensions are zero.
// On Windows, this can occur from minimizing the application. // On Windows, this can occur from minimizing the application.
let window = surface.object().unwrap().downcast_ref::<Window>().unwrap(); let window = surface.object().unwrap().downcast_ref::<Window>().unwrap();
...@@ -653,8 +634,10 @@ fn main() { ...@@ -653,8 +634,10 @@ fn main() {
swapchain = new_swapchain; swapchain = new_swapchain;
// Because framebuffers contains an Arc on the old swapchain, we need to // Because framebuffers contains an Arc on the old swapchain, we need to
// recreate framebuffers as well. // recreate framebuffers as well.
framebuffers = window_size_dependent_setup( ([mesh_pipeline], framebuffers) = window_size_dependent_setup(
&memory_allocator, &memory_allocator,
&mesh_vs,
&mesh_fs,
&new_images, &new_images,
render_pass.clone(), render_pass.clone(),
&mut viewport, &mut viewport,
...@@ -664,7 +647,7 @@ fn main() { ...@@ -664,7 +647,7 @@ fn main() {
//println!("{:?}", right); //println!("{:?}", right);
let uniform_data = { let mut push_constants = {
if looking { if looking {
if keys.w { if keys.w {
campos -= Matrix3::from_angle_y(camforward.y) campos -= Matrix3::from_angle_y(camforward.y)
...@@ -718,7 +701,7 @@ fn main() { ...@@ -718,7 +701,7 @@ fn main() {
* Matrix4::from_scale(scale); * Matrix4::from_scale(scale);
//*Matrix4::from_angle_z(Deg(180f32)); //*Matrix4::from_angle_z(Deg(180f32));
let pc = vs::ty::PushConstantData { let pc = mesh_vs::ty::PushConstantData {
world: Matrix4::identity().into(), world: Matrix4::identity().into(),
view: view.into(), view: view.into(),
proj: proj.into(), proj: proj.into(),
...@@ -735,13 +718,35 @@ fn main() { ...@@ -735,13 +718,35 @@ fn main() {
pc pc
}; };
//let layout = pipeline.layout().set_layouts().get(0).unwrap(); let uniform_buffer_subbuffer = {
/*let set = PersistentDescriptorSet::new( let mut pos = [[0f32; 4]; 32];
&memory_allocator, let mut col = [[0f32; 4]; 32];
for (i, light) in gstate.lights.iter().enumerate() {
pos[i][0] = light.pos.x;
pos[i][1] = light.pos.y;
pos[i][2] = light.pos.z;
col[i][0] = light.colour.x;
col[i][1] = light.colour.y;
col[i][2] = light.colour.z;
}
let uniform_data = mesh_fs::ty::Data {
pos,
col,
light_count: gstate.lights.len() as u32,
};
uniform_buffer.from_data(uniform_data).unwrap()
};
let layout = mesh_pipeline.layout().set_layouts().get(0).unwrap();
let set = PersistentDescriptorSet::new(
&descriptor_set_allocator,
layout.clone(), layout.clone(),
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)], [WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
) )
.unwrap();*/ .unwrap();
// Before we can draw on the output, we have to *acquire* an image from the swapchain. If // Before we can draw on the output, we have to *acquire* an image from the swapchain. If
// no image is available (which happens if you submit draw commands too quickly), then the // no image is available (which happens if you submit draw commands too quickly), then the
...@@ -816,19 +821,31 @@ fn main() { ...@@ -816,19 +821,31 @@ fn main() {
// The last two parameters contain the list of resources to pass to the shaders. // The last two parameters contain the list of resources to pass to the shaders.
// Since we used an `EmptyPipeline` object, the objects have to be `()`. // Since we used an `EmptyPipeline` object, the objects have to be `()`.
.set_viewport(0, [viewport.clone()]) .set_viewport(0, [viewport.clone()])
.bind_pipeline_graphics(pipeline.clone()) .bind_pipeline_graphics(mesh_pipeline.clone())
/*.bind_descriptor_sets( .bind_descriptor_sets(
PipelineBindPoint::Graphics, PipelineBindPoint::Graphics,
pipeline.layout().clone(), mesh_pipeline.layout().clone(),
0, 0,
set, set,
)*/ );
.bind_vertex_buffers(0, vertex_buffer.clone())
.push_constants(pipeline.layout().clone(), 0, uniform_data) for object in &gstate.meshes {
.draw(vertex_buffer.len() as u32, 1, 0, 0) push_constants.world =
.unwrap() (Matrix4::from_translation(object.pos - Point3::origin())
// We leave the render pass. Note that if we had multiple * Matrix4::from(object.rot)
// subpasses we could have called `next_subpass` to jump to the next subpass. * object.scale)
.into();
builder
.bind_vertex_buffers(0, object.vertices.clone())
.bind_index_buffer(object.indices.clone())
.push_constants(mesh_pipeline.layout().clone(), 0, push_constants)
.draw_indexed(object.indices.len() as u32, 1, 0, 0, 0)
.unwrap();
}
// We leave the render pass. Note that if we had multiple
// subpasses we could have called `next_subpass` to jump to the next subpass.
builder
.next_subpass(SubpassContents::SecondaryCommandBuffers) .next_subpass(SubpassContents::SecondaryCommandBuffers)
.unwrap() .unwrap()
.execute_commands(cb) .execute_commands(cb)
...@@ -879,10 +896,12 @@ fn main() { ...@@ -879,10 +896,12 @@ fn main() {
/// This method is called once during initialization, then again whenever the window is resized /// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup( fn window_size_dependent_setup(
allocator: &StandardMemoryAllocator, allocator: &StandardMemoryAllocator,
mesh_vs: &ShaderModule,
mesh_fs: &ShaderModule,
images: &[Arc<SwapchainImage>], images: &[Arc<SwapchainImage>],
render_pass: Arc<RenderPass>, render_pass: Arc<RenderPass>,
viewport: &mut Viewport, viewport: &mut Viewport,
) -> Vec<Arc<Framebuffer>> { ) -> ([Arc<GraphicsPipeline>; 1], Vec<Arc<Framebuffer>>) {
let dimensions = images[0].dimensions().width_height(); let dimensions = images[0].dimensions().width_height();
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
...@@ -891,7 +910,7 @@ fn window_size_dependent_setup( ...@@ -891,7 +910,7 @@ fn window_size_dependent_setup(
) )
.unwrap(); .unwrap();
images let framebuffers = images
.iter() .iter()
.map(|image| { .map(|image| {
let view = ImageView::new_default(image.clone()).unwrap(); let view = ImageView::new_default(image.clone()).unwrap();
...@@ -904,5 +923,39 @@ fn window_size_dependent_setup( ...@@ -904,5 +923,39 @@ fn window_size_dependent_setup(
) )
.unwrap() .unwrap()
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>();
// Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
// program, but much more specific.
let mesh_pipeline = GraphicsPipeline::start()
// We have to indicate which subpass of which render pass this pipeline is going to be used
// in. The pipeline will only be usable from this particular subpass.
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
// We need to indicate the layout of the vertices.
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
// The content of the vertex buffer describes a list of triangles.
.input_assembly_state(InputAssemblyState::new())
// A Vulkan shader can in theory contain multiple entry points, so we have to specify
// which one.
.vertex_shader(mesh_vs.entry_point("main").unwrap(), ())
.viewport_state(ViewportState::viewport_fixed_scissor_irrelevant([
Viewport {
origin: [0.0, 0.0],
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
depth_range: 0.0..1.0,
},
]))
// See `vertex_shader`.
.fragment_shader(mesh_fs.entry_point("main").unwrap(), ())
.depth_stencil_state(DepthStencilState::simple_depth_test())
.rasterization_state(RasterizationState {
front_face: Fixed(Clockwise),
cull_mode: Fixed(CullMode::Back),
..RasterizationState::default()
})
// Now that our builder is filled, we call `build()` to obtain an actual pipeline.
.build(allocator.device().clone())
.unwrap();
([mesh_pipeline], framebuffers)
} }
use std::{collections::HashMap, io::Read, sync::Arc};
use bytemuck::{Pod, Zeroable};
use cgmath::{Deg, Euler, Matrix3, Point3, SquareMatrix, Vector3};
use obj::{LoadConfig, ObjData};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
impl_vertex,
};
use crate::MemoryAllocator;
pub const PLATONIC_SOLIDS: [(&str, &[u8]); 1] = [("Buny", include_bytes!("bunny.obj"))];
// We now create a buffer that will store the shape of our triangle.
// We use #[repr(C)] here to force rustc to not do anything funky with our data, although for this
// particular example, it doesn't actually change the in-memory representation.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
pub struct Vertex {
position: [f32; 3],
normal: [f32; 3],
}
impl_vertex!(Vertex, position, normal);
#[derive(Debug)]
pub struct Mesh {
pub name: String,
pub vertices: Arc<CpuAccessibleBuffer<[Vertex]>>,
pub indices: Arc<CpuAccessibleBuffer<[u32]>>,
pub pos: Point3<f32>,
pub rot: Euler<Deg<f32>>,
pub scale: f32,
}
pub fn load_obj(memory_allocator: &MemoryAllocator, input: &mut dyn Read, name: String) -> Mesh {
let object = ObjData::load_buf_with_config(input, LoadConfig::default()).unwrap();
let mut vertices = vec![];
let mut indices = vec![];
let mut temp_hash_map = HashMap::<(u32, u32), u32>::new();
// We're gonna have to remap all the indices that OBJ uses. Annoying.
// Get each pair of vertex position to vertex normal and assign it a new index. This might duplicate
// vertices or normals but each *pair* needs a unique index
// Uses the hash map to check that we're not duplicating unnecessarily
for g in &object.objects[0].groups {
for p in &g.polys {
for v in &p.0 {
//println!("{:?}", v);
let mapping = ((v.0) as u32, (v.2.unwrap_or(0)) as u32);
if let Some(&exist) = &temp_hash_map.get(&mapping) {
//println!("{:?}", exist);
indices.push(exist);
} else {
vertices.push(Vertex {
position: object.position[mapping.0 as usize],
normal: object.normal[mapping.1 as usize],
});
temp_hash_map.insert(mapping, (vertices.len() - 1) as u32);
indices.push((vertices.len() - 1) as u32);
}
}
}
}
let vertex_buffer = CpuAccessibleBuffer::from_iter(
memory_allocator,
BufferUsage {
vertex_buffer: true,
..BufferUsage::empty()
},
false,
vertices,
)
.unwrap();
let index_buffer = CpuAccessibleBuffer::from_iter(
memory_allocator,
BufferUsage {
index_buffer: true,
..BufferUsage::empty()
},
false,
indices,
)
.unwrap();
Mesh {
vertices: vertex_buffer,
indices: index_buffer,
pos: Point3 {
x: 0.,
y: 0.,
z: 0.,
},
rot: Euler::new(Deg(0.), Deg(0.), Deg(0.)),
scale: 1.,
name,
}
}
#[derive(Debug)]
pub struct Light {
pub pos: Point3<f32>,
pub colour: Vector3<f32>,
}
impl Light {
pub fn new(pos: [f32; 3], colour: [f32; 3], intensity: f32) -> Light {
let c: Vector3<f32> = colour.into();
Light {
pos: pos.into(),
colour: c * intensity,
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment