resource, render: load in texture sampler from gltf and use them in the renderer
This commit is contained in:
parent
b941fa2fe0
commit
5331cfc2c4
|
@ -93,21 +93,21 @@ async fn main() {
|
|||
//let diffuse_texture = resman.request::<Texture>("assets/happy-tree.png").unwrap();
|
||||
//let antique_camera_model = resman.request::<Model>("assets/AntiqueCamera.glb").unwrap();
|
||||
//let cube_model = resman.request::<Model>("assets/cube-texture-bin.glb").unwrap();
|
||||
let cube_gltf = resman.request::<Gltf>("assets/texture-sep/texture-sep.gltf").unwrap();
|
||||
/* let cube_gltf = resman.request::<Gltf>("assets/texture-sep/texture-sep.gltf").unwrap();
|
||||
let crate_gltf = resman.request::<Gltf>("assets/crate/crate.gltf").unwrap();
|
||||
|
||||
let separate_gltf = resman.request::<Gltf>("assets/pos-testing/separate-nodes-two-cubes.glb").unwrap();
|
||||
drop(resman);
|
||||
let separate_gltf = resman.request::<Gltf>("assets/pos-testing/child-node-cubes.glb").unwrap(); */
|
||||
//drop(resman);
|
||||
|
||||
let cube_mesh = &cube_gltf.data_ref()
|
||||
/* let cube_mesh = &cube_gltf.data_ref()
|
||||
.unwrap().meshes[0];
|
||||
let crate_mesh = &crate_gltf.data_ref()
|
||||
.unwrap().meshes[0];
|
||||
|
||||
let separate_scene = &separate_gltf.data_ref()
|
||||
.unwrap().scenes[0];
|
||||
.unwrap().scenes[0]; */
|
||||
|
||||
/* let sponza_model = resman.request::<Gltf>("assets/sponza/Sponza.gltf").unwrap();
|
||||
let sponza_model = resman.request::<Gltf>("assets/sponza/Sponza.gltf").unwrap();
|
||||
drop(resman);
|
||||
|
||||
let sponza_scene = &sponza_model.data_ref()
|
||||
|
@ -116,12 +116,12 @@ async fn main() {
|
|||
world.spawn((
|
||||
sponza_scene.clone(),
|
||||
Transform::from_xyz(0.0, 0.0, 0.0),
|
||||
)); */
|
||||
));
|
||||
|
||||
world.spawn((
|
||||
/* world.spawn((
|
||||
separate_scene.clone(),
|
||||
Transform::from_xyz(0.0, -5.0, -10.0),
|
||||
));
|
||||
)); */
|
||||
|
||||
/* {
|
||||
let cube_tran = Transform::from_xyz(-5.9026427, -1.8953488, -10.0);
|
||||
|
@ -146,7 +146,7 @@ async fn main() {
|
|||
specular: 1.3,
|
||||
},
|
||||
light_tran,
|
||||
cube_mesh.clone(),
|
||||
//cube_mesh.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use lyra_resource::{ResHandle, Texture};
|
||||
|
||||
use super::texture::RenderTexture;
|
||||
|
||||
pub struct MaterialSpecular {
|
||||
|
@ -9,13 +11,18 @@ pub struct MaterialSpecular {
|
|||
pub color_texture: Option<RenderTexture>,
|
||||
}
|
||||
|
||||
fn texture_to_render(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: &Arc<wgpu::BindGroupLayout>, i: &Option<ResHandle<Texture>>) -> Option<RenderTexture> {
|
||||
if let Some(tex) = i {
|
||||
RenderTexture::from_resource(device, queue, bg_layout.clone(), tex, None).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl MaterialSpecular {
|
||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, value: &lyra_resource::gltf::Specular) -> Self {
|
||||
let tex = value.texture.as_ref().and_then(|t| t.data_ref())
|
||||
.map(|i| RenderTexture::from_image(device, queue, bg_layout.clone(), &i.image, None).unwrap());
|
||||
|
||||
let color_tex = value.color_texture.as_ref().and_then(|t| t.data_ref())
|
||||
.map(|i| RenderTexture::from_image(device, queue, bg_layout, &i.image, None).unwrap());
|
||||
let tex = texture_to_render(device, queue, &bg_layout, &value.texture);
|
||||
let color_tex = texture_to_render(device, queue, &bg_layout, &value.color_texture);
|
||||
|
||||
Self {
|
||||
factor: value.factor,
|
||||
|
@ -39,8 +46,7 @@ pub struct Material {
|
|||
|
||||
impl Material {
|
||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, value: &lyra_resource::gltf::Material) -> Self {
|
||||
let diffuse_texture = value.base_color_texture.as_ref().and_then(|t| t.data_ref())
|
||||
.map(|i| RenderTexture::from_image(device, queue, bg_layout.clone(), &i.image, None).unwrap());
|
||||
let diffuse_texture = texture_to_render(device, queue, &bg_layout, &value.base_color_texture);
|
||||
|
||||
let specular = value.specular.as_ref().map(|s| MaterialSpecular::from_resource(device, queue, bg_layout.clone(), s));
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use image::GenericImageView;
|
||||
use lyra_resource::{ResHandle, Texture};
|
||||
use lyra_resource::{FilterMode, ResHandle, Texture, WrappingMode};
|
||||
|
||||
use super::render_buffer::BindGroupPair;
|
||||
|
||||
|
@ -134,12 +134,101 @@ impl RenderTexture {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, texture_res: &ResHandle<Texture>, label: Option<&str>) -> anyhow::Result<Self> {
|
||||
let texture_ref = texture_res.data_ref().unwrap();
|
||||
let img = texture_ref.image.data_ref().unwrap();
|
||||
|
||||
let rgba = img.to_rgba8();
|
||||
let dimensions = img.dimensions();
|
||||
|
||||
let size = wgpu::Extent3d {
|
||||
width: dimensions.0,
|
||||
height: dimensions.1,
|
||||
depth_or_array_layers: 1,
|
||||
};
|
||||
let texture = device.create_texture(
|
||||
&wgpu::TextureDescriptor {
|
||||
label,
|
||||
size,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||
view_formats: &[],
|
||||
}
|
||||
);
|
||||
|
||||
queue.write_texture(
|
||||
wgpu::ImageCopyTexture {
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
},
|
||||
&rgba,
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
|
||||
rows_per_image: std::num::NonZeroU32::new(dimensions.1),
|
||||
},
|
||||
size,
|
||||
);
|
||||
|
||||
// convert resource sampler into wgpu sampler
|
||||
let sampler_desc = match &texture_ref.sampler {
|
||||
Some(sampler) => {
|
||||
let magf = res_filter_to_wgpu(sampler.mag_filter.unwrap_or(FilterMode::Linear));
|
||||
let minf = res_filter_to_wgpu(sampler.min_filter.unwrap_or(FilterMode::Nearest));
|
||||
let mipf = res_filter_to_wgpu(sampler.mipmap_filter.unwrap_or(FilterMode::Nearest));
|
||||
|
||||
let wrap_u = res_wrap_to_wgpu(sampler.wrap_u);
|
||||
let wrap_v = res_wrap_to_wgpu(sampler.wrap_v);
|
||||
let wrap_w = res_wrap_to_wgpu(sampler.wrap_w);
|
||||
|
||||
wgpu::SamplerDescriptor {
|
||||
address_mode_u: wrap_u,
|
||||
address_mode_v: wrap_v,
|
||||
address_mode_w: wrap_w,
|
||||
mag_filter: magf,
|
||||
min_filter: minf,
|
||||
mipmap_filter: mipf,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
None => wgpu::SamplerDescriptor {
|
||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Nearest,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let sampler = device.create_sampler(
|
||||
&sampler_desc
|
||||
);
|
||||
|
||||
let bgp = Self::create_bind_group_pair(device, bg_layout, &view, &sampler);
|
||||
|
||||
Ok(Self {
|
||||
inner_texture: texture,
|
||||
view,
|
||||
sampler,
|
||||
bindgroup_pair: Some(bgp),
|
||||
})
|
||||
}
|
||||
|
||||
/// Updates the texture on the gpu with the provided texture.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if `texture` is not loaded
|
||||
pub fn update_texture(&mut self, _device: &wgpu::Device, queue: &wgpu::Queue, texture: &ResHandle<Texture>) {
|
||||
let texture = &texture.data_ref().unwrap().image;
|
||||
let texture = &texture.data_ref().unwrap();
|
||||
let rgba = texture.to_rgba8();
|
||||
let dimensions = texture.dimensions();
|
||||
let size = wgpu::Extent3d {
|
||||
|
@ -216,3 +305,20 @@ impl RenderTexture {
|
|||
&self.bindgroup_pair.as_ref().unwrap().bindgroup
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert [`lyra_resource::WrappingMode`] to [`wgpu::AddressMode`]
|
||||
fn res_wrap_to_wgpu(wmode: WrappingMode) -> wgpu::AddressMode {
|
||||
match wmode {
|
||||
WrappingMode::ClampToEdge => wgpu::AddressMode::ClampToEdge,
|
||||
WrappingMode::MirroredRepeat => wgpu::AddressMode::MirrorRepeat,
|
||||
WrappingMode::Repeat => wgpu::AddressMode::Repeat,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert [`lyra_resource::FilterMode`] to [`wgpu::FilterMode`]
|
||||
fn res_filter_to_wgpu(fmode: FilterMode) -> wgpu::FilterMode {
|
||||
match fmode {
|
||||
FilterMode::Nearest => wgpu::FilterMode::Nearest,
|
||||
FilterMode::Linear => wgpu::FilterMode::Linear,
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
use std::{collections::hash_map::DefaultHasher, hash::{Hash, Hasher}};
|
||||
|
||||
use crate::{Texture, ResHandle, util};
|
||||
use gltf::texture::{MagFilter, MinFilter};
|
||||
|
||||
use crate::{util, FilterMode, Image, ResHandle, Texture, TextureSampler, WrappingMode};
|
||||
use super::loader::GltfLoadContext;
|
||||
|
||||
/// PBR metallic roughness
|
||||
|
@ -248,15 +250,33 @@ impl Material {
|
|||
fn load_texture(context: &mut GltfLoadContext, texture_info: gltf::texture::Info<'_>) -> ResHandle<Texture> {
|
||||
// TODO: texture_info.tex_coord()
|
||||
let tex = texture_info.texture();
|
||||
// TODO: tex.sampler()
|
||||
let img = tex.source();
|
||||
let src = img.source();
|
||||
|
||||
let buf = Material::read_source(context, src).unwrap();
|
||||
let buflen = buf.len();
|
||||
let mime_type = infer::get(&buf).expect("Failed to get file type").mime_type();
|
||||
let mime_type = infer::get(&buf).expect("Failed to get image type").mime_type();
|
||||
|
||||
context.resource_manager.load_bytes::<Texture>(&uuid::Uuid::new_v4().to_string(), mime_type,
|
||||
buf, 0, buflen).unwrap()
|
||||
let tex_img = context.resource_manager.load_bytes::<Image>(&uuid::Uuid::new_v4().to_string(), mime_type,
|
||||
buf, 0, buflen).unwrap();
|
||||
|
||||
let samp = tex.sampler();
|
||||
let samp = TextureSampler {
|
||||
mag_filter: samp.mag_filter().map(FilterMode::from_mag_filter),
|
||||
min_filter: samp.min_filter().map(FilterMode::from_min_filter),
|
||||
mipmap_filter: samp.min_filter().and_then(FilterMode::mipmap_filter),
|
||||
wrap_u: samp.wrap_s().into(),
|
||||
wrap_v: samp.wrap_t().into(),
|
||||
wrap_w: WrappingMode::ClampToEdge,
|
||||
};
|
||||
|
||||
let handler = ResHandle::with_data("", Texture {
|
||||
image: tex_img,
|
||||
sampler: Some(samp),
|
||||
});
|
||||
context.resource_manager.store_uuid(handler.clone());
|
||||
handler
|
||||
}
|
||||
|
||||
/// Load the Material from a gltf::Material.
|
||||
|
@ -297,3 +317,54 @@ impl Material {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<gltf::texture::MagFilter> for FilterMode {
|
||||
fn from(value: gltf::texture::MagFilter) -> Self {
|
||||
match value {
|
||||
gltf::texture::MagFilter::Nearest => Self::Nearest,
|
||||
gltf::texture::MagFilter::Linear => Self::Linear,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterMode {
|
||||
/// Get the MinFilter mode and the mipmap filter mode from gltf MinFilter
|
||||
pub fn from_min_filter(minf: MinFilter) -> FilterMode {
|
||||
match minf {
|
||||
MinFilter::Nearest => FilterMode::Nearest,
|
||||
MinFilter::Linear => FilterMode::Linear,
|
||||
MinFilter::NearestMipmapNearest => FilterMode::Nearest,
|
||||
MinFilter::LinearMipmapNearest => FilterMode::Linear,
|
||||
MinFilter::NearestMipmapLinear => FilterMode::Nearest,
|
||||
MinFilter::LinearMipmapLinear => FilterMode::Linear,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_mag_filter(magf: MagFilter) -> FilterMode {
|
||||
match magf {
|
||||
MagFilter::Nearest => FilterMode::Nearest,
|
||||
MagFilter::Linear => FilterMode::Linear,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mipmap_filter(minf: MinFilter) -> Option<FilterMode> {
|
||||
match minf {
|
||||
MinFilter::Nearest => None,
|
||||
MinFilter::Linear => None,
|
||||
MinFilter::NearestMipmapNearest => Some(FilterMode::Nearest),
|
||||
MinFilter::LinearMipmapNearest => Some(FilterMode::Nearest),
|
||||
MinFilter::NearestMipmapLinear => Some(FilterMode::Linear),
|
||||
MinFilter::LinearMipmapLinear => Some(FilterMode::Linear),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<gltf::texture::WrappingMode> for WrappingMode {
|
||||
fn from(value: gltf::texture::WrappingMode) -> Self {
|
||||
match value {
|
||||
gltf::texture::WrappingMode::ClampToEdge => Self::ClampToEdge,
|
||||
gltf::texture::WrappingMode::MirroredRepeat => Self::MirroredRepeat,
|
||||
gltf::texture::WrappingMode::Repeat => Self::Repeat,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ use std::{fs::File, sync::Arc, io::Read};
|
|||
use image::ImageError;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::{resource_manager::ResourceStorage, texture::Texture, resource::ResHandle, ResourceManager};
|
||||
use crate::{resource::ResHandle, resource_manager::ResourceStorage, Image, ResourceManager};
|
||||
|
||||
use super::{LoaderError, ResourceLoader};
|
||||
|
||||
|
@ -13,7 +13,7 @@ impl From<ImageError> for LoaderError {
|
|||
}
|
||||
}
|
||||
|
||||
/// A struct that implements the `ResourceLoader` trait used for loading textures.
|
||||
/// A struct that implements the `ResourceLoader` trait used for loading images.
|
||||
#[derive(Default)]
|
||||
pub struct ImageLoader;
|
||||
|
||||
|
@ -60,10 +60,8 @@ impl ResourceLoader for ImageLoader {
|
|||
ImageError::IoError(e) => LoaderError::IoError(e),
|
||||
_ => LoaderError::DecodingError(e.into()),
|
||||
})?;
|
||||
let texture = Texture {
|
||||
image,
|
||||
};
|
||||
let res = ResHandle::with_data(path, texture);
|
||||
let image = Image::from(image);
|
||||
let res = ResHandle::with_data(path, image);
|
||||
|
||||
Ok(Arc::new(res))
|
||||
}
|
||||
|
@ -76,10 +74,8 @@ impl ResourceLoader for ImageLoader {
|
|||
ImageError::IoError(e) => LoaderError::IoError(e),
|
||||
_ => LoaderError::DecodingError(e.into()),
|
||||
})?;
|
||||
let texture = Texture {
|
||||
image,
|
||||
};
|
||||
let res = ResHandle::with_data(&uuid::Uuid::new_v4().to_string(), texture);
|
||||
let image = Image::from(image);
|
||||
let res = ResHandle::with_data(&uuid::Uuid::new_v4().to_string(), image);
|
||||
|
||||
debug!("Finished loading image of {} bytes", length);
|
||||
|
||||
|
|
|
@ -1,10 +1,73 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
//pub use gltf::texture::{MagFilter, MinFilter, WrappingMode};
|
||||
use image::DynamicImage;
|
||||
|
||||
use crate::ResHandle;
|
||||
|
||||
/// The filter mode of the sampler.
|
||||
///
|
||||
/// This is used for minification, magnification, and mipmap filters
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum FilterMode {
|
||||
Nearest,
|
||||
Linear,
|
||||
}
|
||||
|
||||
/// The wrapping mode of the Texture coordinates
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum WrappingMode {
|
||||
ClampToEdge,
|
||||
MirroredRepeat,
|
||||
Repeat,
|
||||
}
|
||||
|
||||
/// The descriptor of the sampler for a Texture.
|
||||
#[derive(Clone)]
|
||||
pub struct TextureSampler {
|
||||
pub mag_filter: Option<FilterMode>,
|
||||
pub min_filter: Option<FilterMode>,
|
||||
pub mipmap_filter: Option<FilterMode>,
|
||||
pub wrap_u: WrappingMode,
|
||||
pub wrap_v: WrappingMode,
|
||||
pub wrap_w: WrappingMode,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Image(DynamicImage);
|
||||
|
||||
impl Deref for Image {
|
||||
type Target = DynamicImage;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Image {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DynamicImage> for Image {
|
||||
fn from(value: DynamicImage) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Texture {
|
||||
pub image: DynamicImage,
|
||||
pub image: ResHandle<Image>,
|
||||
pub sampler: Option<TextureSampler>,
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
|
||||
/// Create a texture from an image.
|
||||
pub fn from_image(image: ResHandle<Image>) -> Self {
|
||||
Self {
|
||||
image,
|
||||
sampler: None,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue