engine: textures

ecs
q3k 2020-05-09 00:40:43 +02:00
parent cb1e800279
commit 1636b9efcc
11 changed files with 170 additions and 46 deletions

1
assets/BUILD Normal file
View File

@ -0,0 +1 @@
exports_files(["test-128px.png"])

BIN
assets/test-128px.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -38,6 +38,7 @@ rust_binary(
data = [ data = [
"//engine/shaders:forward_vert", "//engine/shaders:forward_vert",
"//engine/shaders:forward_frag", "//engine/shaders:forward_frag",
"//assets:test-128px.png",
], ],
) )

View File

@ -2,9 +2,14 @@
#version 450 #version 450
#extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_separate_shader_objects : enable
layout(binding = 0) uniform sampler2D texSampler;
layout(location = 0) in vec3 fragColor; layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
void main() { void main() {
outColor = vec4(fragColor, 1.0); //outColor = vec4(fragColor, 1.0);
outColor = texture(texSampler, fragTexCoord);
} }

View File

@ -8,8 +8,10 @@ layout(push_constant) uniform UniformBufferObject {
layout(location = 0) in vec3 pos; layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 color; layout(location = 1) in vec3 color;
layout(location = 2) in mat4 model; layout(location = 2) in mat4 model;
layout(location = 6) in vec2 tex;
layout(location = 0) out vec3 fragColor; layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord;
out gl_PerVertex { out gl_PerVertex {
vec4 gl_Position; vec4 gl_Position;
@ -19,6 +21,8 @@ void main() {
gl_Position = ubo.view * model * vec4(pos, 1.0); gl_Position = ubo.view * model * vec4(pos, 1.0);
fragColor = color; fragColor = color;
fragTexCoord = tex;
// Vulkanize // Vulkanize
gl_Position.y = -gl_Position.y; gl_Position.y = -gl_Position.y;
} }

View File

@ -17,33 +17,55 @@ fn main() {
let mesh_cube = { let mesh_cube = {
let vertices = Arc::new(vec![ let vertices = Arc::new(vec![
data::Vertex::new([-0.5, -0.5, -0.5], [1.0, 0.0, 0.0]), data::Vertex::new([-0.5, -0.5, 0.5], [1.0, 1.0, 1.0], [1.0, 0.0]),
data::Vertex::new([0.5, -0.5, -0.5], [0.0, 1.0, 0.0]), data::Vertex::new([0.5, -0.5, 0.5], [1.0, 1.0, 0.0], [0.0, 0.0]),
data::Vertex::new([0.5, 0.5, -0.5], [0.0, 0.0, 1.0]), data::Vertex::new([0.5, 0.5, 0.5], [0.0, 1.0, 1.0], [0.0, 1.0]),
data::Vertex::new([-0.5, 0.5, -0.5], [1.0, 1.0, 1.0]), data::Vertex::new([-0.5, 0.5, 0.5], [1.0, 0.0, 1.0], [1.0, 1.0]),
data::Vertex::new([-0.5, -0.5, 0.5], [1.0, 1.0, 1.0]),
data::Vertex::new([0.5, -0.5, 0.5], [1.0, 1.0, 0.0]), data::Vertex::new([0.5, -0.5, -0.5], [1.0, 1.0, 1.0], [0.0, 1.0]),
data::Vertex::new([0.5, 0.5, 0.5], [0.0, 1.0, 1.0]), data::Vertex::new([0.5, 0.5, -0.5], [1.0, 1.0, 0.0], [1.0, 1.0]),
data::Vertex::new([-0.5, 0.5, 0.5], [1.0, 0.0, 1.0]), data::Vertex::new([0.5, 0.5, 0.5], [0.0, 1.0, 1.0], [1.0, 0.0]),
data::Vertex::new([0.5, -0.5, 0.5], [1.0, 0.0, 1.0], [0.0, 0.0]),
data::Vertex::new([-0.5, -0.5, -0.5], [1.0, 1.0, 1.0], [1.0, 1.0]),
data::Vertex::new([-0.5, 0.5, -0.5], [1.0, 1.0, 0.0], [0.0, 1.0]),
data::Vertex::new([-0.5, 0.5, 0.5], [0.0, 1.0, 1.0], [0.0, 0.0]),
data::Vertex::new([-0.5, -0.5, 0.5], [1.0, 0.0, 1.0], [1.0, 0.0]),
data::Vertex::new([-0.5, -0.5, -0.5], [1.0, 1.0, 1.0], [0.0, 1.0]),
data::Vertex::new([0.5, -0.5, -0.5], [1.0, 1.0, 0.0], [1.0, 1.0]),
data::Vertex::new([0.5, -0.5, 0.5], [0.0, 1.0, 1.0], [1.0, 0.0]),
data::Vertex::new([-0.5, -0.5, 0.5], [1.0, 0.0, 1.0], [0.0, 0.0]),
data::Vertex::new([-0.5, 0.5, -0.5], [1.0, 1.0, 1.0], [1.0, 1.0]),
data::Vertex::new([0.5, 0.5, -0.5], [1.0, 1.0, 0.0], [0.0, 1.0]),
data::Vertex::new([0.5, 0.5, 0.5], [0.0, 1.0, 1.0], [0.0, 0.0]),
data::Vertex::new([-0.5, 0.5, 0.5], [1.0, 0.0, 1.0], [1.0, 0.0]),
data::Vertex::new([-0.5, -0.5, -0.5], [1.0, 1.0, 1.0], [0.0, 0.0]),
data::Vertex::new([0.5, -0.5, -0.5], [1.0, 1.0, 0.0], [1.0, 0.0]),
data::Vertex::new([0.5, 0.5, -0.5], [0.0, 1.0, 1.0], [1.0, 1.0]),
data::Vertex::new([-0.5, 0.5, -0.5], [1.0, 0.0, 1.0], [0.0, 1.0]),
]); ]);
let indices = Arc::new(vec![ let indices = Arc::new(vec![
// bottom 0, 1, 2, 2, 3, 0,
2, 1, 0, 0, 3, 2,
// top 4, 5, 6, 6, 7, 4,
4, 5, 6, 6, 7, 4, 8, 10, 9, 10, 8, 11,
12, 13, 14, 14, 15, 12,
16, 18, 17, 18, 16, 19,
20, 22, 21, 22, 20, 23,
// left
4, 7, 0, 0, 7, 3,
// right
5, 1, 6, 6, 1, 2,
// front
7, 6, 3, 3, 6, 2,
// back
5, 4, 1, 1, 4, 0,
]); ]);
Arc::new(render::renderable::Mesh::new(vertices, indices)) Arc::new(render::renderable::Mesh::new(vertices, indices))
}; };
let path = &crate::util::file::resource_path(String::from("assets/test-128px.png"));
let image = Arc::new(image::open(path).unwrap());
let texture_cube = Arc::new(render::renderable::Texture::new(image));
let mut renderer = render::Renderer::initialize(); let mut renderer = render::Renderer::initialize();
let mut cubes: Vec<Arc<Object>> = Vec::new(); let mut cubes: Vec<Arc<Object>> = Vec::new();
@ -53,7 +75,8 @@ fn main() {
let transform = cgm::Matrix4::from_translation(cgm::Vector3::new((x as f32)*4.0, (y as f32)*4.0, (z as f32)*4.0)); let transform = cgm::Matrix4::from_translation(cgm::Vector3::new((x as f32)*4.0, (y as f32)*4.0, (z as f32)*4.0));
let cube = render::renderable::Object { let cube = render::renderable::Object {
mesh: mesh_cube.clone(), mesh: mesh_cube.clone(),
transform transform,
texture: texture_cube.clone(),
}; };
cubes.push(Arc::new(cube)); cubes.push(Arc::new(cube));
} }

View File

@ -4,21 +4,64 @@ use std::sync::Mutex;
use std::time; use std::time;
use cgmath as cgm; use cgmath as cgm;
use image;
use image::GenericImageView;
use vulkano::device as vd; use vulkano::device as vd;
use vulkano::buffer as vb; use vulkano::buffer as vb;
use vulkano::sync::GpuFuture; use vulkano::sync::GpuFuture;
use vulkano::format as vf;
use vulkano::image as vm;
use crate::render::vulkan::data; use crate::render::vulkan::data;
pub trait Renderable { pub trait Renderable {
fn render_data(&self) -> Option<(Arc<Mesh>, cgm::Matrix4<f32>)> { fn render_data(&self) -> Option<(Arc<Mesh>, Arc<Texture>, cgm::Matrix4<f32>)> {
None None
} }
} }
struct VulkanData { pub struct Texture {
vbuffer: Arc<vb::ImmutableBuffer<[data::Vertex]>>, image: Arc<image::DynamicImage>,
ibuffer: Arc<vb::ImmutableBuffer<[u16]>>,
// vulkan cache
vulkan: Mutex<Option<Arc<vm::ImmutableImage<vf::Format>>>>,
}
impl Texture {
pub fn new(
image: Arc<image::DynamicImage>,
) -> Self {
Self {
image,
vulkan: Mutex::new(None),
}
}
pub fn vulkan_texture(
&self,
graphics_queue: Arc<vd::Queue>,
) -> Arc<vm::ImmutableImage<vf::Format>> {
let mut cache = self.vulkan.lock().unwrap();
match &mut *cache {
Some(data) => data.clone(),
None => {
let width = self.image.width();
let height = self.image.height();
let image_rgba = self.image.to_rgba();
let (image_view, future) = vm::ImmutableImage::from_iter(
image_rgba.into_raw().iter().cloned(),
vm::Dimensions::Dim2d{ width, height },
vf::Format::R8G8B8A8Unorm,
graphics_queue.clone(),
).unwrap();
future.flush().unwrap();
*cache = Some(image_view.clone());
image_view
},
}
}
} }
pub struct Mesh { pub struct Mesh {
@ -27,7 +70,12 @@ pub struct Mesh {
id: u64, id: u64,
// vulkan buffers cache // vulkan buffers cache
vulkan: Mutex<Option<VulkanData>>, vulkan: Mutex<Option<MeshVulkanData>>,
}
struct MeshVulkanData {
vbuffer: Arc<vb::ImmutableBuffer<[data::Vertex]>>,
ibuffer: Arc<vb::ImmutableBuffer<[u16]>>,
} }
impl Mesh { impl Mesh {
@ -69,7 +117,7 @@ impl Mesh {
vfuture.flush().unwrap(); vfuture.flush().unwrap();
ifuture.flush().unwrap(); ifuture.flush().unwrap();
*cache = Some(VulkanData { *cache = Some(MeshVulkanData {
vbuffer: vbuffer.clone(), vbuffer: vbuffer.clone(),
ibuffer: ibuffer.clone(), ibuffer: ibuffer.clone(),
}); });
@ -96,11 +144,12 @@ impl Eq for Mesh {}
pub struct Object { pub struct Object {
pub mesh: Arc<Mesh>, pub mesh: Arc<Mesh>,
pub texture: Arc<Texture>,
pub transform: cgm::Matrix4<f32>, pub transform: cgm::Matrix4<f32>,
} }
impl Renderable for Object { impl Renderable for Object {
fn render_data(&self) -> Option<(Arc<Mesh>, cgm::Matrix4<f32>)> { fn render_data(&self) -> Option<(Arc<Mesh>, Arc<Texture>, cgm::Matrix4<f32>)> {
Some((self.mesh.clone(), self.transform.clone())) Some((self.mesh.clone(), self.texture.clone(), self.transform.clone()))
} }
} }

View File

@ -4,16 +4,17 @@ use cgmath as cgm;
pub struct Vertex { pub struct Vertex {
pos: [f32; 3], pos: [f32; 3],
color: [f32; 3], color: [f32; 3],
tex: [f32; 2],
} }
impl Vertex { impl Vertex {
pub fn new(pos: [f32; 3], color: [f32; 3]) -> Self { pub fn new(pos: [f32; 3], color: [f32; 3], tex: [f32; 2]) -> Self {
Self { Self {
pos, color, pos, color, tex,
} }
} }
} }
vulkano::impl_vertex!(Vertex, pos, color); vulkano::impl_vertex!(Vertex, pos, color, tex);
#[derive(Default, Copy, Clone)] #[derive(Default, Copy, Clone)]
pub struct Instance { pub struct Instance {

View File

@ -161,8 +161,10 @@ impl<WT: 'static + Send + Sync> Instance<WT> {
// Sort renderables by mesh. // Sort renderables by mesh.
let mut meshes: HashMap<Arc<renderable::Mesh>, Vec<cgm::Matrix4<f32>>> = HashMap::new(); let mut meshes: HashMap<Arc<renderable::Mesh>, Vec<cgm::Matrix4<f32>>> = HashMap::new();
let mut textures: HashMap<Arc<renderable::Mesh>, Arc<renderable::Texture>> = HashMap::new();
for r in renderables { for r in renderables {
if let Some((mesh, transform)) = r.render_data() { if let Some((mesh, texture, transform)) = r.render_data() {
textures.entry(mesh.clone()).or_insert(texture);
let entry = meshes.entry(mesh.clone()).or_insert(vec![]); let entry = meshes.entry(mesh.clone()).or_insert(vec![]);
entry.push(transform); entry.push(transform);
} }
@ -171,6 +173,7 @@ impl<WT: 'static + Send + Sync> Instance<WT> {
let device = self.surface_binding().device.clone(); let device = self.surface_binding().device.clone();
let queue = self.surface_binding().graphics_queue.clone(); let queue = self.surface_binding().graphics_queue.clone();
let rp = self.swapchain_binding().render_pass.clone(); let rp = self.swapchain_binding().render_pass.clone();
let pipeline = self.pipeline.as_ref().unwrap().get_pipeline().clone(); let pipeline = self.pipeline.as_ref().unwrap().get_pipeline().clone();
for (mesh, transforms) in meshes { for (mesh, transforms) in meshes {
@ -188,9 +191,13 @@ impl<WT: 'static + Send + Sync> Instance<WT> {
).unwrap(); ).unwrap();
future.flush().unwrap(); future.flush().unwrap();
let texture = textures.get(&mesh).unwrap().clone();
let image = texture.vulkan_texture(queue.clone());
let ds = self.pipeline.as_mut().unwrap().make_descriptor_set(image);
let (vbuffer, ibuffer) = mesh.vulkan_buffers(queue.clone()); let (vbuffer, ibuffer) = mesh.vulkan_buffers(queue.clone());
builder = builder.draw_indexed(pipeline.clone(), &vc::DynamicState::none(), builder = builder.draw_indexed(pipeline.clone(), &vc::DynamicState::none(),
vec![vbuffer.clone(), instancebuffer], ibuffer.clone(), (), ubo).unwrap(); vec![vbuffer.clone(), instancebuffer], ibuffer.clone(), ds, ubo).unwrap();
buffers.push(Box::new(builder.build().unwrap())); buffers.push(Box::new(builder.build().unwrap()));
} }

View File

@ -11,6 +11,8 @@ use vulkano::framebuffer as vf;
use vulkano::pipeline as vp; use vulkano::pipeline as vp;
use vulkano::pipeline::shader as vps; use vulkano::pipeline::shader as vps;
use vulkano::pipeline::vertex as vpv; use vulkano::pipeline::vertex as vpv;
use vulkano::sampler as vs;
use vulkano::image as vm;
use crate::render::vulkan::data; use crate::render::vulkan::data;
use crate::render::vulkan::shaders; use crate::render::vulkan::shaders;
@ -20,12 +22,13 @@ type VulkanoDescriptorSet = dyn vdd::DescriptorSet + Send + Sync;
pub trait Pipeline { pub trait Pipeline {
fn get_pipeline(&self) -> Arc<VulkanoPipeline>; fn get_pipeline(&self) -> Arc<VulkanoPipeline>;
fn make_descriptor_set(&mut self, buffer: Box<dyn vb::BufferAccess + Send + Sync>) -> Arc<VulkanoDescriptorSet>; fn make_descriptor_set(&mut self, texture_image: Arc<vm::ImmutableImage<Format>>) -> Arc<VulkanoDescriptorSet>;
} }
pub struct Forward { pub struct Forward {
pipeline: Arc<VulkanoPipeline>, pipeline: Arc<VulkanoPipeline>,
descriptor_set_pool: vdd::FixedSizeDescriptorSetsPool, descriptor_set_pool: vdd::FixedSizeDescriptorSetsPool,
device: Arc<vd::Device>,
} }
impl Forward { impl Forward {
@ -35,7 +38,7 @@ impl Forward {
render_pass: Arc<dyn vf::RenderPassAbstract + Send + Sync>, render_pass: Arc<dyn vf::RenderPassAbstract + Send + Sync>,
) -> Forward { ) -> Forward {
let vertex_shader = shaders::ShaderDefinition { let vertex_shader = shaders::ShaderDefinition {
name: "forward_vert.spv".to_string(), name: "engine/shaders/forward_vert.spv".to_string(),
ty: vps::GraphicsShaderType::Vertex, ty: vps::GraphicsShaderType::Vertex,
inputs: vec![ inputs: vec![
vps::ShaderInterfaceDefEntry { vps::ShaderInterfaceDefEntry {
@ -50,12 +53,20 @@ impl Forward {
location: 2..6, format: Format::R32G32B32A32Sfloat, location: 2..6, format: Format::R32G32B32A32Sfloat,
name: Some(Cow::Borrowed("model")), name: Some(Cow::Borrowed("model")),
}, },
vps::ShaderInterfaceDefEntry {
location: 6..7, format: Format::R32G32Sfloat,
name: Some(Cow::Borrowed("tex")),
},
], ],
outputs: vec![ outputs: vec![
vps::ShaderInterfaceDefEntry { vps::ShaderInterfaceDefEntry {
location: 0..1, format: Format::R32G32B32Sfloat, location: 0..1, format: Format::R32G32B32Sfloat,
name: Some(Cow::Borrowed("fragColor")), name: Some(Cow::Borrowed("fragColor")),
} },
vps::ShaderInterfaceDefEntry {
location: 1..2, format: Format::R32G32Sfloat,
name: Some(Cow::Borrowed("fragTexCoord")),
},
], ],
uniforms: vec![], uniforms: vec![],
push_constants: vec![ push_constants: vec![
@ -71,13 +82,17 @@ impl Forward {
}.load_into(device.clone()).expect("could not load vertex shader"); }.load_into(device.clone()).expect("could not load vertex shader");
let fragment_shader = shaders::ShaderDefinition { let fragment_shader = shaders::ShaderDefinition {
name: "forward_frag.spv".to_string(), name: "engine/shaders/forward_frag.spv".to_string(),
ty: vps::GraphicsShaderType::Fragment, ty: vps::GraphicsShaderType::Fragment,
inputs: vec![ inputs: vec![
vps::ShaderInterfaceDefEntry { vps::ShaderInterfaceDefEntry {
location: 0..1, format: Format::R32G32B32Sfloat, location: 0..1, format: Format::R32G32B32Sfloat,
name: Some(Cow::Borrowed("fragColor")), name: Some(Cow::Borrowed("fragColor")),
} },
vps::ShaderInterfaceDefEntry {
location: 1..2, format: Format::R32G32Sfloat,
name: Some(Cow::Borrowed("fragTexCoord")),
},
], ],
outputs: vec![ outputs: vec![
vps::ShaderInterfaceDefEntry { vps::ShaderInterfaceDefEntry {
@ -85,7 +100,23 @@ impl Forward {
name: Some(Cow::Borrowed("outColor")), name: Some(Cow::Borrowed("outColor")),
} }
], ],
uniforms: vec![], uniforms: vec![
vdD::DescriptorDesc {
ty: vdD::DescriptorDescTy::CombinedImageSampler(vdD::DescriptorImageDesc {
sampled: true,
dimensions: vdD::DescriptorImageDescDimensions::TwoDimensional,
format: None,
multisampled: false,
array_layers: vdD::DescriptorImageDescArray::NonArrayed,
}),
array_count: 1,
readonly: true,
stages: vdD::ShaderStages {
fragment: true,
..vdD::ShaderStages::none()
},
},
],
push_constants: vec![], push_constants: vec![],
}.load_into(device.clone()).expect("could not load fragment shader"); }.load_into(device.clone()).expect("could not load fragment shader");
@ -127,7 +158,8 @@ impl Forward {
Forward { Forward {
pipeline, pipeline,
descriptor_set_pool descriptor_set_pool,
device
} }
} }
} }
@ -137,9 +169,10 @@ impl Pipeline for Forward {
self.pipeline.clone() self.pipeline.clone()
} }
fn make_descriptor_set(&mut self, buffer: Box<dyn vb::BufferAccess + Send + Sync>) -> Arc<VulkanoDescriptorSet> { fn make_descriptor_set(&mut self, texture_image: Arc<vm::ImmutableImage<Format>>) -> Arc<VulkanoDescriptorSet> {
let image_sampler = vs::Sampler::simple_repeat_linear(self.device.clone());
Arc::new(self.descriptor_set_pool.next() Arc::new(self.descriptor_set_pool.next()
.add_buffer(buffer).unwrap() .add_sampled_image(texture_image.clone(), image_sampler).unwrap()
.build().unwrap()) .build().unwrap())
} }
} }

View File

@ -6,7 +6,7 @@ pub fn resource_path(name: String) -> path::PathBuf {
fn stringify(x: std::io::Error) -> String { format!("IO error: {}", x) } fn stringify(x: std::io::Error) -> String { format!("IO error: {}", x) }
match Runfiles::create().map_err(stringify) { match Runfiles::create().map_err(stringify) {
Err(_) => path::Path::new(".").join("shaders").join(name), Err(_) => path::Path::new(".").join(name),
Ok(r) => r.rlocation(format!("abrasion/engine/shaders/{}", name)) Ok(r) => r.rlocation(format!("abrasion/{}", name))
} }
} }