This commit is contained in:
2021-08-15 22:34:29 +02:00
parent c619f945a3
commit 40aa7f635e
11 changed files with 273 additions and 56 deletions

View File

@@ -18,14 +18,15 @@ pub struct GameObject {
pub scale: Vector3<f32>,
pub children: Vec<GameObject>,
pub descriptor_sets: Vec<Arc<RendererDescriptorSets>>,
pub is_selected: bool
pub is_selected: bool,
pub pipeline_index: usize,
}
impl GameObject {
pub fn new(mesh: MeshHandle) -> GameObject {
GameObject { mesh_index: mesh.index, texture_index: mesh.diffuse_handle, normal_map_index: mesh.normal_handle.unwrap_or(0), position: Vector3::new(0.0, 0.0, 0.0),
rotation: Quaternion::new(1.0, 0.0, 0.0, 0.0), scale: Vector3::new(1.0, 1.0, 1.0), children: vec![],
descriptor_sets: vec![], is_selected: false }
descriptor_sets: vec![], is_selected: false, pipeline_index: mesh.pipeline_index }
}
pub fn _set_position(&mut self, x: f32, y: f32, z: f32) {

View File

@@ -6,6 +6,8 @@ use gltf::mesh::util::{ReadJoints, ReadNormals, ReadPositions, ReadTangents, Rea
use crate::vulkan::mesh::LoadError::{GltfError, MeshDataMissing, NoIndices};
use crate::vulkan::Vertex;
use super::TextVertex;
#[derive(Debug)]
pub enum LoadError {
GltfError(gltf::Error),
@@ -25,9 +27,15 @@ impl From<String> for LoadError {
}
}
#[derive(Debug)]
pub enum CPUVertex {
Vertex3D(Vertex),
VertexText(TextVertex)
}
#[derive(Debug)]
pub struct CPUMesh {
pub vertices: Vec<Vertex>,
pub vertices: Vec<CPUVertex>,
pub indices: Vec<u32>,
pub local_texture_index: Option<usize>,
pub local_normal_map_index: Option<usize>,
@@ -41,7 +49,7 @@ fn read_file(path: &str) -> Vec<u8> {
glb_bytes
}
pub fn load_mesh(mesh_path: &str, print_status: bool) -> Result<(Vec<CPUMesh>, Document), LoadError> {
pub fn load_mesh<V>(mesh_path: &str, print_status: bool) -> Result<(Vec<CPUMesh>, Document), LoadError> {
let mut start_time = None;
let mut total_vertices = 0;
let mut total_indices = 0;
@@ -80,7 +88,7 @@ pub fn load_mesh(mesh_path: &str, print_status: bool) -> Result<(Vec<CPUMesh>, D
reader.read_tangents(),
reader.read_joints(0),
reader.read_weights(0));
let vertices = vertices_result?;
let vertices = vertices_result?.iter().map(|v| CPUVertex::Vertex3D(v.clone())).collect();
let cpu_mesh = CPUMesh {
vertices,
indices: indices.into_u32().collect(),

View File

@@ -25,12 +25,14 @@ use winit::window::{Window, WindowBuilder};
use mesh::CPUMesh;
use pipelines::{Drawcall};
use pipelines::line_vs::ty::LinePushConstants;
use pipelines::DefaultShader;
use pipelines::{DefaultShader, TextShader};
use pipelines::vs;
use crate::config::RenderConfig;
use crate::vulkan::gameobject::{GameObject, GameObjectHandle};
use self::mesh::CPUVertex;
pub mod pipelines;
pub mod gameobject;
pub mod mesh;
@@ -39,7 +41,7 @@ mod renderpass;
mod framebuffers;
const VALIDATION_LAYERS: &[&str] = &[
"VK_LAYER_KHRONOS_validation"
"VK_LAYER_KHRONOS_validation",
];
#[derive(Default, Debug, Clone)]
@@ -59,6 +61,14 @@ pub struct LinePoint {
}
vulkano::impl_vertex!(LinePoint, position);
#[derive(Default, Debug, Clone)]
pub struct TextVertex {
pub position: [f32; 3],
pub uv: [f32; 2],
pub normal: [f32; 3],
}
vulkano::impl_vertex!(TextVertex, position, uv, normal);
pub trait Game {
/// Returns true if event should be ignored by the vulkan handler
fn on_window_event(self: &mut Self, event: &Event<()>);
@@ -66,8 +76,8 @@ pub trait Game {
fn update(self: &mut Self, renderer: &mut VulkanRenderer) -> vs::ty::ObjectUniformData;
}
pub struct Mesh {
pub vertex_buffer: Arc<CpuAccessibleBuffer<[Vertex]>>,
pub struct Mesh<V> {
pub vertex_buffer: Arc<CpuAccessibleBuffer<[V]>>,
pub index_buffer: Arc<CpuAccessibleBuffer<[u32]>>,
pub original_path: Option<String>,
}
@@ -77,7 +87,8 @@ pub struct MeshHandle {
pub index: usize,
pub diffuse_handle: TextureHandle,
pub normal_handle: Option<TextureHandle>,
pub original_path: Option<String>
pub original_path: Option<String>,
pub pipeline_index: usize
}
pub(crate) type TextureHandle = usize;
@@ -94,9 +105,9 @@ pub struct GameData {
pub dimensions: [u32; 2],
pub shutdown: bool,
pub game_objects: Vec<GameObject>,
pub meshes: Vec<Mesh>,
pub meshes: Vec<Mesh<Vertex>>,
pub meshes_text: Vec<Mesh<TextVertex>>,
pub textures: Vec<Texture>,
pub use_line_pipeline: bool,
}
pub(crate) type RendererDescriptorSets = dyn DescriptorSet + Send + Sync;
@@ -115,7 +126,6 @@ pub struct VulkanRenderer {
pub debug_callback: Option<DebugCallback>,
pub previous_frame_end: Option<Box<dyn GpuFuture>>,
pub uniform_buffers: Vec<Arc<CpuAccessibleBuffer<vs::ty::ObjectUniformData>>>,
pub line_vertex_buffer: Arc<CpuAccessibleBuffer<[LinePoint]>>,
pub render_config: RenderConfig
}
@@ -134,9 +144,9 @@ impl VulkanRenderer {
line_vertices,
dimensions: [0, 0],
meshes: vec![],
meshes_text: vec![],
game_objects: vec![],
textures: vec![],
use_line_pipeline: true,
};
// Create basic vulkan instance with layers and info
@@ -239,12 +249,11 @@ impl VulkanRenderer {
// Render pass
let render_pass = renderpass::create_render_pass(device.clone(), &render_config, swapchain.format());
let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), false, data.line_vertices.iter().cloned()).unwrap();
let render_pass_text = renderpass::create_render_pass(device.clone(), &render_config, swapchain.format());
let pipelines: Vec<Box<dyn Drawcall>> = vec![
Box::new(DefaultShader::new(device.clone(), render_pass.clone())),
// Box::new(LineShader::new(device.clone(), render_pass.clone(), line_vertex_buffer.clone())),
Box::new(TextShader::new(device.clone(), render_pass_text.clone())),
];
// Dynamic viewports allow us to recreate just the viewport when the window is resized
@@ -292,7 +301,6 @@ impl VulkanRenderer {
surface, swapchain, render_pass, queue,
recreate_swapchain: false, debug_callback, previous_frame_end,
render_config,
line_vertex_buffer,
}, events_loop)
}
@@ -307,8 +315,10 @@ impl VulkanRenderer {
}
// Draw meshes etc.
let mut index = 0;
for pipeline in &self.pipelines {
pipeline.draw(&mut builder, fb_index, &self.game_data, &self.dynamic_state);
pipeline.draw(&mut builder, fb_index, self.game_data.game_objects.iter().filter(|go| go.pipeline_index == index).collect(), &self.game_data, &self.dynamic_state);
index += 1;
}
// General cleanup
@@ -343,7 +353,7 @@ impl VulkanRenderer {
self.pipelines = vec![
Box::new(DefaultShader::new(self.device.clone(), self.render_pass.clone())),
// Box::new(LineShader::new(self.device.clone(), self.render_pass.clone(), self.line_vertex_buffer.clone())),
Box::new(TextShader::new(self.device.clone(), self.render_pass.clone())),
];
self.swapchain = new_swapchain;
@@ -420,11 +430,28 @@ impl VulkanRenderer {
// collision_mesh.push_face((mesh.indices[i] as usize, mesh.indices[i + 1] as usize, mesh.indices[i + 2] as usize));
// }
let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::vertex_buffer(), false, mesh.vertices.into_iter()).unwrap();
let index_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::index_buffer(), false, mesh.indices.into_iter()).unwrap();
let index_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::index_buffer(), false, mesh.indices.into_iter()).unwrap();
self.game_data.meshes.push(Mesh { vertex_buffer, index_buffer, original_path });
self.game_data.meshes.len() - 1
match mesh.vertices.get(0).unwrap() {
CPUVertex::Vertex3D(_) => {
let verts: Vec<Vertex> = mesh.vertices.into_iter().filter_map(|v| match v {
CPUVertex::Vertex3D(vert) => Some(vert),
CPUVertex::VertexText(_) => None
}).collect();
let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::vertex_buffer(), false, verts.into_iter()).unwrap();
self.game_data.meshes.push(Mesh { vertex_buffer, index_buffer, original_path });
self.game_data.meshes.len() - 1
},
CPUVertex::VertexText(_) => {
let verts: Vec<TextVertex> = mesh.vertices.into_iter().filter_map(|v| match v {
CPUVertex::Vertex3D(_) => None,
CPUVertex::VertexText(vert) => Some(vert)
}).collect();
let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::vertex_buffer(), false, verts.into_iter()).unwrap();
self.game_data.meshes_text.push(Mesh { vertex_buffer, index_buffer, original_path });
self.game_data.meshes_text.len() - 1
},
}
}
pub fn upload_texture(self: &mut Self, bytes: &[u8], width: u32, height: u32, format: Format, device: Arc<Device>) {
@@ -438,7 +465,7 @@ impl VulkanRenderer {
};
let layout = ImageLayout::ShaderReadOnlyOptimal;
let mip_maps = if format == Format::R8Srgb { MipmapsCount::One } else { MipmapsCount::Log2 };
let mip_maps = if format == Format::R8Uint { MipmapsCount::One } else { MipmapsCount::Log2 };
let (image_view, initializer) = ImmutableImage::uninitialized(
device.clone(),
@@ -518,8 +545,8 @@ impl VulkanRenderer {
self.game_data.textures.push(Texture { image: image_view, sampler });
}
pub fn add_game_object(self: &mut Self, mut game_object: GameObject, pipeline_index: usize) -> GameObjectHandle {
self.pipelines[pipeline_index].create_descriptor_set(&mut game_object, self);
pub fn add_game_object(self: &mut Self, mut game_object: GameObject) -> GameObjectHandle {
self.pipelines[game_object.pipeline_index].create_descriptor_set(&mut game_object, self);
self.game_data.game_objects.push(game_object);
GameObjectHandle {

View File

@@ -1,6 +1,6 @@
use std::{convert::TryInto, io::{self, ErrorKind, Read, Write}, path::PathBuf, sync::Arc};
use vulkano::{command_buffer::AutoCommandBufferBuilder, descriptor::{descriptor::ShaderStages, descriptor_set::PersistentDescriptorSet}, pipeline::shader::ShaderModule};
use vulkano::{command_buffer::AutoCommandBufferBuilder, descriptor::{descriptor::ShaderStages, descriptor_set::PersistentDescriptorSet}, pipeline::shader::{ShaderModule}};
use vulkano::command_buffer::DynamicState;
use vulkano::device::Device;
use vulkano::framebuffer::RenderPassAbstract;
@@ -9,7 +9,7 @@ use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::GraphicsPipelineAbstract;
use vulkano::pipeline::shader::GraphicsShaderType;
use crate::GameObject;
use crate::{GameObject, vulkan::TextVertex};
use crate::vulkan::{LinePoint, Vertex};
use crate::vulkan::GameData;
use crate::VulkanRenderer;
@@ -18,7 +18,7 @@ type RP = Arc<dyn RenderPassAbstract + Send + Sync>;
type GP = Arc<dyn GraphicsPipelineAbstract + Send + Sync>;
pub trait Drawcall {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_data: &GameData, dynamic_state: &DynamicState);
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData, dynamic_state: &DynamicState);
fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer);
fn recreate_pipeline(self: &mut Self, device: Arc<Device>, render_pass: RP);
fn get_pipeline(self: &Self) -> &GP;
@@ -136,12 +136,14 @@ impl DefaultShader {
}
impl Drawcall for DefaultShader {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_data: &GameData, dynamic_state: &DynamicState) {
for i in 0..game_data.game_objects.len() {
let game_object = &game_data.game_objects[i];
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData, dynamic_state: &DynamicState) {
for i in 0..game_objects.len() {
let game_object = &game_objects[i];
let mesh = &game_data.meshes[game_object.mesh_index];
let push_constants = game_object.get_push_constants();
println!("default: {:?}", game_object.mesh_index);
builder.draw_indexed(
self.pipeline.clone(),
dynamic_state,
@@ -230,7 +232,7 @@ impl LineShader {
}
impl Drawcall for LineShader {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, _fb_index: usize, game_data: &GameData, dynamic_state: &DynamicState) {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, _fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData, dynamic_state: &DynamicState) {
builder.draw(self.pipeline.clone(),
&dynamic_state,
vec![self.vertex_buffer.clone()],
@@ -246,6 +248,124 @@ impl Drawcall for LineShader {
self.pipeline = Self::create_pipeline(device, render_pass);
}
fn get_pipeline(self: &Self) -> &GP {
&self.pipeline
}
}
pub mod vs_text {
vulkano_shaders::shader!{
ty: "vertex",
path: "shaders/text.vert"
}
}
pub mod fs_text {
vulkano_shaders::shader!{
ty: "fragment",
path: "shaders/text.frag"
}
}
pub struct TextShader {
pipeline: GP,
}
impl TextShader {
pub fn new(device: Arc<Device>, render_pass: RP) -> Self {
TextShader {
pipeline: Self::create_pipeline(device, render_pass)
}
}
fn create_pipeline(device: Arc<Device>, render_pass: RP) -> GP {
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
#[cfg(debug_assertions)]
{
println!("Compiling shaders...");
compile_shaders().unwrap();
}
unsafe {
static ENTRY_NAME: [u8; 5usize] = [109u8, 97u8, 105u8, 110u8, 0];
let entry_name_c = std::ffi::CStr::from_ptr(ENTRY_NAME.as_ptr() as *const _);
let fs_module = shader_module_from_file(device.clone(), "shaders/text.frag.spv");
let fs_layout = fs::Layout(ShaderStages {
fragment: true,
..ShaderStages::none()
});
let fs_entry = fs_module.graphics_entry_point(entry_name_c, fs_text::MainInput, fs_text::MainOutput, fs_layout, GraphicsShaderType::Fragment);
let vs_module = shader_module_from_file(device.clone(), "shaders/text.vert.spv");
let vs_layout = vs::Layout(ShaderStages {
vertex: true,
..ShaderStages::none()
});
let vs_entry = vs_module.graphics_entry_point(entry_name_c, vs_text::MainInput, vs_text::MainOutput, vs_layout, GraphicsShaderType::Vertex);
let gp = Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<TextVertex>()
.vertex_shader(vs_entry, ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fs_entry, ())
.blend_alpha_blending()
.cull_mode_back()
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
println!("layout: {:?}", vulkano::descriptor::PipelineLayoutAbstract::descriptor_set_layout(&gp, 0).unwrap().descriptors_count());
gp
}
}
}
impl Drawcall for TextShader {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData, dynamic_state: &DynamicState) {
for i in 0..game_objects.len() {
let game_object = &game_objects[i];
let mesh = &game_data.meshes[game_object.mesh_index];
let push_constants = game_object.get_push_constants();
println!("text: {:?}", game_object.mesh_index);
builder.draw_indexed(
self.pipeline.clone(),
dynamic_state,
vec![mesh.vertex_buffer.clone()],
mesh.index_buffer.clone(),
game_object.descriptor_sets[fb_index].clone(),
push_constants).unwrap();
}
}
fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer) {
let descriptor_set_layout = self.get_pipeline().descriptor_set_layout(0).unwrap().clone();
game_object.descriptor_sets = renderer.uniform_buffers.iter().map(|uniform_buffer| {
let descriptor_set: Arc<(dyn vulkano::descriptor::DescriptorSet + std::marker::Send + std::marker::Sync + 'static)>;
let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone());
let diffuse = &renderer.game_data.textures[game_object.texture_index];
descriptor_set = Arc::new(builder
.add_buffer(uniform_buffer.clone()).unwrap()
.add_sampled_image(diffuse.image.clone(), diffuse.sampler.clone()).unwrap()
.add_sampled_image(diffuse.image.clone(), diffuse.sampler.clone()).unwrap()
.build().unwrap());
descriptor_set
}).collect();
}
fn recreate_pipeline(self: &mut Self, device: Arc<Device>, render_pass: RP) {
self.pipeline = Self::create_pipeline(device, render_pass);
}
fn get_pipeline(self: &Self) -> &GP {
&self.pipeline
}