various overhauls to data formats
This commit is contained in:
+14
-3
@@ -1,10 +1,21 @@
|
|||||||
#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.);
|
||||||
}
|
}
|
||||||
+47
-6
@@ -1,6 +1,11 @@
|
|||||||
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...
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
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));
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+158
-105
@@ -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::{
|
|||||||
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() {
|
|||||||
// 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() {
|
|||||||
.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() {
|
|||||||
//
|
//
|
||||||
// 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() {
|
|||||||
|
|
||||||
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() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
)
|
)
|
||||||
.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() {
|
|||||||
//
|
//
|
||||||
// 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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
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() {
|
|||||||
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() {
|
|||||||
|
|
||||||
//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() {
|
|||||||
* 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() {
|
|||||||
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() {
|
|||||||
// 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() {
|
|||||||
/// 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(
|
|||||||
)
|
)
|
||||||
.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(
|
|||||||
)
|
)
|
||||||
.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)
|
||||||
}
|
}
|
||||||
|
|||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user