engine/render: refactor mesh and materials into separate modules
parent
2eaecfd1dd
commit
1a52782882
|
@ -13,6 +13,8 @@ rust_binary(
|
|||
"src/main.rs",
|
||||
"src/physics/mod.rs",
|
||||
"src/physics/color.rs",
|
||||
"src/render/material.rs",
|
||||
"src/render/mesh.rs",
|
||||
"src/render/mod.rs",
|
||||
"src/render/renderable.rs",
|
||||
"src/render/vulkan/data.rs",
|
||||
|
|
|
@ -10,7 +10,9 @@ mod util;
|
|||
mod physics;
|
||||
|
||||
use render::vulkan::data;
|
||||
use render::renderable::{Object, Renderable, ResourceManager, Mesh, Texture, PBRTextureSet};
|
||||
use render::material::{Texture, PBRMaterialBuilder};
|
||||
use render::mesh::Mesh;
|
||||
use render::renderable::{Object, Renderable, ResourceManager};
|
||||
use physics::color;
|
||||
|
||||
fn main() {
|
||||
|
@ -66,10 +68,10 @@ fn main() {
|
|||
rm.add_mesh(Mesh::new(vertices, indices))
|
||||
};
|
||||
|
||||
let material = PBRTextureSet {
|
||||
let material = rm.add_material(PBRMaterialBuilder {
|
||||
diffuse: Texture::from_image(String::from("assets/test-128px.png")),
|
||||
roughness: Texture::from_color(color::LinearF32::new(1.0)),
|
||||
}.build(&mut rm);
|
||||
}.build());
|
||||
|
||||
|
||||
let mut cubes: Vec<Box<Object>> = vec![];
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::time;
|
||||
|
||||
use image;
|
||||
use image::GenericImageView;
|
||||
use vulkano::device as vd;
|
||||
use vulkano::format as vf;
|
||||
use vulkano::image as vm;
|
||||
use vulkano::sync::GpuFuture;
|
||||
|
||||
use crate::physics::color;
|
||||
use crate::render::vulkan::data;
|
||||
use crate::util::file;
|
||||
|
||||
pub trait ChannelLayout {
|
||||
fn vulkan_from_image(
|
||||
image: Arc<image::DynamicImage>,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>>;
|
||||
|
||||
fn vulkan_from_value(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>>;
|
||||
}
|
||||
|
||||
impl ChannelLayout for color::XYZ {
|
||||
fn vulkan_from_image(
|
||||
image: Arc<image::DynamicImage>,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
let (width, height) = (image.width(), image.height());
|
||||
let rgba = image.to_rgba();
|
||||
// TODO(q3k): RGB -> CIE XYZ
|
||||
let (image_view, future) = vm::ImmutableImage::from_iter(
|
||||
rgba.into_raw().iter().cloned(),
|
||||
vm::Dimensions::Dim2d{ width, height },
|
||||
vf::Format::R8G8B8A8Unorm,
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
|
||||
future.flush().unwrap();
|
||||
image_view
|
||||
}
|
||||
|
||||
fn vulkan_from_value(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
let mut image = image::ImageBuffer::<image::Rgba<f32>, Vec<f32>>::new(1, 1);
|
||||
image.put_pixel(0, 0, image::Rgba([self.x, self.y, self.z, 0.0]));
|
||||
|
||||
let (image_view, future) = vm::ImmutableImage::from_iter(
|
||||
image.into_raw().iter().cloned(),
|
||||
vm::Dimensions::Dim2d{ width: 1, height: 1 },
|
||||
vf::Format::R32G32B32A32Sfloat,
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
future.flush().unwrap();
|
||||
image_view
|
||||
}
|
||||
}
|
||||
|
||||
impl ChannelLayout for color::LinearF32 {
|
||||
fn vulkan_from_image(
|
||||
image: Arc<image::DynamicImage>,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
let (width, height) = (image.width(), image.height());
|
||||
assert!(match image.color() {
|
||||
image::ColorType::L8 => true,
|
||||
image::ColorType::L16 => true,
|
||||
_ => false,
|
||||
}, "linearf32 texture must be 8-bit grayscale");
|
||||
let gray = image.to_luma();
|
||||
let (image_view, future) = vm::ImmutableImage::from_iter(
|
||||
gray.into_raw().iter().cloned(),
|
||||
vm::Dimensions::Dim2d{ width, height },
|
||||
vf::Format::R8G8B8A8Unorm,
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
|
||||
future.flush().unwrap();
|
||||
image_view
|
||||
}
|
||||
|
||||
fn vulkan_from_value(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
let mut image = image::ImageBuffer::<image::Luma<f32>, Vec<f32>>::new(1, 1);
|
||||
image.put_pixel(0, 0, image::Luma([self.d]));
|
||||
|
||||
let (image_view, future) = vm::ImmutableImage::from_iter(
|
||||
image.into_raw().iter().cloned(),
|
||||
vm::Dimensions::Dim2d{ width: 1, height: 1 },
|
||||
vf::Format::R32Sfloat,
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
|
||||
future.flush().unwrap();
|
||||
image_view
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Texture<T: ChannelLayout> {
|
||||
Color(T),
|
||||
ImageRef(String),
|
||||
}
|
||||
|
||||
impl<T: ChannelLayout> Texture<T> {
|
||||
fn vulkan_image(&self, graphics_queue: Arc<vd::Queue>) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
match self {
|
||||
Texture::<T>::Color(c) => c.vulkan_from_value(graphics_queue),
|
||||
Texture::<T>::ImageRef(r) => {
|
||||
let path = &file::resource_path(r.clone());
|
||||
let img = Arc::new(image::open(path).unwrap());
|
||||
T::vulkan_from_image(img, graphics_queue)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_color(color: T) -> Self {
|
||||
Texture::<T>::Color(color)
|
||||
}
|
||||
|
||||
pub fn from_image(name: String) -> Self {
|
||||
Texture::<T>::ImageRef(name)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Material {
|
||||
diffuse: Texture<color::XYZ>,
|
||||
roughness: Texture<color::LinearF32>,
|
||||
|
||||
pub id: u64,
|
||||
// vulkan cache
|
||||
vulkan: Mutex<Option<data::Textures>>,
|
||||
}
|
||||
|
||||
impl Material {
|
||||
pub fn new(
|
||||
diffuse: Texture<color::XYZ>,
|
||||
roughness: Texture<color::LinearF32>,
|
||||
) -> Self {
|
||||
Self {
|
||||
diffuse,
|
||||
roughness,
|
||||
|
||||
// TODO: use a better method
|
||||
id: time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos() as u64,
|
||||
vulkan: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vulkan_textures(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> data::Textures {
|
||||
let mut cache = self.vulkan.lock().unwrap();
|
||||
match &mut *cache {
|
||||
Some(data) => data.clone(),
|
||||
None => {
|
||||
let diffuse = self.diffuse.vulkan_image(graphics_queue.clone());
|
||||
let roughness = self.roughness.vulkan_image(graphics_queue.clone());
|
||||
let textures = data::Textures {
|
||||
diffuse, roughness,
|
||||
};
|
||||
*cache = Some(textures.clone());
|
||||
textures
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PBRMaterialBuilder {
|
||||
pub diffuse: Texture<color::XYZ>,
|
||||
pub roughness: Texture<color::LinearF32>,
|
||||
}
|
||||
|
||||
impl PBRMaterialBuilder {
|
||||
pub fn build(self) -> Material {
|
||||
Material::new(self.diffuse, self.roughness)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
use std::sync::Arc;
|
||||
use std::time;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use vulkano::device as vd;
|
||||
use vulkano::buffer as vb;
|
||||
use vulkano::sync::GpuFuture;
|
||||
|
||||
use crate::render::vulkan::data;
|
||||
|
||||
pub struct Mesh {
|
||||
vertices: Arc<Vec<data::Vertex>>,
|
||||
indices: Arc<Vec<u16>>,
|
||||
|
||||
pub id: u64,
|
||||
// vulkan buffers cache
|
||||
vulkan: Mutex<Option<data::VertexData>>,
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
pub fn new(
|
||||
vertices: Arc<Vec<data::Vertex>>,
|
||||
indices: Arc<Vec<u16>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
vertices, indices,
|
||||
// TODO: use a better method
|
||||
id: time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos() as u64,
|
||||
vulkan: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vulkan_buffers(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> (
|
||||
Arc<vb::ImmutableBuffer<[data::Vertex]>>,
|
||||
Arc<vb::ImmutableBuffer<[u16]>>,
|
||||
) {
|
||||
let mut cache = self.vulkan.lock().unwrap();
|
||||
match &mut *cache {
|
||||
Some(data) => (data.vbuffer.clone(), data.ibuffer.clone()),
|
||||
None => {
|
||||
let (vbuffer, vfuture) = vb::immutable::ImmutableBuffer::from_iter(
|
||||
self.vertices.iter().cloned(),
|
||||
vb::BufferUsage::vertex_buffer(),
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
let (ibuffer, ifuture) = vb::immutable::ImmutableBuffer::from_iter(
|
||||
self.indices.iter().cloned(),
|
||||
vb::BufferUsage::index_buffer(),
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
vfuture.flush().unwrap();
|
||||
ifuture.flush().unwrap();
|
||||
|
||||
*cache = Some(data::VertexData {
|
||||
vbuffer: vbuffer.clone(),
|
||||
ibuffer: ibuffer.clone(),
|
||||
});
|
||||
|
||||
(vbuffer.clone(), ibuffer.clone())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,8 @@ use vulkano::instance as vi;
|
|||
use vulkano::swapchain as vs;
|
||||
|
||||
pub mod vulkan;
|
||||
pub mod material;
|
||||
pub mod mesh;
|
||||
pub mod renderable;
|
||||
|
||||
const WIDTH: u32 = 800;
|
||||
|
|
|
@ -1,21 +1,10 @@
|
|||
use std::collections::HashMap;
|
||||
use std::hash;
|
||||
use std::sync::Arc;
|
||||
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;
|
||||
use crate::physics::color;
|
||||
use crate::util::file;
|
||||
use crate::render::material::Material;
|
||||
use crate::render::mesh::Mesh;
|
||||
|
||||
pub struct ResourceManager {
|
||||
meshes: HashMap<u64, Mesh>,
|
||||
|
@ -88,118 +77,6 @@ impl<'a> ResourceManager {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct PBRTextureSet {
|
||||
pub diffuse: Texture<color::XYZ>,
|
||||
pub roughness: Texture<color::LinearF32>,
|
||||
}
|
||||
|
||||
impl PBRTextureSet {
|
||||
pub fn build(self, rm: &mut ResourceManager) -> ResourceID {
|
||||
rm.add_material(Material::new(self.diffuse, self.roughness))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Material {
|
||||
diffuse: Texture<color::XYZ>,
|
||||
roughness: Texture<color::LinearF32>,
|
||||
|
||||
id: u64,
|
||||
// vulkan cache
|
||||
vulkan: Mutex<Option<data::Textures>>,
|
||||
}
|
||||
|
||||
impl Material {
|
||||
pub fn new(
|
||||
diffuse: Texture<color::XYZ>,
|
||||
roughness: Texture<color::LinearF32>,
|
||||
) -> Self {
|
||||
Self {
|
||||
diffuse,
|
||||
roughness,
|
||||
|
||||
// TODO: use a better method
|
||||
id: time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos() as u64,
|
||||
vulkan: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vulkan_textures(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> data::Textures {
|
||||
let mut cache = self.vulkan.lock().unwrap();
|
||||
match &mut *cache {
|
||||
Some(data) => data.clone(),
|
||||
None => {
|
||||
let diffuse = self.diffuse.vulkan_image(graphics_queue.clone());
|
||||
let roughness = self.roughness.vulkan_image(graphics_queue.clone());
|
||||
let textures = data::Textures {
|
||||
diffuse, roughness,
|
||||
};
|
||||
*cache = Some(textures.clone());
|
||||
textures
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mesh {
|
||||
vertices: Arc<Vec<data::Vertex>>,
|
||||
indices: Arc<Vec<u16>>,
|
||||
|
||||
id: u64,
|
||||
// vulkan buffers cache
|
||||
vulkan: Mutex<Option<data::VertexData>>,
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
pub fn new(
|
||||
vertices: Arc<Vec<data::Vertex>>,
|
||||
indices: Arc<Vec<u16>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
vertices, indices,
|
||||
// TODO: use a better method
|
||||
id: time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos() as u64,
|
||||
vulkan: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vulkan_buffers(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> (
|
||||
Arc<vb::ImmutableBuffer<[data::Vertex]>>,
|
||||
Arc<vb::ImmutableBuffer<[u16]>>,
|
||||
) {
|
||||
let mut cache = self.vulkan.lock().unwrap();
|
||||
match &mut *cache {
|
||||
Some(data) => (data.vbuffer.clone(), data.ibuffer.clone()),
|
||||
None => {
|
||||
let (vbuffer, vfuture) = vb::immutable::ImmutableBuffer::from_iter(
|
||||
self.vertices.iter().cloned(),
|
||||
vb::BufferUsage::vertex_buffer(),
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
let (ibuffer, ifuture) = vb::immutable::ImmutableBuffer::from_iter(
|
||||
self.indices.iter().cloned(),
|
||||
vb::BufferUsage::index_buffer(),
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
vfuture.flush().unwrap();
|
||||
ifuture.flush().unwrap();
|
||||
|
||||
*cache = Some(data::VertexData {
|
||||
vbuffer: vbuffer.clone(),
|
||||
ibuffer: ibuffer.clone(),
|
||||
});
|
||||
|
||||
(vbuffer.clone(), ibuffer.clone())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Renderable {
|
||||
fn render_data(&self) -> Option<(ResourceID, ResourceID, &cgm::Matrix4<f32>)> {
|
||||
None
|
||||
|
@ -218,120 +95,3 @@ impl Renderable for Object {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ChannelLayout {
|
||||
fn vulkan_from_image(
|
||||
image: Arc<image::DynamicImage>,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>>;
|
||||
|
||||
fn vulkan_from_value(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>>;
|
||||
}
|
||||
|
||||
impl ChannelLayout for color::XYZ {
|
||||
fn vulkan_from_image(
|
||||
image: Arc<image::DynamicImage>,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
let (width, height) = (image.width(), image.height());
|
||||
let rgba = image.to_rgba();
|
||||
// TODO(q3k): RGB -> CIE XYZ
|
||||
let (image_view, future) = vm::ImmutableImage::from_iter(
|
||||
rgba.into_raw().iter().cloned(),
|
||||
vm::Dimensions::Dim2d{ width, height },
|
||||
vf::Format::R8G8B8A8Unorm,
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
|
||||
future.flush().unwrap();
|
||||
image_view
|
||||
}
|
||||
|
||||
fn vulkan_from_value(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
let mut image = image::ImageBuffer::<image::Rgba<f32>, Vec<f32>>::new(1, 1);
|
||||
image.put_pixel(0, 0, image::Rgba([self.x, self.y, self.z, 0.0]));
|
||||
|
||||
let (image_view, future) = vm::ImmutableImage::from_iter(
|
||||
image.into_raw().iter().cloned(),
|
||||
vm::Dimensions::Dim2d{ width: 1, height: 1 },
|
||||
vf::Format::R32G32B32A32Sfloat,
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
future.flush().unwrap();
|
||||
image_view
|
||||
}
|
||||
}
|
||||
|
||||
impl ChannelLayout for color::LinearF32 {
|
||||
fn vulkan_from_image(
|
||||
image: Arc<image::DynamicImage>,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
let (width, height) = (image.width(), image.height());
|
||||
assert!(match image.color() {
|
||||
image::ColorType::L8 => true,
|
||||
image::ColorType::L16 => true,
|
||||
_ => false,
|
||||
}, "linearf32 texture must be 8-bit grayscale");
|
||||
let gray = image.to_luma();
|
||||
let (image_view, future) = vm::ImmutableImage::from_iter(
|
||||
gray.into_raw().iter().cloned(),
|
||||
vm::Dimensions::Dim2d{ width, height },
|
||||
vf::Format::R8G8B8A8Unorm,
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
|
||||
future.flush().unwrap();
|
||||
image_view
|
||||
}
|
||||
|
||||
fn vulkan_from_value(
|
||||
&self,
|
||||
graphics_queue: Arc<vd::Queue>,
|
||||
) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
let mut image = image::ImageBuffer::<image::Luma<f32>, Vec<f32>>::new(1, 1);
|
||||
image.put_pixel(0, 0, image::Luma([self.d]));
|
||||
|
||||
let (image_view, future) = vm::ImmutableImage::from_iter(
|
||||
image.into_raw().iter().cloned(),
|
||||
vm::Dimensions::Dim2d{ width: 1, height: 1 },
|
||||
vf::Format::R32Sfloat,
|
||||
graphics_queue.clone(),
|
||||
).unwrap();
|
||||
|
||||
future.flush().unwrap();
|
||||
image_view
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Texture<T: ChannelLayout> {
|
||||
Color(T),
|
||||
ImageRef(String),
|
||||
}
|
||||
|
||||
impl<T: ChannelLayout> Texture<T> {
|
||||
fn vulkan_image(&self, graphics_queue: Arc<vd::Queue>) -> Arc<vm::ImmutableImage<vf::Format>> {
|
||||
match self {
|
||||
Texture::<T>::Color(c) => c.vulkan_from_value(graphics_queue),
|
||||
Texture::<T>::ImageRef(r) => {
|
||||
let path = &file::resource_path(r.clone());
|
||||
let img = Arc::new(image::open(path).unwrap());
|
||||
T::vulkan_from_image(img, graphics_queue)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_color(color: T) -> Self {
|
||||
Texture::<T>::Color(color)
|
||||
}
|
||||
|
||||
pub fn from_image(name: String) -> Self {
|
||||
Texture::<T>::ImageRef(name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue