From 6ae0fd8c169f09bcd329a067f828683eeef5a332 Mon Sep 17 00:00:00 2001 From: Greeble <166992735+greeble-dev@users.noreply.github.com> Date: Tue, 6 May 2025 10:10:51 +0100 Subject: [PATCH 01/11] Added checkboard model and texture. --- assets/models/checkerboard/checkerboard.bin | Bin 0 -> 140 bytes assets/models/checkerboard/checkerboard.gltf | 143 +++++++++++++++++++ assets/models/checkerboard/checkerboard.ktx2 | Bin 0 -> 727 bytes 3 files changed, 143 insertions(+) create mode 100644 assets/models/checkerboard/checkerboard.bin create mode 100644 assets/models/checkerboard/checkerboard.gltf create mode 100644 assets/models/checkerboard/checkerboard.ktx2 diff --git a/assets/models/checkerboard/checkerboard.bin b/assets/models/checkerboard/checkerboard.bin new file mode 100644 index 0000000000000000000000000000000000000000..9bc116e4c07d5af01b97d600e73f7c7ead97d649 GIT binary patch literal 140 zcmZQzXxPsH1`YNM3?K{wU^Yw~NW;ZpVo-H3wO~z9eduh3gA5D?jtmS6Kn$jVd;uT^ Q@j)~r12a$yGXoO?0OT$Z1^@s6 literal 0 HcmV?d00001 diff --git a/assets/models/checkerboard/checkerboard.gltf b/assets/models/checkerboard/checkerboard.gltf new file mode 100644 index 0000000000000..632ff35372d12 --- /dev/null +++ b/assets/models/checkerboard/checkerboard.gltf @@ -0,0 +1,143 @@ +{ + "asset":{ + "generator":"Khronos glTF Blender I/O v4.3.47", + "version":"2.0" + }, + "extensionsUsed":[ + "KHR_materials_unlit" + ], + "scene":0, + "scenes":[ + { + "name":"Scene", + "nodes":[ + 0 + ] + } + ], + "nodes":[ + { + "mesh":0, + "name":"Plane" + } + ], + "materials":[ + { + "doubleSided":true, + "extensions":{ + "KHR_materials_unlit":{} + }, + "name":"Material.001", + "pbrMetallicRoughness":{ + "baseColorTexture":{ + "index":0 + }, + "metallicFactor":0, + "roughnessFactor":0.9 + } + } + ], + "meshes":[ + { + "name":"Plane", + "primitives":[ + { + "attributes":{ + "POSITION":0, + "NORMAL":1, + "TEXCOORD_0":2 + }, + "indices":3, + "material":0 + } + ] + } + ], + "textures":[ + { + "sampler":0, + "source":0 + } + ], + "images":[ + { + "mimeType":"image/png", + "name":"checkerboard.ktx2", + "uri":"checkerboard.ktx2" + } + ], + "accessors":[ + { + "bufferView":0, + "componentType":5126, + "count":4, + "max":[ + 1, + 0, + 1 + ], + "min":[ + -1, + 0, + -1 + ], + "type":"VEC3" + }, + { + "bufferView":1, + "componentType":5126, + "count":4, + "type":"VEC3" + }, + { + "bufferView":2, + "componentType":5126, + "count":4, + "type":"VEC2" + }, + { + "bufferView":3, + "componentType":5123, + "count":6, + "type":"SCALAR" + } + ], + "bufferViews":[ + { + "buffer":0, + "byteLength":48, + "byteOffset":0, + "target":34962 + }, + { + "buffer":0, + "byteLength":48, + "byteOffset":48, + "target":34962 + }, + { + "buffer":0, + "byteLength":32, + "byteOffset":96, + "target":34962 + }, + { + "buffer":0, + "byteLength":12, + "byteOffset":128, + "target":34963 + } + ], + "samplers":[ + { + "magFilter":9729, + "minFilter":9987 + } + ], + "buffers":[ + { + "byteLength":140, + "uri":"checkerboard.bin" + } + ] +} diff --git a/assets/models/checkerboard/checkerboard.ktx2 b/assets/models/checkerboard/checkerboard.ktx2 new file mode 100644 index 0000000000000000000000000000000000000000..fa758298183cac8fe42d7eea175d602ec5db4efc GIT binary patch literal 727 zcmZ4O9TK5nWU!l;ONvXJfq{V$h`|Jy0pdWooIsihh&6!XK0vwzNQVGvbg&Af2nci` z6p&;Fvznpe>M-#G5JoaoTmdF-0AaX7#pPh)JP?LDx;Vsm241MR6jc2IDE$)Z4;3gM zYCOXgsJJLp9BMqn38*-X4>ca_XOL1R1`h^CMyMjFUIqqsIO{)<#lgT1R{-J*Ft9^i z$G`yMgWLcN_VS|4lGGxG?2-zF ze*asD+3XDp_O{cdeze(bvz}A8=ipZ12_G0t` Date: Tue, 6 May 2025 10:11:09 +0100 Subject: [PATCH 02/11] Added duplicates of the checkboard model to work around #18267. --- assets/models/checkerboard/checkerboard0.gltf | 143 ++++++++++++++++++ assets/models/checkerboard/checkerboard0.ktx2 | Bin 0 -> 727 bytes assets/models/checkerboard/checkerboard1.gltf | 143 ++++++++++++++++++ assets/models/checkerboard/checkerboard1.ktx2 | Bin 0 -> 727 bytes assets/models/checkerboard/checkerboard2.gltf | 143 ++++++++++++++++++ assets/models/checkerboard/checkerboard2.ktx2 | Bin 0 -> 727 bytes assets/models/checkerboard/checkerboard3.gltf | 143 ++++++++++++++++++ assets/models/checkerboard/checkerboard3.ktx2 | Bin 0 -> 727 bytes 8 files changed, 572 insertions(+) create mode 100644 assets/models/checkerboard/checkerboard0.gltf create mode 100644 assets/models/checkerboard/checkerboard0.ktx2 create mode 100644 assets/models/checkerboard/checkerboard1.gltf create mode 100644 assets/models/checkerboard/checkerboard1.ktx2 create mode 100644 assets/models/checkerboard/checkerboard2.gltf create mode 100644 assets/models/checkerboard/checkerboard2.ktx2 create mode 100644 assets/models/checkerboard/checkerboard3.gltf create mode 100644 assets/models/checkerboard/checkerboard3.ktx2 diff --git a/assets/models/checkerboard/checkerboard0.gltf b/assets/models/checkerboard/checkerboard0.gltf new file mode 100644 index 0000000000000..505481c16ba40 --- /dev/null +++ b/assets/models/checkerboard/checkerboard0.gltf @@ -0,0 +1,143 @@ +{ + "asset":{ + "generator":"Khronos glTF Blender I/O v4.3.47", + "version":"2.0" + }, + "extensionsUsed":[ + "KHR_materials_unlit" + ], + "scene":0, + "scenes":[ + { + "name":"Scene", + "nodes":[ + 0 + ] + } + ], + "nodes":[ + { + "mesh":0, + "name":"Plane" + } + ], + "materials":[ + { + "doubleSided":true, + "extensions":{ + "KHR_materials_unlit":{} + }, + "name":"Material.001", + "pbrMetallicRoughness":{ + "baseColorTexture":{ + "index":0 + }, + "metallicFactor":0, + "roughnessFactor":0.9 + } + } + ], + "meshes":[ + { + "name":"Plane", + "primitives":[ + { + "attributes":{ + "POSITION":0, + "NORMAL":1, + "TEXCOORD_0":2 + }, + "indices":3, + "material":0 + } + ] + } + ], + "textures":[ + { + "sampler":0, + "source":0 + } + ], + "images":[ + { + "mimeType":"image/png", + "name":"checkerboard0.ktx2", + "uri":"checkerboard0.ktx2" + } + ], + "accessors":[ + { + "bufferView":0, + "componentType":5126, + "count":4, + "max":[ + 1, + 0, + 1 + ], + "min":[ + -1, + 0, + -1 + ], + "type":"VEC3" + }, + { + "bufferView":1, + "componentType":5126, + "count":4, + "type":"VEC3" + }, + { + "bufferView":2, + "componentType":5126, + "count":4, + "type":"VEC2" + }, + { + "bufferView":3, + "componentType":5123, + "count":6, + "type":"SCALAR" + } + ], + "bufferViews":[ + { + "buffer":0, + "byteLength":48, + "byteOffset":0, + "target":34962 + }, + { + "buffer":0, + "byteLength":48, + "byteOffset":48, + "target":34962 + }, + { + "buffer":0, + "byteLength":32, + "byteOffset":96, + "target":34962 + }, + { + "buffer":0, + "byteLength":12, + "byteOffset":128, + "target":34963 + } + ], + "samplers":[ + { + "magFilter":9729, + "minFilter":9987 + } + ], + "buffers":[ + { + "byteLength":140, + "uri":"checkerboard.bin" + } + ] +} diff --git a/assets/models/checkerboard/checkerboard0.ktx2 b/assets/models/checkerboard/checkerboard0.ktx2 new file mode 100644 index 0000000000000000000000000000000000000000..fa758298183cac8fe42d7eea175d602ec5db4efc GIT binary patch literal 727 zcmZ4O9TK5nWU!l;ONvXJfq{V$h`|Jy0pdWooIsihh&6!XK0vwzNQVGvbg&Af2nci` z6p&;Fvznpe>M-#G5JoaoTmdF-0AaX7#pPh)JP?LDx;Vsm241MR6jc2IDE$)Z4;3gM zYCOXgsJJLp9BMqn38*-X4>ca_XOL1R1`h^CMyMjFUIqqsIO{)<#lgT1R{-J*Ft9^i z$G`yMgWLcN_VS|4lGGxG?2-zF ze*asD+3XDp_O{cdeze(bvz}A8=ipZ12_G0t`M-#G5JoaoTmdF-0AaX7#pPh)JP?LDx;Vsm241MR6jc2IDE$)Z4;3gM zYCOXgsJJLp9BMqn38*-X4>ca_XOL1R1`h^CMyMjFUIqqsIO{)<#lgT1R{-J*Ft9^i z$G`yMgWLcN_VS|4lGGxG?2-zF ze*asD+3XDp_O{cdeze(bvz}A8=ipZ12_G0t`M-#G5JoaoTmdF-0AaX7#pPh)JP?LDx;Vsm241MR6jc2IDE$)Z4;3gM zYCOXgsJJLp9BMqn38*-X4>ca_XOL1R1`h^CMyMjFUIqqsIO{)<#lgT1R{-J*Ft9^i z$G`yMgWLcN_VS|4lGGxG?2-zF ze*asD+3XDp_O{cdeze(bvz}A8=ipZ12_G0t`M-#G5JoaoTmdF-0AaX7#pPh)JP?LDx;Vsm241MR6jc2IDE$)Z4;3gM zYCOXgsJJLp9BMqn38*-X4>ca_XOL1R1`h^CMyMjFUIqqsIO{)<#lgT1R{-J*Ft9^i z$G`yMgWLcN_VS|4lGGxG?2-zF ze*asD+3XDp_O{cdeze(bvz}A8=ipZ12_G0t` Date: Tue, 6 May 2025 10:12:33 +0100 Subject: [PATCH 03/11] Added test. --- Cargo.toml | 8 ++ tests/gltf/gltf_override_sampler.rs | 173 ++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 tests/gltf/gltf_override_sampler.rs diff --git a/Cargo.toml b/Cargo.toml index a3d3a2ab63e51..6b48e49ff61db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1410,6 +1410,14 @@ doc-scrape-examples = true [package.metadata.example.no_prepass] hidden = true +[[example]] +name = "gltf_override_sampler" +path = "tests/gltf/gltf_override_sampler.rs" +doc-scrape-examples = true + +[package.metadata.example.gltf_override_sampler] +hidden = true + # Animation [[example]] name = "animation_events" diff --git a/tests/gltf/gltf_override_sampler.rs b/tests/gltf/gltf_override_sampler.rs new file mode 100644 index 0000000000000..ef1684091baa6 --- /dev/null +++ b/tests/gltf/gltf_override_sampler.rs @@ -0,0 +1,173 @@ +//! Tests loading the same glTF multiple times but with different values for +//! `GltfLoaderSettings::override_sampler` and `default_sampler`. + +use bevy::{gltf::GltfLoaderSettings, prelude::*}; +use bevy_image::{ImageAddressMode, ImageFilterMode, ImageSamplerDescriptor}; + +fn main() { + App::new() + .insert_resource(VisibleCombo(KeyCode::Digit1)) + .add_plugins(DefaultPlugins) + .add_systems(Startup, setup) + .add_systems(Update, (update_controls, update_camera)) + .run(); +} + +#[derive(Component, Clone)] +struct Combo { + key: KeyCode, + label: &'static str, + sampler: ImageSamplerDescriptor, +} + +fn setup(mut commands: Commands, asset_server: Res) { + let default_sampler = ImageSamplerDescriptor { + address_mode_u: ImageAddressMode::Repeat, + address_mode_v: ImageAddressMode::Repeat, + mag_filter: ImageFilterMode::Linear, + min_filter: ImageFilterMode::Linear, + mipmap_filter: ImageFilterMode::Nearest, + ..Default::default() + }; + + // Declare combinations of sampler settings linked to a key code. + + let combos: &[Combo] = &[ + Combo { + key: KeyCode::Digit1, + label: "1: None", + sampler: ImageSamplerDescriptor { + lod_max_clamp: 0.0, + ..default_sampler.clone() + }, + }, + Combo { + key: KeyCode::Digit2, + label: "2: Nearest", + sampler: default_sampler.clone(), + }, + Combo { + key: KeyCode::Digit3, + label: "3: Linear", + sampler: ImageSamplerDescriptor { + mipmap_filter: ImageFilterMode::Linear, + ..default_sampler.clone() + }, + }, + Combo { + key: KeyCode::Digit4, + label: "4: Linear, Anisotropic", + sampler: ImageSamplerDescriptor { + mipmap_filter: ImageFilterMode::Linear, + anisotropy_clamp: 16, + ..default_sampler.clone() + }, + }, + ]; + + // Spawn each combination. + + for (index, combo) in combos.iter().enumerate() { + let asset = GltfAssetLabel::Scene(0) + .from_asset(format!("models/checkerboard/checkerboard{index}.gltf")); + + let sampler = combo.sampler.clone(); + + let settings = move |settings: &mut GltfLoaderSettings| { + settings.default_sampler = Some(sampler.clone()); + settings.override_sampler = true; + }; + + commands.spawn(( + SceneRoot(asset_server.load_with_settings(asset, settings)), + combo.clone(), + )); + } + + // Spawn camera and text. + + commands.spawn(( + Camera3d::default(), + Projection::from(PerspectiveProjection { + near: 0.001, + ..Default::default() + }), + )); + + commands.spawn(( + Text::default(), + Node { + position_type: PositionType::Absolute, + top: Val::Px(12.0), + left: Val::Px(12.0), + ..Default::default() + }, + )); +} + +#[derive(Resource, PartialEq)] +struct VisibleCombo(KeyCode); + +fn update_controls( + mut text: Single<&mut Text>, + keyboard_input: Res>, + mut time: ResMut>, + mut combos: Query<(&Combo, &mut Visibility)>, + mut visible_combo: ResMut, +) { + // Update combo visibility. + + for (combo, _) in &combos { + if keyboard_input.just_pressed(combo.key) { + *visible_combo = VisibleCombo(combo.key); + } + } + + for (combo, mut visibility) in &mut combos { + *visibility = if *visible_combo == VisibleCombo(combo.key) { + Visibility::Visible + } else { + Visibility::Hidden + }; + } + + // Update pause. + + if keyboard_input.just_pressed(KeyCode::Space) { + if time.is_paused() { + time.unpause(); + } else { + time.pause(); + } + } + + // Update help text. + + text.clear(); + + text.push_str(&format!( + "Space: {}\n\n", + if time.is_paused() { "Unpause" } else { "Pause" } + )); + + text.push_str("Mipmap filter:\n"); + + for (combo, _) in &combos { + let visible = *visible_combo == VisibleCombo(combo.key); + + text.push_str(&format!( + "{}{}\n", + if visible { "> " } else { " " }, + combo.label, + )); + } +} + +fn update_camera(time: Res