diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index b82ee33c76f3e..2418299f4f861 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -7,14 +7,18 @@ use bevy_render::{ mesh::{Indices, Mesh, VertexAttribute}, pipeline::PrimitiveTopology, prelude::{Color, Texture}, - texture::TextureFormat, + texture::{AddressMode, FilterMode, SamplerDescriptor, TextureFormat}, }; use bevy_scene::Scene; use bevy_transform::{ hierarchy::{BuildWorldChildren, WorldChildBuilder}, prelude::{GlobalTransform, Transform}, }; -use gltf::{mesh::Mode, Primitive}; +use gltf::{ + mesh::Mode, + texture::{MagFilter, MinFilter, WrappingMode}, + Primitive, +}; use image::{GenericImageView, ImageFormat}; use std::path::Path; use thiserror::Error; @@ -24,6 +28,8 @@ use thiserror::Error; pub enum GltfError { #[error("Unsupported primitive mode.")] UnsupportedPrimitive { mode: Mode }, + #[error("Unsupported min filter.")] + UnsupportedMinFilter { filter: MinFilter }, #[error("Invalid GLTF file.")] Gltf(#[from] gltf::Error), #[error("Binary blob is missing.")] @@ -133,6 +139,7 @@ async fn load_gltf<'a, 'b>( data: image.clone().into_vec(), size: bevy_math::f32::vec2(size.0 as f32, size.1 as f32), format: TextureFormat::Rgba8Unorm, + sampler: texture_sampler(&texture)?, }), ); } @@ -263,6 +270,43 @@ fn texture_label(texture: &gltf::Texture) -> String { format!("Texture{}", texture.index()) } +fn texture_sampler(texture: &gltf::Texture) -> Result { + let gltf_sampler = texture.sampler(); + + Ok(SamplerDescriptor { + address_mode_u: texture_address_mode(&gltf_sampler.wrap_s()), + address_mode_v: texture_address_mode(&gltf_sampler.wrap_t()), + + mag_filter: gltf_sampler + .mag_filter() + .map(|mf| match mf { + MagFilter::Nearest => FilterMode::Nearest, + MagFilter::Linear => FilterMode::Linear, + }) + .unwrap_or(SamplerDescriptor::default().mag_filter), + + min_filter: gltf_sampler + .min_filter() + .map(|mf| match mf { + MinFilter::Nearest => Ok(FilterMode::Nearest), + MinFilter::Linear => Ok(FilterMode::Linear), + filter => Err(GltfError::UnsupportedMinFilter { filter }), + }) + .transpose()? + .unwrap_or(SamplerDescriptor::default().min_filter), + + ..Default::default() + }) +} + +fn texture_address_mode(gltf_address_mode: &gltf::texture::WrappingMode) -> AddressMode { + match gltf_address_mode { + WrappingMode::ClampToEdge => AddressMode::ClampToEdge, + WrappingMode::Repeat => AddressMode::Repeat, + WrappingMode::MirroredRepeat => AddressMode::MirrorRepeat, + } +} + fn get_primitive_topology(mode: Mode) -> Result { match mode { Mode::Points => Ok(PrimitiveTopology::PointList), diff --git a/crates/bevy_render/src/texture/sampler_descriptor.rs b/crates/bevy_render/src/texture/sampler_descriptor.rs index 7ef881bee1ff9..50637937d26fa 100644 --- a/crates/bevy_render/src/texture/sampler_descriptor.rs +++ b/crates/bevy_render/src/texture/sampler_descriptor.rs @@ -1,9 +1,8 @@ -use super::Texture; use crate::pipeline::CompareFunction; use std::num::NonZeroU8; /// Describes a sampler -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SamplerDescriptor { pub address_mode_u: AddressMode, pub address_mode_v: AddressMode, @@ -34,23 +33,6 @@ impl Default for SamplerDescriptor { } } -impl From<&Texture> for SamplerDescriptor { - fn from(_texture: &Texture) -> Self { - SamplerDescriptor { - address_mode_u: AddressMode::ClampToEdge, - address_mode_v: AddressMode::ClampToEdge, - address_mode_w: AddressMode::ClampToEdge, - mag_filter: FilterMode::Nearest, - min_filter: FilterMode::Linear, - mipmap_filter: FilterMode::Nearest, - lod_min_clamp: 0.0, - lod_max_clamp: std::f32::MAX, - compare_function: None, - anisotropy_clamp: None, - } - } -} - /// How edges should be handled in texture addressing. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub enum AddressMode { diff --git a/crates/bevy_render/src/texture/texture.rs b/crates/bevy_render/src/texture/texture.rs index 23a6ffc1ebe73..375e5ef2c6882 100644 --- a/crates/bevy_render/src/texture/texture.rs +++ b/crates/bevy_render/src/texture/texture.rs @@ -18,6 +18,7 @@ pub struct Texture { pub data: Vec, pub size: Vec2, pub format: TextureFormat, + pub sampler: SamplerDescriptor, } impl Default for Texture { @@ -26,6 +27,7 @@ impl Default for Texture { data: Default::default(), size: Default::default(), format: TextureFormat::Rgba8UnormSrgb, + sampler: Default::default(), } } } @@ -37,7 +39,12 @@ impl Texture { data.len(), "Pixel data, size and format have to match", ); - Self { data, size, format } + Self { + data, + size, + format, + ..Default::default() + } } pub fn new_fill(size: Vec2, pixel: &[u8], format: TextureFormat) -> Self { @@ -104,8 +111,7 @@ impl Texture { let texture_descriptor: TextureDescriptor = texture.into(); let texture_resource = render_resource_context.create_texture(texture_descriptor); - let sampler_descriptor: SamplerDescriptor = texture.into(); - let sampler_resource = render_resource_context.create_sampler(&sampler_descriptor); + let sampler_resource = render_resource_context.create_sampler(&texture.sampler); render_resource_context.set_asset_resource( texture_handle,