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 = [
"//engine/shaders:forward_vert",
"//engine/shaders:forward_frag",
"//assets:test-128px.png",
],
)

View File

@ -2,9 +2,14 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(binding = 0) uniform sampler2D texSampler;
layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
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 = 1) in vec3 color;
layout(location = 2) in mat4 model;
layout(location = 6) in vec2 tex;
layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord;
out gl_PerVertex {
vec4 gl_Position;
@ -19,6 +21,8 @@ void main() {
gl_Position = ubo.view * model * vec4(pos, 1.0);
fragColor = color;
fragTexCoord = tex;
// Vulkanize
gl_Position.y = -gl_Position.y;
}

View File

@ -17,33 +17,55 @@ fn main() {
let mesh_cube = {
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], [0.0, 1.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], [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], [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], [1.0, 1.0, 1.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, 1.0, 1.0], [0.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], [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, 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![
// bottom
2, 1, 0, 0, 3, 2,
// top
4, 5, 6, 6, 7, 4,
0, 1, 2, 2, 3, 0,
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))
};
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 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 cube = render::renderable::Object {
mesh: mesh_cube.clone(),
transform
transform,
texture: texture_cube.clone(),
};
cubes.push(Arc::new(cube));
}

View File

@ -4,21 +4,64 @@ use std::sync::Mutex;
use std::time;
use cgmath as cgm;
use image;
use image::GenericImageView;
use vulkano::device as vd;
use vulkano::buffer as vb;
use vulkano::sync::GpuFuture;
use vulkano::format as vf;
use vulkano::image as vm;
use crate::render::vulkan::data;
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
}
}
struct VulkanData {
vbuffer: Arc<vb::ImmutableBuffer<[data::Vertex]>>,
ibuffer: Arc<vb::ImmutableBuffer<[u16]>>,
pub struct Texture {
image: Arc<image::DynamicImage>,
// 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 {
@ -27,7 +70,12 @@ pub struct Mesh {
id: u64,
// 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 {
@ -69,7 +117,7 @@ impl Mesh {
vfuture.flush().unwrap();
ifuture.flush().unwrap();
*cache = Some(VulkanData {
*cache = Some(MeshVulkanData {
vbuffer: vbuffer.clone(),
ibuffer: ibuffer.clone(),
});
@ -96,11 +144,12 @@ impl Eq for Mesh {}
pub struct Object {
pub mesh: Arc<Mesh>,
pub texture: Arc<Texture>,
pub transform: cgm::Matrix4<f32>,
}
impl Renderable for Object {
fn render_data(&self) -> Option<(Arc<Mesh>, cgm::Matrix4<f32>)> {
Some((self.mesh.clone(), self.transform.clone()))
fn render_data(&self) -> Option<(Arc<Mesh>, Arc<Texture>, cgm::Matrix4<f32>)> {
Some((self.mesh.clone(), self.texture.clone(), self.transform.clone()))
}
}

View File

@ -4,16 +4,17 @@ use cgmath as cgm;
pub struct Vertex {
pos: [f32; 3],
color: [f32; 3],
tex: [f32; 2],
}
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 {
pos, color,
pos, color, tex,
}
}
}
vulkano::impl_vertex!(Vertex, pos, color);
vulkano::impl_vertex!(Vertex, pos, color, tex);
#[derive(Default, Copy, Clone)]
pub struct Instance {

View File

@ -161,8 +161,10 @@ impl<WT: 'static + Send + Sync> Instance<WT> {
// Sort renderables by mesh.
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 {
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![]);
entry.push(transform);
}
@ -171,6 +173,7 @@ impl<WT: 'static + Send + Sync> Instance<WT> {
let device = self.surface_binding().device.clone();
let queue = self.surface_binding().graphics_queue.clone();
let rp = self.swapchain_binding().render_pass.clone();
let pipeline = self.pipeline.as_ref().unwrap().get_pipeline().clone();
for (mesh, transforms) in meshes {
@ -188,9 +191,13 @@ impl<WT: 'static + Send + Sync> Instance<WT> {
).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());
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()));
}

View File

@ -11,6 +11,8 @@ use vulkano::framebuffer as vf;
use vulkano::pipeline as vp;
use vulkano::pipeline::shader as vps;
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::shaders;
@ -20,12 +22,13 @@ type VulkanoDescriptorSet = dyn vdd::DescriptorSet + Send + Sync;
pub trait Pipeline {
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 {
pipeline: Arc<VulkanoPipeline>,
descriptor_set_pool: vdd::FixedSizeDescriptorSetsPool,
device: Arc<vd::Device>,
}
impl Forward {
@ -35,7 +38,7 @@ impl Forward {
render_pass: Arc<dyn vf::RenderPassAbstract + Send + Sync>,
) -> Forward {
let vertex_shader = shaders::ShaderDefinition {
name: "forward_vert.spv".to_string(),
name: "engine/shaders/forward_vert.spv".to_string(),
ty: vps::GraphicsShaderType::Vertex,
inputs: vec![
vps::ShaderInterfaceDefEntry {
@ -50,12 +53,20 @@ impl Forward {
location: 2..6, format: Format::R32G32B32A32Sfloat,
name: Some(Cow::Borrowed("model")),
},
vps::ShaderInterfaceDefEntry {
location: 6..7, format: Format::R32G32Sfloat,
name: Some(Cow::Borrowed("tex")),
},
],
outputs: vec![
vps::ShaderInterfaceDefEntry {
location: 0..1, format: Format::R32G32B32Sfloat,
name: Some(Cow::Borrowed("fragColor")),
}
},
vps::ShaderInterfaceDefEntry {
location: 1..2, format: Format::R32G32Sfloat,
name: Some(Cow::Borrowed("fragTexCoord")),
},
],
uniforms: vec![],
push_constants: vec![
@ -71,13 +82,17 @@ impl Forward {
}.load_into(device.clone()).expect("could not load vertex shader");
let fragment_shader = shaders::ShaderDefinition {
name: "forward_frag.spv".to_string(),
name: "engine/shaders/forward_frag.spv".to_string(),
ty: vps::GraphicsShaderType::Fragment,
inputs: vec![
vps::ShaderInterfaceDefEntry {
location: 0..1, format: Format::R32G32B32Sfloat,
name: Some(Cow::Borrowed("fragColor")),
}
},
vps::ShaderInterfaceDefEntry {
location: 1..2, format: Format::R32G32Sfloat,
name: Some(Cow::Borrowed("fragTexCoord")),
},
],
outputs: vec![
vps::ShaderInterfaceDefEntry {
@ -85,7 +100,23 @@ impl Forward {
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![],
}.load_into(device.clone()).expect("could not load fragment shader");
@ -127,7 +158,8 @@ impl Forward {
Forward {
pipeline,
descriptor_set_pool
descriptor_set_pool,
device
}
}
}
@ -137,9 +169,10 @@ impl Pipeline for Forward {
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()
.add_buffer(buffer).unwrap()
.add_sampled_image(texture_image.clone(), image_sampler).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) }
match Runfiles::create().map_err(stringify) {
Err(_) => path::Path::new(".").join("shaders").join(name),
Ok(r) => r.rlocation(format!("abrasion/engine/shaders/{}", name))
Err(_) => path::Path::new(".").join(name),
Ok(r) => r.rlocation(format!("abrasion/{}", name))
}
}