textures!!!

This commit is contained in:
2019-08-02 23:50:37 +02:00
parent c582af5138
commit 4f261fa708
5 changed files with 108 additions and 27 deletions

View File

@@ -1,9 +1,11 @@
#version 450
layout(location = 0) in vec3 pos;
layout(location = 0) in vec2 tex_coords;
layout(location = 0) out vec4 f_color;
layout(set = 0, binding = 0) uniform sampler2D tex;
void main() {
f_color = vec4(.3, (pos.y + 5.) / 10., .8, 1.0);
f_color = texture(tex, tex_coords);
}

View File

@@ -2,8 +2,9 @@
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 uv;
layout(location = 0) out vec3 pos;
layout(location = 0) out vec2 tex_coords;
layout(push_constant) uniform PushConstants {
float time;
@@ -14,5 +15,5 @@ layout(push_constant) uniform PushConstants {
void main() {
gl_Position = push.projection * push.view * push.model * vec4(position, 1.0);
pos = gl_Position.xyz;
tex_coords = uv;
}

View File

@@ -16,7 +16,7 @@ struct TestGame {
input: InputState,
cam_position: Vector3<f32>,
cam_rotation: Quaternion<f32>,
cube_mesh: Option<MeshHandle>,
test_meshes: Vec<(MeshHandle, usize)>,
cubes: Vec<GameObjectHandle>,
log_config: LogConfig,
}
@@ -29,8 +29,16 @@ impl Game for TestGame {
impl TestGame {
fn game_start(self: &mut Self, renderer: &mut VulkanRenderer) {
self.cube_mesh = Some(renderer.upload_mesh(mesh::load_mesh("models/box.gltf", self.log_config.mesh_load_info).unwrap().into_iter().nth(0).unwrap()));
println!("Game started.");
let (meshes, textures) = mesh::load_mesh("models/iski51.gltf", self.log_config.mesh_load_info).unwrap();
self.test_meshes = meshes.into_iter().map(|m| {
let id = match m.texture_index {
Some(tex_id) => tex_id + 1,
None => 0,
};
(renderer.upload_mesh(m), id)
}).collect();
textures.iter().for_each(|tex| renderer.upload_texture(tex));
println!("Game loaded!");
}
fn update(self: &mut Self, renderer: &mut VulkanRenderer) {
@@ -55,7 +63,7 @@ impl TestGame {
if self.input.button_just_pressed("test") {
println!("test");
self.cubes.push(renderer.add_game_object(GameObject::new(self.cube_mesh.unwrap())));
self.cubes = self.test_meshes.iter().map(|(mesh, tex_id)| renderer.add_game_object(GameObject::new(*mesh, *tex_id, renderer))).collect();
}
self.cam_rotation = self.cam_rotation * Quaternion::from_angle_z(Deg(self.input.get_axis("look_horizontal") * 0.05));
@@ -93,7 +101,7 @@ fn main() {
input: InputState::new("config/input.toml", log_config),
cam_rotation: Quaternion::one(),
cam_position: Vector3::new(0.0, 0.0, -10.0),
cube_mesh: None,
test_meshes: vec![],
cubes: vec![],
log_config
};

View File

@@ -3,11 +3,13 @@ use crate::vulkan::Vertex;
use std::time::SystemTime;
pub struct CPUMesh {
pub(crate) vertices: Vec<Vertex>,
pub(crate) indices: Vec<u32>,
pub vertices: Vec<Vertex>,
pub indices: Vec<u32>,
pub texture_index: Option<usize>,
pub name: Option<String>,
}
pub fn load_mesh(mesh_path: &str, print_status: bool) -> Result<Vec<CPUMesh>, gltf::Error> {
pub fn load_mesh(mesh_path: &str, print_status: bool) -> Result<(Vec<CPUMesh>, Vec<gltf::image::Data>), gltf::Error> {
let mut start_time = None;
let mut total_vertices = 0;
let mut total_indices = 0;
@@ -16,14 +18,15 @@ pub fn load_mesh(mesh_path: &str, print_status: bool) -> Result<Vec<CPUMesh>, gl
start_time = Some(SystemTime::now());
println!("Loading mesh file {}", mesh_path);
}
let (document, buffers, _textures) = gltf::import(mesh_path)?;
let (document, buffers, textures) = gltf::import(mesh_path)?;
let mut meshes = vec![];
if print_status { println!("Mesh file loaded after {} seconds, processing...", start_time.unwrap().elapsed().unwrap().as_secs()); }
for mesh in document.meshes() {
for primitive in mesh.primitives() {
let texture_index = primitive.material().pbr_metallic_roughness().base_color_texture().map(|tex_info| tex_info.texture().index());
let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
match (reader.read_indices(), reader.read_positions(), reader.read_tex_coords(0), reader.read_normals()) {
(Some(indices), Some(positions), Some(tex_coords), Some(normals)) => {
@@ -32,7 +35,12 @@ pub fn load_mesh(mesh_path: &str, print_status: bool) -> Result<Vec<CPUMesh>, gl
uv: t,
normal: n
}).collect();
let cpu_mesh = CPUMesh { vertices, indices: indices.into_u32().collect() };
let cpu_mesh = CPUMesh {
vertices,
indices: indices.into_u32().collect(),
texture_index,
name: mesh.name().map(|n| n.to_owned()),
};
if print_status {
let vert_count = cpu_mesh.vertices.len();
let index_count = cpu_mesh.indices.len();
@@ -60,5 +68,5 @@ pub fn load_mesh(mesh_path: &str, print_status: bool) -> Result<Vec<CPUMesh>, gl
println!("Finished loading file, total vertices: {}, total indices: {}", total_vertices, total_indices);
}
Ok(meshes)
Ok((meshes, textures))
}

View File

@@ -2,7 +2,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
use vulkano::device::{Device, DeviceExtensions, Queue};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
use vulkano::image::{SwapchainImage, AttachmentImage, ImageUsage};
use vulkano::image::{SwapchainImage, AttachmentImage, ImageUsage, ImmutableImage, Dimensions};
use vulkano::instance::{Instance, PhysicalDevice, ApplicationInfo, Version, InstanceExtensions};
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract};
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule};
@@ -14,6 +14,9 @@ use vulkano::sync;
use vulkano::format::{Format, ClearValue};
use vulkano::instance::debug::{DebugCallback, MessageTypes};
use vulkano::memory::pool::{PotentialDedicatedAllocation, StdMemoryPoolAlloc};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor::DescriptorSet;
use vulkano::sampler::{Sampler, Filter, MipmapMode, SamplerAddressMode};
use vulkano_win::VkSurfaceBuild;
@@ -28,14 +31,15 @@ use cgmath::{Matrix4, SquareMatrix};
use shade_runner;
use shade_runner::{CompiledShaders, Entry};
use shaderc;
use vs::ty::PushConstants;
use line_vs::ty::LinePushConstants;
use crate::mesh::CPUMesh;
use crate::mesh::{CPUMesh};
use crate::vulkan::RenderLoopResult::Quit;
use image::{ImageFormat, ConvertBuffer, ImageBuffer, Rgb, Rgba};
const VALIDATION_LAYERS: &[&str] = &[
"VK_LAYER_LUNARG_standard_validation"
];
@@ -66,6 +70,8 @@ pub struct Mesh {
pub struct GameObject {
pub mesh_index: usize,
pub texture_index: usize,
pub descriptor_set: Arc<DescriptorSet + Send + Sync>,
pub model_matrix: Matrix4<f32>,
}
@@ -82,12 +88,15 @@ pub struct GameData {
pub shutdown: bool,
pub game_objects: Vec<GameObject>,
pub meshes: Vec<Mesh>,
pub textures: Vec<Arc<ImmutableImage<Format>>>,
}
pub struct VulkanRenderer {
pub game_data: GameData,
pub device: Arc<Device>,
pub framebuffers: Vec<Arc<FramebufferAbstract + Send + Sync>>,
pub sampler: Arc<Sampler>,
pub default_descriptor_set: Arc<DescriptorSet + Send + Sync>,
pub dynamic_state: DynamicState,
pub pipeline: Arc<GraphicsPipelineAbstract + Send + Sync>,
pub line_pipeline: Arc<GraphicsPipelineAbstract + Send + Sync>,
@@ -130,6 +139,7 @@ impl VulkanRenderer {
dimensions: [0, 0],
meshes: vec![],
game_objects: vec![],
textures: vec![],
};
if enable_validation_layers {
@@ -268,11 +278,36 @@ impl VulkanRenderer {
}
).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<GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<Vertex>(device.clone(), render_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false).unwrap();
let line_pipeline: Arc<GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<LinePoint>(device.clone(), render_pass.clone(), "shaders/line.vert", "shaders/line.frag", true).unwrap();
let (default_tex, default_tex_future) = {
let image = image::load_from_memory_with_format(include_bytes!("../models/Eye.png"),
ImageFormat::PNG).unwrap().to_rgba();
let image_data = image.into_raw().clone();
ImmutableImage::from_iter(
image_data.iter().cloned(),
Dimensions::Dim2d { width: 4096, height: 4096 },
Format::R8G8B8A8Unorm,
queue.clone(),
).unwrap()
};
let default_descriptor_set = Arc::new(PersistentDescriptorSet::start(pipeline.clone(), 0)
.add_sampled_image(default_tex.clone(), sampler.clone()).unwrap()
.build().unwrap()
);
data.textures.push(default_tex);
// Dynamic viewports allow us to recreate just the viewport when the window is resized
// Otherwise we would have to recreate the whole pipeline.
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None };
@@ -289,7 +324,9 @@ impl VulkanRenderer {
// that, we store the submission of the previous frame here.
let previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
VulkanRenderer { game_data: data, device, framebuffers, dynamic_state, pipeline, line_pipeline,
VulkanRenderer { game_data: data, device, framebuffers, sampler,
default_descriptor_set: default_descriptor_set,
dynamic_state, pipeline, line_pipeline,
surface, swapchain, render_pass, queue, line_vertex_buffer, events_loop,
recreate_swapchain: false, debug_callback, previous_frame_end }
}
@@ -362,10 +399,12 @@ impl VulkanRenderer {
let game_object = &self.game_data.game_objects[i];
let mesh = &self.game_data.meshes[game_object.mesh_index];
self.game_data.push_constants.model = game_object.model_matrix.into();
cbb = cbb.draw_indexed(self.pipeline.clone(), &self.dynamic_state,
cbb = cbb.draw_indexed(self.pipeline.clone(),
&self.dynamic_state,
vec![mesh.vertex_buffer.clone()],
mesh.index_buffer.clone(),
(), self.game_data.push_constants.clone()).unwrap();
game_object.descriptor_set.clone(),
self.game_data.push_constants.clone()).unwrap();
}
cbb = cbb.draw(self.line_pipeline.clone(), &self.dynamic_state, vec![self.line_vertex_buffer.clone()], (), self.game_data.line_push_constants.clone()).unwrap()
@@ -423,6 +462,22 @@ impl VulkanRenderer {
self.game_data.meshes.len() - 1
}
pub fn upload_texture(self: &mut Self, texture_data: &gltf::image::Data) {
let buffer: ImageBuffer<Rgb<u8>, Vec<u8>> = image::ImageBuffer::from_raw(texture_data.width, texture_data.height, texture_data.pixels.clone()).unwrap();
let new_buffer: ImageBuffer<Rgba<u8>, Vec<u8>> = buffer.convert();
let (image_view, future) = ImmutableImage::from_iter(
new_buffer.iter().cloned(),
Dimensions::Dim2d { width: texture_data.width, height: texture_data.height },
Format::R8G8B8A8Unorm,
self.queue.clone(),
).unwrap();
future.flush().unwrap();
self.game_data.textures.push(image_view);
}
pub fn add_game_object(self: &mut Self, game_object: GameObject) -> usize {
self.game_data.game_objects.push(game_object);
self.game_data.game_objects.len() - 1
@@ -523,9 +578,10 @@ fn create_pipeline<V: vulkano::pipeline::vertex::Vertex>(device: Arc<Device>, re
.vertex_shader(vertex_shader_entry.clone(), ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.cull_mode_back()
.fragment_shader(fragment_shader_entry.clone(), ())
.depth_stencil_simple_depth()
.blend_alpha_blending()
.cull_mode_back()
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
@@ -538,8 +594,14 @@ fn create_pipeline<V: vulkano::pipeline::vertex::Vertex>(device: Arc<Device>, re
}
impl GameObject {
pub fn new(mesh: MeshHandle) -> GameObject {
GameObject { mesh_index: mesh, model_matrix: Matrix4::identity() }
pub fn new(mesh: MeshHandle, texture_index: usize, renderer: &VulkanRenderer) -> GameObject {
println!("Texid: {}", texture_index);
let descriptor_set = Arc::new(PersistentDescriptorSet::start(renderer.pipeline.clone(), 0)
.add_sampled_image(renderer.game_data.textures[texture_index].clone(), renderer.sampler.clone()).unwrap()
.build().unwrap()
);
GameObject { mesh_index: mesh, texture_index, descriptor_set, model_matrix: Matrix4::identity() }
}
}