mirror of
https://github.com/bevyengine/bevy.git
synced 2026-05-06 06:06:42 -04:00
535cf401cc
Part 2 of #23619 In **Bevy 0.19** we are landing a subset of Bevy's Next Generation Scene system (often known as BSN), which now lives in the `bevy_scene` / `bevy::scene` crate. However the old `bevy_scene` system still needs to stick around for a bit longer, as it provides some features that Bevy's Next Generation Scene system doesn't (yet!): 1. It is not _yet_ possible to write a World _to_ BSN, so the old system is still necessary for "round trip World serialization". 2. The GLTF scene loader has not yet been ported to BSN, so the old system is still necessary to spawn GLTF scenes in Bevy. For this reason, we have renamed the old `bevy_scene` crate to `bevy_world_serialization`. If you were referencing `bevy_scene::*` or `bevy::scene::*` types, rename those paths to `bevy_world_serialization::*` and `bevy::world_serialization::*` respectively. Additionally, to avoid confusion / conflicts with the new scene system, all "scene" terminology / types have been reframed as "world serialization": - `Scene` -> `WorldAsset` (as this was always just a World wrapper) - `SceneRoot` -> `WorldAssetRoot` - `DynamicScene` -> `DynamicWorld` - `DynamicScene::from_scene` -> `DynamicWorld::from_world_asset` - `DynamicSceneBuilder` -> `DynamicWorldBuilder` - `DynamicSceneRoot` -> `DynamicWorldRoot` - `SceneInstanceReady` -> `WorldInstanceReady` - `SceneLoader` -> `WorldAssetLoader` - `ScenePlugin` -> `WorldSerializationPlugin` - `SceneRootTemplate` -> `WorldAssetRootTemplate` - `SceneSpawner` -> `WorldInstanceSpawner` - `SceneFilter` -> `WorldFilter` - `SceneLoaderError` -> `WorldAssetLoaderError` - `SceneSpawnError` -> `WorldInstanceSpawnError` Note that I went with `bevy_world_serialization` over `bevy_ecs_serialization`, as that is what all of the internal features described themselves as. I think it is both more specific and does a better job of making itself decoupled from `bevy_ecs` proper.
533 lines
17 KiB
Rust
533 lines
17 KiB
Rust
//! Compares different anti-aliasing techniques supported by Bevy.
|
|
|
|
use std::{f32::consts::PI, fmt::Write};
|
|
|
|
use bevy::{
|
|
anti_alias::{
|
|
contrast_adaptive_sharpening::ContrastAdaptiveSharpening,
|
|
fxaa::{Fxaa, Sensitivity},
|
|
smaa::{Smaa, SmaaPreset},
|
|
taa::TemporalAntiAliasing,
|
|
},
|
|
asset::RenderAssetUsages,
|
|
camera::Hdr,
|
|
core_pipeline::prepass::{DepthPrepass, MotionVectorPrepass},
|
|
image::{ImageSampler, ImageSamplerDescriptor},
|
|
light::CascadeShadowConfigBuilder,
|
|
prelude::*,
|
|
render::{
|
|
camera::{MipBias, TemporalJitter},
|
|
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
|
},
|
|
};
|
|
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
use bevy::anti_alias::dlss::{
|
|
Dlss, DlssPerfQualityMode, DlssProjectId, DlssSuperResolutionSupported,
|
|
};
|
|
|
|
fn main() {
|
|
let mut app = App::new();
|
|
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
app.insert_resource(DlssProjectId(bevy_asset::uuid::uuid!(
|
|
"5417916c-0291-4e3f-8f65-326c1858ab96" // Don't copy paste this - generate your own UUID!
|
|
)));
|
|
|
|
app.add_plugins(DefaultPlugins)
|
|
.add_systems(Startup, setup)
|
|
.add_systems(
|
|
Update,
|
|
(modify_aa, modify_sharpening, modify_projection, update_ui),
|
|
);
|
|
|
|
app.run();
|
|
}
|
|
|
|
type TaaComponents = (
|
|
TemporalAntiAliasing,
|
|
TemporalJitter,
|
|
MipBias,
|
|
DepthPrepass,
|
|
MotionVectorPrepass,
|
|
);
|
|
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
type DlssComponents = (
|
|
Dlss,
|
|
TemporalJitter,
|
|
MipBias,
|
|
DepthPrepass,
|
|
MotionVectorPrepass,
|
|
);
|
|
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
|
|
type DlssComponents = ();
|
|
|
|
fn modify_aa(
|
|
keys: Res<ButtonInput<KeyCode>>,
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] camera: Single<
|
|
(
|
|
Entity,
|
|
Option<&mut Fxaa>,
|
|
Option<&mut Smaa>,
|
|
Option<&TemporalAntiAliasing>,
|
|
&mut Msaa,
|
|
Option<&mut Dlss>,
|
|
),
|
|
With<Camera>,
|
|
>,
|
|
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))] camera: Single<
|
|
(
|
|
Entity,
|
|
Option<&mut Fxaa>,
|
|
Option<&mut Smaa>,
|
|
Option<&TemporalAntiAliasing>,
|
|
&mut Msaa,
|
|
),
|
|
With<Camera>,
|
|
>,
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] dlss_supported: Option<
|
|
Res<DlssSuperResolutionSupported>,
|
|
>,
|
|
mut commands: Commands,
|
|
) {
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
let (camera_entity, fxaa, smaa, taa, mut msaa, dlss) = camera.into_inner();
|
|
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
|
|
let (camera_entity, fxaa, smaa, taa, mut msaa) = camera.into_inner();
|
|
let mut camera = commands.entity(camera_entity);
|
|
|
|
// No AA
|
|
if keys.just_pressed(KeyCode::Digit1) {
|
|
*msaa = Msaa::Off;
|
|
camera
|
|
.remove::<Fxaa>()
|
|
.remove::<Smaa>()
|
|
.remove::<TaaComponents>()
|
|
.remove::<DlssComponents>();
|
|
}
|
|
|
|
// MSAA
|
|
if keys.just_pressed(KeyCode::Digit2) && *msaa == Msaa::Off {
|
|
camera
|
|
.remove::<Fxaa>()
|
|
.remove::<Smaa>()
|
|
.remove::<TaaComponents>()
|
|
.remove::<DlssComponents>();
|
|
|
|
*msaa = Msaa::Sample4;
|
|
}
|
|
|
|
// MSAA Sample Count
|
|
if *msaa != Msaa::Off {
|
|
if keys.just_pressed(KeyCode::KeyQ) {
|
|
*msaa = Msaa::Sample2;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyW) {
|
|
*msaa = Msaa::Sample4;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyE) {
|
|
*msaa = Msaa::Sample8;
|
|
}
|
|
}
|
|
|
|
// FXAA
|
|
if keys.just_pressed(KeyCode::Digit3) && fxaa.is_none() {
|
|
*msaa = Msaa::Off;
|
|
camera
|
|
.remove::<Smaa>()
|
|
.remove::<TaaComponents>()
|
|
.remove::<DlssComponents>()
|
|
.insert(Fxaa::default());
|
|
}
|
|
|
|
// FXAA Settings
|
|
if let Some(mut fxaa) = fxaa {
|
|
if keys.just_pressed(KeyCode::KeyQ) {
|
|
fxaa.edge_threshold = Sensitivity::Low;
|
|
fxaa.edge_threshold_min = Sensitivity::Low;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyW) {
|
|
fxaa.edge_threshold = Sensitivity::Medium;
|
|
fxaa.edge_threshold_min = Sensitivity::Medium;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyE) {
|
|
fxaa.edge_threshold = Sensitivity::High;
|
|
fxaa.edge_threshold_min = Sensitivity::High;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyR) {
|
|
fxaa.edge_threshold = Sensitivity::Ultra;
|
|
fxaa.edge_threshold_min = Sensitivity::Ultra;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyT) {
|
|
fxaa.edge_threshold = Sensitivity::Extreme;
|
|
fxaa.edge_threshold_min = Sensitivity::Extreme;
|
|
}
|
|
}
|
|
|
|
// SMAA
|
|
if keys.just_pressed(KeyCode::Digit4) && smaa.is_none() {
|
|
*msaa = Msaa::Off;
|
|
camera
|
|
.remove::<Fxaa>()
|
|
.remove::<TaaComponents>()
|
|
.remove::<DlssComponents>()
|
|
.insert(Smaa::default());
|
|
}
|
|
|
|
// SMAA Settings
|
|
if let Some(mut smaa) = smaa {
|
|
if keys.just_pressed(KeyCode::KeyQ) {
|
|
smaa.preset = SmaaPreset::Low;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyW) {
|
|
smaa.preset = SmaaPreset::Medium;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyE) {
|
|
smaa.preset = SmaaPreset::High;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyR) {
|
|
smaa.preset = SmaaPreset::Ultra;
|
|
}
|
|
}
|
|
|
|
// TAA
|
|
if keys.just_pressed(KeyCode::Digit5) && taa.is_none() {
|
|
*msaa = Msaa::Off;
|
|
camera
|
|
.remove::<Fxaa>()
|
|
.remove::<Smaa>()
|
|
.remove::<DlssComponents>()
|
|
.insert(TemporalAntiAliasing::default());
|
|
}
|
|
|
|
// DLSS
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
if keys.just_pressed(KeyCode::Digit6) && dlss.is_none() && dlss_supported.is_some() {
|
|
*msaa = Msaa::Off;
|
|
camera
|
|
.remove::<Fxaa>()
|
|
.remove::<Smaa>()
|
|
.remove::<TaaComponents>()
|
|
.insert(Dlss::default());
|
|
}
|
|
|
|
// DLSS Settings
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
if let Some(mut dlss) = dlss {
|
|
if keys.just_pressed(KeyCode::KeyZ) {
|
|
dlss.perf_quality_mode = DlssPerfQualityMode::Auto;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyX) {
|
|
dlss.perf_quality_mode = DlssPerfQualityMode::UltraPerformance;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyC) {
|
|
dlss.perf_quality_mode = DlssPerfQualityMode::Performance;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyV) {
|
|
dlss.perf_quality_mode = DlssPerfQualityMode::Balanced;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyB) {
|
|
dlss.perf_quality_mode = DlssPerfQualityMode::Quality;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyN) {
|
|
dlss.perf_quality_mode = DlssPerfQualityMode::Dlaa;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn modify_sharpening(
|
|
keys: Res<ButtonInput<KeyCode>>,
|
|
mut query: Query<&mut ContrastAdaptiveSharpening>,
|
|
) {
|
|
for mut cas in &mut query {
|
|
if keys.just_pressed(KeyCode::Digit0) {
|
|
cas.enabled = !cas.enabled;
|
|
}
|
|
if cas.enabled {
|
|
if keys.just_pressed(KeyCode::Minus) {
|
|
cas.sharpening_strength -= 0.1;
|
|
cas.sharpening_strength = cas.sharpening_strength.clamp(0.0, 1.0);
|
|
}
|
|
if keys.just_pressed(KeyCode::Equal) {
|
|
cas.sharpening_strength += 0.1;
|
|
cas.sharpening_strength = cas.sharpening_strength.clamp(0.0, 1.0);
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyD) {
|
|
cas.denoise = !cas.denoise;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn modify_projection(keys: Res<ButtonInput<KeyCode>>, mut query: Query<&mut Projection>) {
|
|
for mut projection in &mut query {
|
|
if keys.just_pressed(KeyCode::KeyO) {
|
|
match *projection {
|
|
Projection::Perspective(_) => {
|
|
*projection = Projection::Orthographic(OrthographicProjection {
|
|
scale: 0.002,
|
|
..OrthographicProjection::default_3d()
|
|
});
|
|
}
|
|
_ => {
|
|
*projection = Projection::Perspective(PerspectiveProjection::default());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn update_ui(
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] camera: Single<
|
|
(
|
|
&Projection,
|
|
Option<&Fxaa>,
|
|
Option<&Smaa>,
|
|
Option<&TemporalAntiAliasing>,
|
|
&ContrastAdaptiveSharpening,
|
|
&Msaa,
|
|
Option<&Dlss>,
|
|
),
|
|
With<Camera>,
|
|
>,
|
|
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))] camera: Single<
|
|
(
|
|
&Projection,
|
|
Option<&Fxaa>,
|
|
Option<&Smaa>,
|
|
Option<&TemporalAntiAliasing>,
|
|
&ContrastAdaptiveSharpening,
|
|
&Msaa,
|
|
),
|
|
With<Camera>,
|
|
>,
|
|
mut ui: Single<&mut Text>,
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] dlss_supported: Option<
|
|
Res<DlssSuperResolutionSupported>,
|
|
>,
|
|
) {
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
let (projection, fxaa, smaa, taa, cas, msaa, dlss) = *camera;
|
|
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
|
|
let (projection, fxaa, smaa, taa, cas, msaa) = *camera;
|
|
|
|
let ui = &mut ui.0;
|
|
*ui = "Antialias Method\n".to_string();
|
|
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
let dlss_none = dlss.is_none();
|
|
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
|
|
let dlss_none = true;
|
|
|
|
draw_selectable_menu_item(
|
|
ui,
|
|
"No AA",
|
|
'1',
|
|
*msaa == Msaa::Off && fxaa.is_none() && taa.is_none() && smaa.is_none() && dlss_none,
|
|
);
|
|
draw_selectable_menu_item(ui, "MSAA", '2', *msaa != Msaa::Off);
|
|
draw_selectable_menu_item(ui, "FXAA", '3', fxaa.is_some());
|
|
draw_selectable_menu_item(ui, "SMAA", '4', smaa.is_some());
|
|
draw_selectable_menu_item(ui, "TAA", '5', taa.is_some());
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
if dlss_supported.is_some() {
|
|
draw_selectable_menu_item(ui, "DLSS", '6', dlss.is_some());
|
|
}
|
|
|
|
if *msaa != Msaa::Off {
|
|
ui.push_str("\n----------\n\nSample Count\n");
|
|
draw_selectable_menu_item(ui, "2", 'Q', *msaa == Msaa::Sample2);
|
|
draw_selectable_menu_item(ui, "4", 'W', *msaa == Msaa::Sample4);
|
|
draw_selectable_menu_item(ui, "8", 'E', *msaa == Msaa::Sample8);
|
|
}
|
|
|
|
if let Some(fxaa) = fxaa {
|
|
ui.push_str("\n----------\n\nSensitivity\n");
|
|
draw_selectable_menu_item(ui, "Low", 'Q', fxaa.edge_threshold == Sensitivity::Low);
|
|
draw_selectable_menu_item(
|
|
ui,
|
|
"Medium",
|
|
'W',
|
|
fxaa.edge_threshold == Sensitivity::Medium,
|
|
);
|
|
draw_selectable_menu_item(ui, "High", 'E', fxaa.edge_threshold == Sensitivity::High);
|
|
draw_selectable_menu_item(ui, "Ultra", 'R', fxaa.edge_threshold == Sensitivity::Ultra);
|
|
draw_selectable_menu_item(
|
|
ui,
|
|
"Extreme",
|
|
'T',
|
|
fxaa.edge_threshold == Sensitivity::Extreme,
|
|
);
|
|
}
|
|
|
|
if let Some(smaa) = smaa {
|
|
ui.push_str("\n----------\n\nQuality\n");
|
|
draw_selectable_menu_item(ui, "Low", 'Q', smaa.preset == SmaaPreset::Low);
|
|
draw_selectable_menu_item(ui, "Medium", 'W', smaa.preset == SmaaPreset::Medium);
|
|
draw_selectable_menu_item(ui, "High", 'E', smaa.preset == SmaaPreset::High);
|
|
draw_selectable_menu_item(ui, "Ultra", 'R', smaa.preset == SmaaPreset::Ultra);
|
|
}
|
|
|
|
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
|
|
if let Some(dlss) = dlss {
|
|
let pqm = dlss.perf_quality_mode;
|
|
ui.push_str("\n----------\n\nQuality\n");
|
|
draw_selectable_menu_item(ui, "Auto", 'Z', pqm == DlssPerfQualityMode::Auto);
|
|
draw_selectable_menu_item(
|
|
ui,
|
|
"UltraPerformance",
|
|
'X',
|
|
pqm == DlssPerfQualityMode::UltraPerformance,
|
|
);
|
|
draw_selectable_menu_item(
|
|
ui,
|
|
"Performance",
|
|
'C',
|
|
pqm == DlssPerfQualityMode::Performance,
|
|
);
|
|
draw_selectable_menu_item(ui, "Balanced", 'V', pqm == DlssPerfQualityMode::Balanced);
|
|
draw_selectable_menu_item(ui, "Quality", 'B', pqm == DlssPerfQualityMode::Quality);
|
|
draw_selectable_menu_item(ui, "DLAA", 'N', pqm == DlssPerfQualityMode::Dlaa);
|
|
}
|
|
|
|
ui.push_str("\n----------\n\n");
|
|
draw_selectable_menu_item(ui, "Sharpening", '0', cas.enabled);
|
|
|
|
if cas.enabled {
|
|
ui.push_str(&format!("(-/+) Strength: {:.1}\n", cas.sharpening_strength));
|
|
draw_selectable_menu_item(ui, "Denoising", 'D', cas.denoise);
|
|
}
|
|
|
|
ui.push_str("\n----------\n\n");
|
|
draw_selectable_menu_item(
|
|
ui,
|
|
"Orthographic",
|
|
'O',
|
|
matches!(projection, Projection::Orthographic(_)),
|
|
);
|
|
}
|
|
|
|
/// Set up a simple 3D scene
|
|
fn setup(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
mut images: ResMut<Assets<Image>>,
|
|
asset_server: Res<AssetServer>,
|
|
) {
|
|
// Plane
|
|
commands.spawn((
|
|
Mesh3d(meshes.add(Plane3d::default().mesh().size(20.0, 20.0))),
|
|
MeshMaterial3d(materials.add(Color::srgb(0.1, 0.2, 0.1))),
|
|
));
|
|
|
|
let cube_material = materials.add(StandardMaterial {
|
|
base_color_texture: Some(images.add(uv_debug_texture())),
|
|
..default()
|
|
});
|
|
|
|
// Cubes
|
|
for i in 0..5 {
|
|
commands.spawn((
|
|
Mesh3d(meshes.add(Cuboid::new(0.25, 0.25, 0.25))),
|
|
MeshMaterial3d(cube_material.clone()),
|
|
Transform::from_xyz(i as f32 * 0.25 - 1.0, 0.125, -i as f32 * 0.5),
|
|
));
|
|
}
|
|
|
|
// Flight Helmet
|
|
commands.spawn(WorldAssetRoot(asset_server.load(
|
|
GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"),
|
|
)));
|
|
|
|
// Light
|
|
commands.spawn((
|
|
DirectionalLight {
|
|
illuminance: light_consts::lux::FULL_DAYLIGHT,
|
|
shadow_maps_enabled: true,
|
|
..default()
|
|
},
|
|
Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, PI * -0.15, PI * -0.15)),
|
|
CascadeShadowConfigBuilder {
|
|
maximum_distance: 3.0,
|
|
first_cascade_far_bound: 0.9,
|
|
..default()
|
|
}
|
|
.build(),
|
|
));
|
|
|
|
// Camera
|
|
commands.spawn((
|
|
Camera3d::default(),
|
|
Hdr,
|
|
Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y),
|
|
ContrastAdaptiveSharpening {
|
|
enabled: false,
|
|
..default()
|
|
},
|
|
EnvironmentMapLight {
|
|
diffuse_map: asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2"),
|
|
specular_map: asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
|
|
intensity: 150.0,
|
|
..default()
|
|
},
|
|
DistanceFog {
|
|
color: Color::srgba_u8(43, 44, 47, 255),
|
|
falloff: FogFalloff::Linear {
|
|
start: 1.0,
|
|
end: 4.0,
|
|
},
|
|
..default()
|
|
},
|
|
));
|
|
|
|
// example instructions
|
|
commands.spawn((
|
|
Text::default(),
|
|
Node {
|
|
position_type: PositionType::Absolute,
|
|
top: px(12),
|
|
left: px(12),
|
|
..default()
|
|
},
|
|
));
|
|
}
|
|
|
|
/// Writes a simple menu item that can be on or off.
|
|
fn draw_selectable_menu_item(ui: &mut String, label: &str, shortcut: char, enabled: bool) {
|
|
let star = if enabled { "*" } else { "" };
|
|
let _ = writeln!(*ui, "({shortcut}) {star}{label}{star}");
|
|
}
|
|
|
|
/// Creates a colorful test pattern
|
|
fn uv_debug_texture() -> Image {
|
|
const TEXTURE_SIZE: usize = 8;
|
|
|
|
let mut palette: [u8; 32] = [
|
|
255, 102, 159, 255, 255, 159, 102, 255, 236, 255, 102, 255, 121, 255, 102, 255, 102, 255,
|
|
198, 255, 102, 198, 255, 255, 121, 102, 255, 255, 236, 102, 255, 255,
|
|
];
|
|
|
|
let mut texture_data = [0; TEXTURE_SIZE * TEXTURE_SIZE * 4];
|
|
for y in 0..TEXTURE_SIZE {
|
|
let offset = TEXTURE_SIZE * y * 4;
|
|
texture_data[offset..(offset + TEXTURE_SIZE * 4)].copy_from_slice(&palette);
|
|
palette.rotate_right(4);
|
|
}
|
|
|
|
let mut img = Image::new_fill(
|
|
Extent3d {
|
|
width: TEXTURE_SIZE as u32,
|
|
height: TEXTURE_SIZE as u32,
|
|
depth_or_array_layers: 1,
|
|
},
|
|
TextureDimension::D2,
|
|
&texture_data,
|
|
TextureFormat::Rgba8UnormSrgb,
|
|
RenderAssetUsages::RENDER_WORLD,
|
|
);
|
|
img.sampler = ImageSampler::Descriptor(ImageSamplerDescriptor::default());
|
|
img
|
|
}
|