wip
@@ -10,7 +10,7 @@ use crate::{
|
||||
};
|
||||
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct DebugMode(bool);
|
||||
pub struct DebugMode(pub bool);
|
||||
|
||||
pub struct DebugPlugin;
|
||||
impl Plugin for DebugPlugin {
|
||||
@@ -28,8 +28,11 @@ impl Plugin for DebugPlugin {
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
toggle_debug_mode,
|
||||
update_debug_picking_mode.run_if(resource_changed::<DebugMode>()),
|
||||
toggle_debug_mode.run_if(resource_exists::<Events<InputAction>>()),
|
||||
update_debug_picking_mode.run_if(
|
||||
resource_exists::<NextState<DebugPickingMode>>()
|
||||
.and_then(resource_changed::<DebugMode>()),
|
||||
),
|
||||
update_gizmo_line_thickness,
|
||||
draw_world_axes
|
||||
.after(CameraMotionSystem)
|
||||
@@ -72,7 +75,9 @@ fn update_gizmo_line_thickness(
|
||||
}
|
||||
|
||||
fn draw_world_axes(mut gizmos: Gizmos, q: Query<&CameraController>) {
|
||||
let &CameraController { focus, radius, .. } = q.single();
|
||||
let Ok(&CameraController { focus, radius, .. }) = q.get_single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut draw_axis = |direction: Vec3, color: Color| {
|
||||
let end = focus + direction * radius / 15.;
|
||||
|
||||
@@ -23,7 +23,7 @@ pub(super) struct TransformGizmoBundle {
|
||||
scale: NaturalScale,
|
||||
}
|
||||
|
||||
#[derive(Component, Deref, Reflect)]
|
||||
#[derive(Component, Deref)]
|
||||
pub(super) struct NaturalScale(pub Vec3);
|
||||
|
||||
#[derive(Component, Deref)]
|
||||
|
||||
@@ -35,7 +35,6 @@ pub struct GizmoPlugin;
|
||||
|
||||
impl Plugin for GizmoPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.register_type::<NaturalScale>();
|
||||
app.add_event::<RebuildGizmo>();
|
||||
app.add_systems(Startup, init_resources);
|
||||
app.add_systems(
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy_mod_picking::DefaultPickingPlugins;
|
||||
use camera_controller::CameraControllerPlugin;
|
||||
use debug::DebugPlugin;
|
||||
pub use debug::{DebugMode, DebugPlugin};
|
||||
use input::StudioInputPlugin;
|
||||
use interaction::InteractionPlugin;
|
||||
use math::InterpolationPlugin;
|
||||
use scene::ScenePlugin;
|
||||
use skybox::SkyboxPlugin;
|
||||
pub use math::InterpolationPlugin;
|
||||
pub use scene::{ActiveScene, Inspectable, ScenePlugin};
|
||||
pub use skybox::{SkyboxId, SkyboxPlugin};
|
||||
use ui::UiLayerPlugin;
|
||||
use viewport::ViewportSize;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
mod camera_controller;
|
||||
mod debug;
|
||||
mod design_system;
|
||||
pub mod design_system;
|
||||
mod input;
|
||||
mod interaction;
|
||||
mod math;
|
||||
pub mod math;
|
||||
mod scene;
|
||||
mod skybox;
|
||||
mod ui;
|
||||
@@ -27,8 +27,9 @@ mod viewport;
|
||||
#[cfg(feature = "wasm")]
|
||||
mod wasm;
|
||||
|
||||
#[derive(Component)]
|
||||
pub(crate) struct MainCamera;
|
||||
#[derive(Component, Reflect, Default)]
|
||||
#[reflect(Component)]
|
||||
pub struct MainCamera;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn init(viewport_size: ViewportSize) {
|
||||
@@ -36,6 +37,7 @@ pub fn init(viewport_size: ViewportSize) {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let mut app = App::new();
|
||||
app.register_type::<MainCamera>();
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
app.add_plugins(viewport::wasm::ViewportPlugin);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use bevy::{
|
||||
asset::LoadState,
|
||||
core_pipeline::{
|
||||
bloom::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings},
|
||||
core_3d::Camera3dDepthTextureUsage,
|
||||
fxaa::Fxaa,
|
||||
tonemapping::Tonemapping,
|
||||
},
|
||||
@@ -31,11 +33,20 @@ impl Plugin for ScenePlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.insert_resource(ClearColor(Color::hsl(0.0, 0.0, 0.25)))
|
||||
.insert_resource(Msaa::Off)
|
||||
.register_type::<Camera3dDepthTextureUsage>()
|
||||
.register_type::<Inspectable>()
|
||||
.add_plugins(MaterialPlugin::<ProceduralGridMaterial>::default())
|
||||
.add_systems(Startup, initialize)
|
||||
.add_systems(
|
||||
Update,
|
||||
mark_scene_objects.run_if(resource_exists::<NewScene>().and_then(scene_inst_ready)),
|
||||
(
|
||||
mark_scene_objects.run_if(
|
||||
resource_exists::<NewScene>()
|
||||
.and_then(scene_loaded)
|
||||
.and_then(scene_inst_ready),
|
||||
),
|
||||
log_asset_paths,
|
||||
),
|
||||
)
|
||||
.add_systems(PostUpdate, move_plane_with_camera.after(CameraMotionSystem));
|
||||
|
||||
@@ -52,6 +63,42 @@ impl Plugin for ScenePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
fn log_asset_paths(
|
||||
mut l_logged: Local<HashSet<Entity>>,
|
||||
r_assets: Res<AssetServer>,
|
||||
mut q_meshes: Query<(Entity, &Name, &Handle<Mesh>, &Handle<StandardMaterial>)>,
|
||||
) {
|
||||
for (ent, name, mesh, mat) in q_meshes.iter_mut() {
|
||||
if l_logged.contains(&ent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mesh_path = if mesh.is_strong() {
|
||||
r_assets.get_handle_path(mesh.id())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mat_path = if mat.is_strong() {
|
||||
r_assets.get_handle_path(mat.id())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if [&mesh_path, &mat_path]
|
||||
.iter()
|
||||
.any(|option| option.is_some())
|
||||
{
|
||||
info!("[{ent:?} {name}");
|
||||
info!(" mesh: {mesh_path:?}");
|
||||
info!(" material: {mat_path:?}");
|
||||
l_logged.insert(ent);
|
||||
} else if mesh.is_strong() && mat.is_strong() {
|
||||
info!("[{ent:?}] {name} | failed to determine asset paths");
|
||||
l_logged.insert(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct WorldGridPlane;
|
||||
|
||||
@@ -65,8 +112,9 @@ struct NewScene {
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct ActiveScene(pub Handle<Scene>);
|
||||
|
||||
#[derive(Component)]
|
||||
struct Inspectable;
|
||||
#[derive(Component, Reflect, Default)]
|
||||
#[reflect(Component)]
|
||||
pub struct Inspectable;
|
||||
|
||||
fn initialize(
|
||||
mut cmd: Commands,
|
||||
@@ -154,12 +202,30 @@ fn initialize(
|
||||
});
|
||||
}
|
||||
|
||||
fn scene_loaded(r_assets: Res<AssetServer>, r_new_scene: Res<NewScene>) -> bool {
|
||||
let Some(gltf) = &r_new_scene.gltf else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if r_assets.get_load_state(gltf) == LoadState::Loaded {
|
||||
info!("SCENE LOADED");
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn scene_inst_ready(r_scene_mgr: Res<SceneSpawner>, q_scene_inst: Query<&SceneInstance>) -> bool {
|
||||
let Ok(scene_inst) = q_scene_inst.get_single() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
r_scene_mgr.instance_is_ready(**scene_inst)
|
||||
if r_scene_mgr.instance_is_ready(**scene_inst) {
|
||||
info!("SCENE SPAWNED");
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn mark_scene_objects(
|
||||
|
||||
@@ -13,22 +13,26 @@ pub struct SkyboxPlugin;
|
||||
|
||||
impl Plugin for SkyboxPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(
|
||||
Update,
|
||||
(
|
||||
load_skybox.run_if(resource_exists_and_changed::<SkyboxId>()),
|
||||
spawn_skybox
|
||||
.run_if(resource_exists::<SkyboxAssets>())
|
||||
.run_if(skybox_assets_loaded),
|
||||
),
|
||||
);
|
||||
app.register_type::<SkyboxId>()
|
||||
.register_type::<SkyboxAssets>()
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
load_skybox.run_if(resource_exists_and_changed::<SkyboxId>()),
|
||||
spawn_skybox
|
||||
.run_if(resource_exists::<SkyboxAssets>())
|
||||
.run_if(skybox_assets_loaded),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
#[derive(Resource, Deref, DerefMut, Reflect, Default)]
|
||||
#[reflect(Resource)]
|
||||
pub struct SkyboxId(pub String);
|
||||
|
||||
#[derive(Resource)]
|
||||
#[derive(Resource, Reflect, Default)]
|
||||
#[reflect(Resource)]
|
||||
struct SkyboxAssets {
|
||||
cubemap: Handle<Image>,
|
||||
env_diffuse: Handle<Image>,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# Generating Skybox and Image-Based Lighting Assets
|
||||
|
||||
HDRI images like those available at [Poly Haven](https://polyhaven.com/hdris/skies)
|
||||
or [HDRI Haven](https://hdri-haven.com) must be preprocessed before they can be
|
||||
used for skyboxes and image-based lighting in Bevy Engine. Ultimately, three
|
||||
files are required:
|
||||
|
||||
* An `*.hdr` cubemap texture for the skybox
|
||||
* A `*.ktx2` prefiltered diffuse irradiance cubemap for IBL
|
||||
* A `*.ktx2` prefiltered specular cubemap for IBL
|
||||
|
||||
The HDR cubemap texture currently must be generated using Blender. A helper
|
||||
asset with instructions is available [here](https://drive.google.com/file/d/1UG_w9a6XfRmZtcfsSwFTDWPF7KnRa56I/view?usp=sharing)
|
||||
for Blender 3.6.
|
||||
|
||||
The prefiltered IBL cubemaps are generated with two CLI tools:
|
||||
|
||||
1. [glTF IBL Sampler](https://github.com/KhronosGroup/glTF-IBL-Sampler)
|
||||
* Git clone with `--recursive` and build using CMake
|
||||
* Diffuse:
|
||||
```sh
|
||||
./path/to/build-output/cli \
|
||||
-inputPath <input>.hdr \
|
||||
-outCubeMap <output>_diffuse.ktx2 \
|
||||
-distribution Lambertian \
|
||||
-cubeMapResolution 32
|
||||
```
|
||||
* Specular:
|
||||
```sh
|
||||
./path/to/build-output/cli \
|
||||
-inputPath <input>.hdr \
|
||||
-outCubeMap <output>_specular.ktx2 \
|
||||
-distribution GGX \
|
||||
-cubeMapResolution 512
|
||||
```
|
||||
|
||||
2. [bevy_mod_environment_map_tools](https://github.com/DGriffin91/bevy_mod_environment_map_tools)
|
||||
* You can run this directly with `cargo` on the files generated by the
|
||||
previous step:
|
||||
```sh
|
||||
cargo run --release -- \
|
||||
--inputs <input>_diffuse.ktx2,<input>_specular.ktx2 \
|
||||
--outputs <output>_diffuse.zstd.ktx2,<output>_specular.zstd.ktx2
|
||||
```
|
||||
|
||||
The Bevy app expects the filenames to exactly match the patterns given in the
|
||||
examples above:
|
||||
|
||||
* `{name}.hdr`
|
||||
* `{name}_diffuse.zstd.ktx2`
|
||||
* `{name}_specular.zstd.ktx2`
|
||||
|
||||
Once the files are in place, the application's `skybox` module can load all of
|
||||
the associated files for a skybox by passing its `name` to a helper function.
|
||||
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 915 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 971 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 915 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 612 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 915 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 898 KiB |
|
After Width: | Height: | Size: 929 KiB |
|
After Width: | Height: | Size: 915 KiB |
|
After Width: | Height: | Size: 707 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 932 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 249 KiB |
|
After Width: | Height: | Size: 983 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 244 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 530 KiB |
|
After Width: | Height: | Size: 976 KiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 339 KiB |
|
After Width: | Height: | Size: 445 KiB |
|
After Width: | Height: | Size: 4.1 MiB |
|
After Width: | Height: | Size: 345 KiB |
|
After Width: | Height: | Size: 597 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 445 KiB |
|
After Width: | Height: | Size: 990 KiB |
|
After Width: | Height: | Size: 915 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 916 KiB |
|
After Width: | Height: | Size: 253 KiB |
|
After Width: | Height: | Size: 443 KiB |
|
After Width: | Height: | Size: 915 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 229 KiB |
|
After Width: | Height: | Size: 284 KiB |
|
After Width: | Height: | Size: 914 KiB |
|
After Width: | Height: | Size: 274 KiB |
|
After Width: | Height: | Size: 419 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 258 KiB |
|
After Width: | Height: | Size: 197 KiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 916 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 309 KiB |
|
After Width: | Height: | Size: 937 KiB |
|
After Width: | Height: | Size: 209 KiB |
|
After Width: | Height: | Size: 418 KiB |
|
After Width: | Height: | Size: 915 KiB |