mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-23 20:30:54 +00:00
feat(scene components) : added scene components to control ambient, bloom etc from Blender(#76)
* feat(tools): scene component injection & export - ambient light, shadowmap resolution, bloom intensity, ambient occlusion are now directly settable from scene components that are injected automatically in the scene - relaxed requirements for changes(aka when to export gltf) for main scenes, so that render , background etc changes also trigger a save - added scene components examples - added additional proxies & handling for camera & lights - in relevant cases, made sure that entity specific components are not overridden by scene components - added option to toggle scene level exports of params/ components - ambient colour/ intensity is now also set as background/clear colour - updated docs
This commit is contained in:
parent
3d192f7876
commit
0aead0853c
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -809,6 +809,18 @@ dependencies = [
|
|||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_gltf_blueprints_basic_scene_components_example"
|
||||||
|
version = "0.3.0"
|
||||||
|
dependencies = [
|
||||||
|
"bevy",
|
||||||
|
"bevy_asset_loader",
|
||||||
|
"bevy_editor_pls",
|
||||||
|
"bevy_gltf_blueprints",
|
||||||
|
"bevy_rapier3d",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_gltf_blueprints_basic_xpbd_physics_example"
|
name = "bevy_gltf_blueprints_basic_xpbd_physics_example"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -4,6 +4,7 @@ members = [
|
|||||||
"crates/bevy_gltf_blueprints",
|
"crates/bevy_gltf_blueprints",
|
||||||
"examples/bevy_gltf_components/basic/",
|
"examples/bevy_gltf_components/basic/",
|
||||||
"examples/bevy_gltf_blueprints/basic/",
|
"examples/bevy_gltf_blueprints/basic/",
|
||||||
|
"examples/bevy_gltf_blueprints/basic_scene_components/",
|
||||||
"examples/bevy_gltf_blueprints/basic_xpbd_physics/",
|
"examples/bevy_gltf_blueprints/basic_xpbd_physics/",
|
||||||
"examples/bevy_gltf_blueprints/animation/",
|
"examples/bevy_gltf_blueprints/animation/",
|
||||||
"examples/bevy_gltf_blueprints/multiple_levels/",
|
"examples/bevy_gltf_blueprints/multiple_levels/",
|
||||||
|
@ -273,6 +273,8 @@ https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/example
|
|||||||
|
|
||||||
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/basic_xpbd_physics
|
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/basic_xpbd_physics
|
||||||
|
|
||||||
|
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/basic_scene_components
|
||||||
|
|
||||||
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/animation
|
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/animation
|
||||||
|
|
||||||
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/multiple_levels
|
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/multiple_levels
|
||||||
|
4629
examples/bevy_gltf_blueprints/basic_scene_components/Cargo.lock
generated
Normal file
4629
examples/bevy_gltf_blueprints/basic_scene_components/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "bevy_gltf_blueprints_basic_scene_components_example"
|
||||||
|
version = "0.3.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bevy="0.12"
|
||||||
|
bevy_gltf_blueprints = { path = "../../../crates/bevy_gltf_blueprints" }
|
||||||
|
bevy_rapier3d = { version = "0.23.0", features = [ "serde-serialize", "debug-render-3d", "enhanced-determinism"] }
|
||||||
|
bevy_asset_loader = { version = "0.18", features = ["standard_dynamic_assets" ]}
|
||||||
|
bevy_editor_pls = { version = "0.6" }
|
||||||
|
rand = "0.8.5"
|
@ -0,0 +1,11 @@
|
|||||||
|
# Basic scene components demo
|
||||||
|
|
||||||
|
This example showcases the use of "scene" components ie components that are injected into the root scene/level so that you can control things
|
||||||
|
like ambient lighting, bloom, shadowmap resolution, & ao directly from Blender.
|
||||||
|
|
||||||
|
## Running this example
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo run --features bevy/dynamic_linking
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
({})
|
@ -0,0 +1,6 @@
|
|||||||
|
({
|
||||||
|
"world":File (path: "models/World.glb"),
|
||||||
|
"models": Folder (
|
||||||
|
path: "models/library",
|
||||||
|
),
|
||||||
|
})
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,485 @@
|
|||||||
|
(
|
||||||
|
resources: {},
|
||||||
|
entities: {
|
||||||
|
20: (
|
||||||
|
components: {
|
||||||
|
"bevy_render::camera::projection::Projection": Perspective((
|
||||||
|
fov: 0.3995965,
|
||||||
|
aspect_ratio: 1.7777778,
|
||||||
|
near: 0.1,
|
||||||
|
far: 100.0,
|
||||||
|
)),
|
||||||
|
"bevy_render::primitives::Frustum": (),
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 34.821884,
|
||||||
|
y: 49.024857,
|
||||||
|
z: -36.79615,
|
||||||
|
),
|
||||||
|
rotation: (-0.1694689, 0.82838506, 0.40884802, 0.3433684),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core_pipeline::tonemapping::Tonemapping": BlenderFilmic,
|
||||||
|
"bevy_core_pipeline::tonemapping::DebandDither": Enabled,
|
||||||
|
"bevy_render::view::ColorGrading": (
|
||||||
|
exposure: 0.0,
|
||||||
|
gamma: 1.0,
|
||||||
|
pre_saturation: 1.0,
|
||||||
|
post_saturation: 1.0,
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 17702508670109176045,
|
||||||
|
name: "Camera",
|
||||||
|
),
|
||||||
|
"advanced::core::camera::camera_tracking::CameraTrackingOffset": ((
|
||||||
|
x: 26.0,
|
||||||
|
y: 48.0,
|
||||||
|
z: -26.0,
|
||||||
|
)),
|
||||||
|
"bevy_pbr::light::ClusterConfig": FixedZ(
|
||||||
|
total: 4096,
|
||||||
|
z_slices: 24,
|
||||||
|
z_config: (
|
||||||
|
first_slice_depth: 5.0,
|
||||||
|
far_z_mode: MaxLightRange,
|
||||||
|
),
|
||||||
|
dynamic_resizing: true,
|
||||||
|
),
|
||||||
|
"bevy_core_pipeline::bloom::settings::BloomSettings": (
|
||||||
|
intensity: 0.01,
|
||||||
|
low_frequency_boost: 0.7,
|
||||||
|
low_frequency_boost_curvature: 0.95,
|
||||||
|
high_pass_frequency: 1.0,
|
||||||
|
prefilter_settings: (
|
||||||
|
threshold: 0.0,
|
||||||
|
threshold_softness: 0.0,
|
||||||
|
),
|
||||||
|
composite_mode: Additive,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
34: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 4.697565,
|
||||||
|
y: 1.5983224,
|
||||||
|
z: 8.962274,
|
||||||
|
),
|
||||||
|
rotation: (0.000000000000000031724054, -0.00000000000000000000647681, -0.000013119204, 1.0),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 9837288155836662016,
|
||||||
|
name: "Health_Pickup.001",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
54: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 8.799996,
|
||||||
|
y: 1.02484,
|
||||||
|
z: -10.799994,
|
||||||
|
),
|
||||||
|
rotation: (0.0, 0.0, 0.0, 1.0),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 17978181434632022651,
|
||||||
|
name: "Player",
|
||||||
|
),
|
||||||
|
"advanced::core::camera::camera_tracking::CameraTrackable": (),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Player"),
|
||||||
|
"advanced::game::Player": (),
|
||||||
|
"advanced::game::SoundMaterial": Wood,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
60: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 3.6351967,
|
||||||
|
y: 1.7298106,
|
||||||
|
z: -7.313273,
|
||||||
|
),
|
||||||
|
rotation: (0.0, 0.0, 0.0, 1.0),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 7225506896223411979,
|
||||||
|
name: "MagicTeapot.001",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("MagicTeapot"),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
64: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: -4.6068983,
|
||||||
|
y: 1.5983224,
|
||||||
|
z: -10.579347,
|
||||||
|
),
|
||||||
|
rotation: (0.000000000000000031724054, 0.00000000000000000000647681, 0.000013119204, 1.0),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 3089896164553476909,
|
||||||
|
name: "Health_Pickup.002",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
72: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: -11.560788,
|
||||||
|
y: 0.0,
|
||||||
|
z: 7.6554174,
|
||||||
|
),
|
||||||
|
rotation: (0.0, 0.0, 0.0, 1.0),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 16961132108296874979,
|
||||||
|
name: "Container.001",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Container"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
80: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: -21.397858,
|
||||||
|
y: 0.3833189,
|
||||||
|
z: -0.32418346,
|
||||||
|
),
|
||||||
|
rotation: (0.0, 0.0, 0.0, 1.0),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 5104740624378885265,
|
||||||
|
name: "Container.002",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Container"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
82: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 2.9156065,
|
||||||
|
y: 1.4984571,
|
||||||
|
z: 2.1909573,
|
||||||
|
),
|
||||||
|
rotation: (0.058853183, 0.0726243, 0.2048649, 0.97431636),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 107557640935939866,
|
||||||
|
name: "test5159735758431545549",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
"bevy_rapier3d::dynamics::rigid_body::Velocity": (
|
||||||
|
linvel: (
|
||||||
|
x: -1.2580805,
|
||||||
|
y: -0.39687577,
|
||||||
|
z: 0.4816798,
|
||||||
|
),
|
||||||
|
angvel: (
|
||||||
|
x: 0.2979751,
|
||||||
|
y: 0.07926611,
|
||||||
|
z: 0.8434645,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
86: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 0.26087752,
|
||||||
|
y: 1.5525806,
|
||||||
|
z: 1.5980839,
|
||||||
|
),
|
||||||
|
rotation: (0.059497803, -0.0000018232388, 0.13145457, 0.9895351),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 3398656236303073559,
|
||||||
|
name: "test7470642598731063943",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
"bevy_rapier3d::dynamics::rigid_body::Velocity": (
|
||||||
|
linvel: (
|
||||||
|
x: -0.9268077,
|
||||||
|
y: -0.19806683,
|
||||||
|
z: 0.41948256,
|
||||||
|
),
|
||||||
|
angvel: (
|
||||||
|
x: 0.26946256,
|
||||||
|
y: -0.000006710977,
|
||||||
|
z: 0.5953494,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
90: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 2.6515265,
|
||||||
|
y: 1.5944021,
|
||||||
|
z: -4.391837,
|
||||||
|
),
|
||||||
|
rotation: (-0.030030435, -0.0000006527225, 0.029748484, 0.9991062),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 12541900054595385134,
|
||||||
|
name: "test3938024405863834719",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
"bevy_rapier3d::dynamics::rigid_body::Velocity": (
|
||||||
|
linvel: (
|
||||||
|
x: -0.28430828,
|
||||||
|
y: -0.022357654,
|
||||||
|
z: -0.2870027,
|
||||||
|
),
|
||||||
|
angvel: (
|
||||||
|
x: -0.17986917,
|
||||||
|
y: -0.0000035613396,
|
||||||
|
z: 0.17818078,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
94: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: -4.2356462,
|
||||||
|
y: 1.596993,
|
||||||
|
z: 0.7254991,
|
||||||
|
),
|
||||||
|
rotation: (-0.0221751, -0.0000000001891749, 0.011065631, 0.99969286),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 6757906322211730861,
|
||||||
|
name: "test11007490954016878479",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
"bevy_rapier3d::dynamics::rigid_body::Velocity": (
|
||||||
|
linvel: (
|
||||||
|
x: -0.21747473,
|
||||||
|
y: -0.014912919,
|
||||||
|
z: -0.43581253,
|
||||||
|
),
|
||||||
|
angvel: (
|
||||||
|
x: -0.2727097,
|
||||||
|
y: -0.0000000034594905,
|
||||||
|
z: 0.13608481,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
98: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 3.1525247,
|
||||||
|
y: 1.5518407,
|
||||||
|
z: -2.9611976,
|
||||||
|
),
|
||||||
|
rotation: (-0.09219627, 0.1602262, -0.11205085, 0.9763565),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 12588565107899185946,
|
||||||
|
name: "test5980867849331267699",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
"bevy_rapier3d::dynamics::rigid_body::Velocity": (
|
||||||
|
linvel: (
|
||||||
|
x: 0.8323179,
|
||||||
|
y: -0.20597076,
|
||||||
|
z: -0.68975484,
|
||||||
|
),
|
||||||
|
angvel: (
|
||||||
|
x: -0.37971017,
|
||||||
|
y: 0.49603412,
|
||||||
|
z: -0.6079359,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
4294967310: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 4.826278,
|
||||||
|
y: 1.2710563,
|
||||||
|
z: -3.1997645,
|
||||||
|
),
|
||||||
|
rotation: (-0.303028, 0.00000087800436, -0.23889118, 0.9225535),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 15533546218717453536,
|
||||||
|
name: "test12380979123759326444",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
"bevy_rapier3d::dynamics::rigid_body::Velocity": (
|
||||||
|
linvel: (
|
||||||
|
x: 1.2146912,
|
||||||
|
y: -1.1640646,
|
||||||
|
z: -1.5408095,
|
||||||
|
),
|
||||||
|
angvel: (
|
||||||
|
x: -1.1932359,
|
||||||
|
y: 0.000002945365,
|
||||||
|
z: -0.94068503,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
4294967314: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 3.9906094,
|
||||||
|
y: 1.4824095,
|
||||||
|
z: 2.4394412,
|
||||||
|
),
|
||||||
|
rotation: (0.06015042, 0.085218765, 0.2215642, 0.9695509),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 2466794778849297109,
|
||||||
|
name: "test12475628281920299197",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
"bevy_rapier3d::dynamics::rigid_body::Velocity": (
|
||||||
|
linvel: (
|
||||||
|
x: -1.0818624,
|
||||||
|
y: -0.37798148,
|
||||||
|
z: 0.45334253,
|
||||||
|
),
|
||||||
|
angvel: (
|
||||||
|
x: 0.25961447,
|
||||||
|
y: 0.14854014,
|
||||||
|
z: 0.7426717,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
4294967321: (
|
||||||
|
components: {
|
||||||
|
"bevy_transform::components::transform::Transform": (
|
||||||
|
translation: (
|
||||||
|
x: 2.2306876,
|
||||||
|
y: 0.989814,
|
||||||
|
z: -1.3596333,
|
||||||
|
),
|
||||||
|
rotation: (0.30614096, 0.002587511, -0.42789298, 0.8503991),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"bevy_core::name::Name": (
|
||||||
|
hash: 1545925632270385398,
|
||||||
|
name: "test15780367212768138828",
|
||||||
|
),
|
||||||
|
"bevy_gltf_blueprints::spawn_from_blueprints::BlueprintName": ("Health_Pickup"),
|
||||||
|
"advanced::game::picking::Pickable": (),
|
||||||
|
"bevy_rapier3d::dynamics::rigid_body::Velocity": (
|
||||||
|
linvel: (
|
||||||
|
x: 1.3027526,
|
||||||
|
y: -1.8947054,
|
||||||
|
z: 1.6179247,
|
||||||
|
),
|
||||||
|
angvel: (
|
||||||
|
x: 1.4565696,
|
||||||
|
y: -0.16299045,
|
||||||
|
z: -1.3631926,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
@ -0,0 +1,5 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_asset_loader::prelude::*;
|
||||||
|
|
||||||
|
#[derive(AssetCollection, Resource)]
|
||||||
|
pub struct CoreAssets {}
|
@ -0,0 +1,13 @@
|
|||||||
|
use bevy::gltf::Gltf;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::utils::HashMap;
|
||||||
|
use bevy_asset_loader::prelude::*;
|
||||||
|
|
||||||
|
#[derive(AssetCollection, Resource)]
|
||||||
|
pub struct GameAssets {
|
||||||
|
#[asset(key = "world")]
|
||||||
|
pub world: Handle<Gltf>,
|
||||||
|
|
||||||
|
#[asset(key = "models", collection(typed, mapped))]
|
||||||
|
pub models: HashMap<String, Handle<Gltf>>,
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
pub mod assets_core;
|
||||||
|
pub use assets_core::*;
|
||||||
|
|
||||||
|
pub mod assets_game;
|
||||||
|
pub use assets_game::*;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_asset_loader::prelude::*;
|
||||||
|
|
||||||
|
use crate::state::AppState;
|
||||||
|
|
||||||
|
pub struct AssetsPlugin;
|
||||||
|
impl Plugin for AssetsPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app
|
||||||
|
// load core assets (ie assets needed in the main menu, and everywhere else before loading more assets in game)
|
||||||
|
.add_loading_state(
|
||||||
|
LoadingState::new(AppState::CoreLoading).continue_to_state(AppState::MenuRunning),
|
||||||
|
)
|
||||||
|
.add_dynamic_collection_to_loading_state::<_, StandardDynamicAssetCollection>(
|
||||||
|
AppState::CoreLoading,
|
||||||
|
"assets_core.assets.ron",
|
||||||
|
)
|
||||||
|
.add_collection_to_loading_state::<_, CoreAssets>(AppState::CoreLoading)
|
||||||
|
// load game assets
|
||||||
|
.add_loading_state(
|
||||||
|
LoadingState::new(AppState::AppLoading).continue_to_state(AppState::AppRunning),
|
||||||
|
)
|
||||||
|
.add_dynamic_collection_to_loading_state::<_, StandardDynamicAssetCollection>(
|
||||||
|
AppState::AppLoading,
|
||||||
|
"assets_game.assets.ron",
|
||||||
|
)
|
||||||
|
.add_collection_to_loading_state::<_, GameAssets>(AppState::AppLoading);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
use bevy::core_pipeline::bloom::{BloomCompositeMode, BloomSettings};
|
||||||
|
use bevy::core_pipeline::experimental::taa::TemporalAntiAliasBundle;
|
||||||
|
use bevy::core_pipeline::tonemapping::{DebandDither, Tonemapping};
|
||||||
|
use bevy::pbr::ScreenSpaceAmbientOcclusionBundle;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use super::CameraTrackingOffset;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct SSAOSettings;
|
||||||
|
|
||||||
|
pub fn camera_replace_proxies(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut added_cameras: Query<(Entity, &mut Camera, Option<&BloomSettings>, Option<&SSAOSettings>), (Added<Camera>, With<CameraTrackingOffset>)>,
|
||||||
|
|
||||||
|
added_bloom_settings : Query<&BloomSettings, Added<BloomSettings>>,
|
||||||
|
added_ssao_settings: Query<&SSAOSettings, Added<SSAOSettings>>, // Move to camera
|
||||||
|
) {
|
||||||
|
for (entity, mut camera, bloom_settings, ssao_setting) in added_cameras.iter_mut() {
|
||||||
|
info!("detected added camera, updating proxy");
|
||||||
|
camera.hdr = true;
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(DebandDither::Enabled)
|
||||||
|
.insert(Tonemapping::BlenderFilmic)
|
||||||
|
;
|
||||||
|
|
||||||
|
// we only inject the scene_level bloom settings if there are no settings already on the Camera
|
||||||
|
if bloom_settings.is_none() {
|
||||||
|
for bloom_settings in added_bloom_settings.iter(){
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(BloomSettings {
|
||||||
|
intensity: bloom_settings.intensity,
|
||||||
|
composite_mode: BloomCompositeMode::Additive,
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ssao_setting.is_none() {
|
||||||
|
for _ in added_ssao_settings.iter(){
|
||||||
|
commands.insert_resource(Msaa::Off); // when using SSAO, you cannot use Msaa
|
||||||
|
|
||||||
|
commands.entity(entity)
|
||||||
|
.insert(ScreenSpaceAmbientOcclusionBundle::default())
|
||||||
|
.insert(TemporalAntiAliasBundle::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// Component for cameras, with an offset from the Trackable target
|
||||||
|
///
|
||||||
|
pub struct CameraTracking {
|
||||||
|
pub offset: Vec3,
|
||||||
|
}
|
||||||
|
impl Default for CameraTracking {
|
||||||
|
fn default() -> Self {
|
||||||
|
CameraTracking {
|
||||||
|
offset: Vec3::new(0.0, 6.0, 8.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Debug, Deref, DerefMut)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// Component for cameras, with an offset from the Trackable target
|
||||||
|
pub struct CameraTrackingOffset(Vec3);
|
||||||
|
impl Default for CameraTrackingOffset {
|
||||||
|
fn default() -> Self {
|
||||||
|
CameraTrackingOffset(Vec3::new(0.0, 6.0, 8.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CameraTrackingOffset {
|
||||||
|
fn new(input: Vec3) -> Self {
|
||||||
|
CameraTrackingOffset(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// Add this component to an entity if you want it to be tracked by a Camera
|
||||||
|
pub struct CameraTrackable;
|
||||||
|
|
||||||
|
pub fn camera_track(
|
||||||
|
mut tracking_cameras: Query<
|
||||||
|
(&mut Transform, &CameraTrackingOffset),
|
||||||
|
(
|
||||||
|
With<Camera>,
|
||||||
|
With<CameraTrackingOffset>,
|
||||||
|
Without<CameraTrackable>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
camera_tracked: Query<&Transform, With<CameraTrackable>>,
|
||||||
|
) {
|
||||||
|
for (mut camera_transform, tracking_offset) in tracking_cameras.iter_mut() {
|
||||||
|
for tracked_transform in camera_tracked.iter() {
|
||||||
|
let target_position = tracked_transform.translation + tracking_offset.0;
|
||||||
|
let eased_position = camera_transform.translation.lerp(target_position, 0.1);
|
||||||
|
camera_transform.translation = eased_position; // + tracking.offset;// tracked_transform.translation + tracking.offset;
|
||||||
|
*camera_transform = camera_transform.looking_at(tracked_transform.translation, Vec3::Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
pub mod camera_tracking;
|
||||||
|
pub use camera_tracking::*;
|
||||||
|
|
||||||
|
pub mod camera_replace_proxies;
|
||||||
|
pub use camera_replace_proxies::*;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_gltf_blueprints::GltfBlueprintsSet;
|
||||||
|
|
||||||
|
pub struct CameraPlugin;
|
||||||
|
impl Plugin for CameraPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.register_type::<CameraTrackable>()
|
||||||
|
.register_type::<CameraTracking>()
|
||||||
|
.register_type::<CameraTrackingOffset>()
|
||||||
|
.register_type::<SSAOSettings>()
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
camera_replace_proxies.after(GltfBlueprintsSet::AfterSpawn),
|
||||||
|
camera_track,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use bevy::pbr::{CascadeShadowConfig, CascadeShadowConfigBuilder, DirectionalLightShadowMap};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct AmbientLightSettings {pub color: Color, pub brightness: f32}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct ShadowmapSettings {pub size: usize}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn lighting_replace_proxies(
|
||||||
|
mut added_dirights: Query<(Entity, &mut DirectionalLight), Added<DirectionalLight>>,
|
||||||
|
mut added_spotlights: Query<&mut SpotLight, Added<SpotLight>>,
|
||||||
|
mut added_pointlights: Query<&mut PointLight, Added<PointLight>>,
|
||||||
|
|
||||||
|
added_ambient_proxies : Query<&AmbientLightSettings, Added<AmbientLightSettings>>,
|
||||||
|
added_shadowmap_settings : Query<&ShadowmapSettings, Added<ShadowmapSettings>>,
|
||||||
|
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for (entity, mut light) in added_dirights.iter_mut() {
|
||||||
|
light.illuminance *= 5.0;
|
||||||
|
light.shadows_enabled = true;
|
||||||
|
let shadow_config: CascadeShadowConfig = CascadeShadowConfigBuilder {
|
||||||
|
first_cascade_far_bound: 15.0,
|
||||||
|
maximum_distance: 135.0,
|
||||||
|
..default()
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
commands.entity(entity).insert(shadow_config);
|
||||||
|
}
|
||||||
|
for mut light in added_spotlights.iter_mut() {
|
||||||
|
light.shadows_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for mut light in added_pointlights.iter_mut() {
|
||||||
|
light.intensity *= 0.001; // arbitrary/ eyeballed to match the levels of Blender
|
||||||
|
light.shadows_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for setting in added_shadowmap_settings.iter() {
|
||||||
|
commands.insert_resource(DirectionalLightShadowMap { size: setting.size });
|
||||||
|
}
|
||||||
|
|
||||||
|
for ambient in added_ambient_proxies.iter(){
|
||||||
|
commands.insert_resource(AmbientLight {
|
||||||
|
color: ambient.color,
|
||||||
|
brightness: ambient.brightness,
|
||||||
|
});
|
||||||
|
// FIXME: does this belong here ?
|
||||||
|
commands.insert_resource(ClearColor(ambient.color * ambient.brightness));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
mod lighting_replace_proxies;
|
||||||
|
use lighting_replace_proxies::*;
|
||||||
|
|
||||||
|
use bevy::pbr::NotShadowCaster;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub struct LightingPlugin;
|
||||||
|
impl Plugin for LightingPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app
|
||||||
|
.register_type::<AmbientLightSettings>()
|
||||||
|
.register_type::<ShadowmapSettings>()
|
||||||
|
// FIXME: adding these since they are missing
|
||||||
|
.register_type::<NotShadowCaster>()
|
||||||
|
|
||||||
|
.add_systems(PreUpdate, lighting_replace_proxies)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
pub mod camera;
|
||||||
|
pub use camera::*;
|
||||||
|
|
||||||
|
pub mod lighting;
|
||||||
|
pub use lighting::*;
|
||||||
|
|
||||||
|
pub mod relationships;
|
||||||
|
pub use relationships::*;
|
||||||
|
|
||||||
|
pub mod physics;
|
||||||
|
pub use physics::*;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_gltf_blueprints::*;
|
||||||
|
|
||||||
|
pub struct CorePlugin;
|
||||||
|
impl Plugin for CorePlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_plugins((
|
||||||
|
LightingPlugin,
|
||||||
|
CameraPlugin,
|
||||||
|
PhysicsPlugin,
|
||||||
|
BlueprintsPlugin {
|
||||||
|
library_folder: "models/library".into(),
|
||||||
|
format: GltfFormat::GLB,
|
||||||
|
aabbs: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
use bevy::{
|
||||||
|
ecs::system::Res,
|
||||||
|
input::{keyboard::KeyCode, Input},
|
||||||
|
prelude::{info, ResMut},
|
||||||
|
};
|
||||||
|
use bevy_rapier3d::{prelude::RapierConfiguration, render::DebugRenderContext};
|
||||||
|
|
||||||
|
pub fn pause_physics(mut physics_config: ResMut<RapierConfiguration>) {
|
||||||
|
info!("pausing physics");
|
||||||
|
physics_config.physics_pipeline_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resume_physics(mut physics_config: ResMut<RapierConfiguration>) {
|
||||||
|
info!("unpausing physics");
|
||||||
|
physics_config.physics_pipeline_active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_physics_debug(
|
||||||
|
mut debug_config: ResMut<DebugRenderContext>,
|
||||||
|
keycode: Res<Input<KeyCode>>,
|
||||||
|
) {
|
||||||
|
if keycode.just_pressed(KeyCode::D) {
|
||||||
|
debug_config.enabled = !debug_config.enabled;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
pub mod physics_replace_proxies;
|
||||||
|
pub use physics_replace_proxies::*;
|
||||||
|
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
pub mod controls;
|
||||||
|
pub use controls::*;
|
||||||
|
|
||||||
|
use crate::state::GameState;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_gltf_blueprints::GltfBlueprintsSet;
|
||||||
|
use bevy_rapier3d::{
|
||||||
|
prelude::{NoUserData, RapierPhysicsPlugin},
|
||||||
|
render::RapierDebugRenderPlugin,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PhysicsPlugin;
|
||||||
|
impl Plugin for PhysicsPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_plugins((
|
||||||
|
RapierPhysicsPlugin::<NoUserData>::default(),
|
||||||
|
RapierDebugRenderPlugin::default(),
|
||||||
|
))
|
||||||
|
.register_type::<AutoAABBCollider>()
|
||||||
|
.register_type::<physics_replace_proxies::Collider>()
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
physics_replace_proxies.after(GltfBlueprintsSet::AfterSpawn),
|
||||||
|
)
|
||||||
|
.add_systems(Update, toggle_physics_debug)
|
||||||
|
.add_systems(OnEnter(GameState::InGame), resume_physics)
|
||||||
|
.add_systems(OnExit(GameState::InGame), pause_physics);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
// use bevy::render::primitives::Aabb;
|
||||||
|
use bevy_rapier3d::geometry::Collider as RapierCollider;
|
||||||
|
use bevy_rapier3d::prelude::{ActiveCollisionTypes, ActiveEvents, ComputedColliderShape};
|
||||||
|
|
||||||
|
use super::utils::*;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub enum Collider {
|
||||||
|
Ball(f32),
|
||||||
|
Cuboid(Vec3),
|
||||||
|
Capsule(Vec3, Vec3, f32),
|
||||||
|
#[default]
|
||||||
|
Mesh,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub enum AutoAABBCollider {
|
||||||
|
#[default]
|
||||||
|
Cuboid,
|
||||||
|
Ball,
|
||||||
|
Capsule,
|
||||||
|
}
|
||||||
|
|
||||||
|
// replaces all physics stand-ins with the actual rapier types
|
||||||
|
pub fn physics_replace_proxies(
|
||||||
|
meshes: Res<Assets<Mesh>>,
|
||||||
|
mesh_handles: Query<&Handle<Mesh>>,
|
||||||
|
mut proxy_colliders: Query<
|
||||||
|
(Entity, &Collider, &Name, &mut Visibility),
|
||||||
|
(Without<RapierCollider>, Added<Collider>),
|
||||||
|
>,
|
||||||
|
// needed for tri meshes
|
||||||
|
children: Query<&Children>,
|
||||||
|
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for proxy_colider in proxy_colliders.iter_mut() {
|
||||||
|
let (entity, collider_proxy, name, mut visibility) = proxy_colider;
|
||||||
|
// we hide the collider meshes: perhaps they should be removed altogether once processed ?
|
||||||
|
if name.ends_with("_collider") || name.ends_with("_sensor") {
|
||||||
|
*visibility = Visibility::Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rapier_collider: RapierCollider;
|
||||||
|
match collider_proxy {
|
||||||
|
Collider::Ball(radius) => {
|
||||||
|
info!("generating collider from proxy: ball");
|
||||||
|
rapier_collider = RapierCollider::ball(*radius);
|
||||||
|
commands.entity(entity)
|
||||||
|
.insert(rapier_collider)
|
||||||
|
.insert(ActiveEvents::COLLISION_EVENTS) // FIXME: this is just for demo purposes !!!
|
||||||
|
;
|
||||||
|
}
|
||||||
|
Collider::Cuboid(size) => {
|
||||||
|
info!("generating collider from proxy: cuboid");
|
||||||
|
rapier_collider = RapierCollider::cuboid(size.x, size.y, size.z);
|
||||||
|
commands.entity(entity)
|
||||||
|
.insert(rapier_collider)
|
||||||
|
.insert(ActiveEvents::COLLISION_EVENTS) // FIXME: this is just for demo purposes !!!
|
||||||
|
;
|
||||||
|
}
|
||||||
|
Collider::Capsule(a, b, radius) => {
|
||||||
|
info!("generating collider from proxy: capsule");
|
||||||
|
rapier_collider = RapierCollider::capsule(*a, *b, *radius);
|
||||||
|
commands.entity(entity)
|
||||||
|
.insert(rapier_collider)
|
||||||
|
.insert(ActiveEvents::COLLISION_EVENTS) // FIXME: this is just for demo purposes !!!
|
||||||
|
;
|
||||||
|
}
|
||||||
|
Collider::Mesh => {
|
||||||
|
info!("generating collider from proxy: mesh");
|
||||||
|
for (_, collider_mesh) in
|
||||||
|
Mesh::search_in_children(entity, &children, &meshes, &mesh_handles)
|
||||||
|
{
|
||||||
|
rapier_collider = RapierCollider::from_bevy_mesh(
|
||||||
|
collider_mesh,
|
||||||
|
&ComputedColliderShape::TriMesh,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(rapier_collider)
|
||||||
|
// FIXME: this is just for demo purposes !!!
|
||||||
|
.insert(
|
||||||
|
ActiveCollisionTypes::default()
|
||||||
|
| ActiveCollisionTypes::KINEMATIC_STATIC
|
||||||
|
| ActiveCollisionTypes::STATIC_STATIC
|
||||||
|
| ActiveCollisionTypes::DYNAMIC_STATIC,
|
||||||
|
)
|
||||||
|
.insert(ActiveEvents::COLLISION_EVENTS);
|
||||||
|
// .insert(ActiveEvents::COLLISION_EVENTS)
|
||||||
|
// break;
|
||||||
|
// RapierCollider::convex_hull(points)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,175 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::render::mesh::{MeshVertexAttributeId, PrimitiveTopology, VertexAttributeValues};
|
||||||
|
// TAKEN VERBATIB FROM https://github.com/janhohenheim/foxtrot/blob/src/util/trait_extension.rs
|
||||||
|
|
||||||
|
pub(crate) trait Vec3Ext: Copy {
|
||||||
|
fn is_approx_zero(self) -> bool;
|
||||||
|
fn split(self, up: Vec3) -> SplitVec3;
|
||||||
|
}
|
||||||
|
impl Vec3Ext for Vec3 {
|
||||||
|
#[inline]
|
||||||
|
fn is_approx_zero(self) -> bool {
|
||||||
|
self.length_squared() < 1e-5
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn split(self, up: Vec3) -> SplitVec3 {
|
||||||
|
let vertical = up * self.dot(up);
|
||||||
|
let horizontal = self - vertical;
|
||||||
|
SplitVec3 {
|
||||||
|
vertical,
|
||||||
|
horizontal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub(crate) struct SplitVec3 {
|
||||||
|
pub(crate) vertical: Vec3,
|
||||||
|
pub(crate) horizontal: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait Vec2Ext: Copy {
|
||||||
|
fn is_approx_zero(self) -> bool;
|
||||||
|
fn x0y(self) -> Vec3;
|
||||||
|
}
|
||||||
|
impl Vec2Ext for Vec2 {
|
||||||
|
#[inline]
|
||||||
|
fn is_approx_zero(self) -> bool {
|
||||||
|
self.length_squared() < 1e-5
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn x0y(self) -> Vec3 {
|
||||||
|
Vec3::new(self.x, 0., self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait MeshExt {
|
||||||
|
fn transform(&mut self, transform: Transform);
|
||||||
|
fn transformed(&self, transform: Transform) -> Mesh;
|
||||||
|
fn read_coords_mut(&mut self, id: impl Into<MeshVertexAttributeId>) -> &mut Vec<[f32; 3]>;
|
||||||
|
fn search_in_children<'a>(
|
||||||
|
parent: Entity,
|
||||||
|
children: &'a Query<&Children>,
|
||||||
|
meshes: &'a Assets<Mesh>,
|
||||||
|
mesh_handles: &'a Query<&Handle<Mesh>>,
|
||||||
|
) -> Vec<(Entity, &'a Mesh)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MeshExt for Mesh {
|
||||||
|
fn transform(&mut self, transform: Transform) {
|
||||||
|
for coords in self.read_coords_mut(Mesh::ATTRIBUTE_POSITION.clone()) {
|
||||||
|
let vec3 = (*coords).into();
|
||||||
|
let transformed = transform.transform_point(vec3);
|
||||||
|
*coords = transformed.into();
|
||||||
|
}
|
||||||
|
for normal in self.read_coords_mut(Mesh::ATTRIBUTE_NORMAL.clone()) {
|
||||||
|
let vec3 = (*normal).into();
|
||||||
|
let transformed = transform.rotation.mul_vec3(vec3);
|
||||||
|
*normal = transformed.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transformed(&self, transform: Transform) -> Mesh {
|
||||||
|
let mut mesh = self.clone();
|
||||||
|
mesh.transform(transform);
|
||||||
|
mesh
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_coords_mut(&mut self, id: impl Into<MeshVertexAttributeId>) -> &mut Vec<[f32; 3]> {
|
||||||
|
// Guaranteed by Bevy for the current usage
|
||||||
|
match self
|
||||||
|
.attribute_mut(id)
|
||||||
|
.expect("Failed to read unknown mesh attribute")
|
||||||
|
{
|
||||||
|
VertexAttributeValues::Float32x3(values) => values,
|
||||||
|
// Guaranteed by Bevy for the current usage
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_in_children<'a>(
|
||||||
|
parent: Entity,
|
||||||
|
children_query: &'a Query<&Children>,
|
||||||
|
meshes: &'a Assets<Mesh>,
|
||||||
|
mesh_handles: &'a Query<&Handle<Mesh>>,
|
||||||
|
) -> Vec<(Entity, &'a Mesh)> {
|
||||||
|
if let Ok(children) = children_query.get(parent) {
|
||||||
|
let mut result: Vec<_> = children
|
||||||
|
.iter()
|
||||||
|
.filter_map(|entity| mesh_handles.get(*entity).ok().map(|mesh| (*entity, mesh)))
|
||||||
|
.map(|(entity, mesh_handle)| {
|
||||||
|
(
|
||||||
|
entity,
|
||||||
|
meshes
|
||||||
|
.get(mesh_handle)
|
||||||
|
.expect("Failed to get mesh from handle"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|(entity, mesh)| {
|
||||||
|
assert_eq!(mesh.primitive_topology(), PrimitiveTopology::TriangleList);
|
||||||
|
(entity, mesh)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut inner_result = children
|
||||||
|
.iter()
|
||||||
|
.flat_map(|entity| {
|
||||||
|
Self::search_in_children(*entity, children_query, meshes, mesh_handles)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
result.append(&mut inner_result);
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait F32Ext: Copy {
|
||||||
|
fn is_approx_zero(self) -> bool;
|
||||||
|
fn squared(self) -> f32;
|
||||||
|
fn lerp(self, other: f32, ratio: f32) -> f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl F32Ext for f32 {
|
||||||
|
#[inline]
|
||||||
|
fn is_approx_zero(self) -> bool {
|
||||||
|
self.abs() < 1e-5
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn squared(self) -> f32 {
|
||||||
|
self * self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn lerp(self, other: f32, ratio: f32) -> f32 {
|
||||||
|
self.mul_add(1. - ratio, other * ratio)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait TransformExt: Copy {
|
||||||
|
fn horizontally_looking_at(self, target: Vec3, up: Vec3) -> Transform;
|
||||||
|
fn lerp(self, other: Transform, ratio: f32) -> Transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransformExt for Transform {
|
||||||
|
fn horizontally_looking_at(self, target: Vec3, up: Vec3) -> Transform {
|
||||||
|
let direction = target - self.translation;
|
||||||
|
let horizontal_direction = direction - up * direction.dot(up);
|
||||||
|
let look_target = self.translation + horizontal_direction;
|
||||||
|
self.looking_at(look_target, up)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lerp(self, other: Transform, ratio: f32) -> Transform {
|
||||||
|
let translation = self.translation.lerp(other.translation, ratio);
|
||||||
|
let rotation = self.rotation.slerp(other.rotation, ratio);
|
||||||
|
let scale = self.scale.lerp(other.scale, ratio);
|
||||||
|
Transform {
|
||||||
|
translation,
|
||||||
|
rotation,
|
||||||
|
scale,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
pub mod relationships_insert_dependant_components;
|
||||||
|
pub use relationships_insert_dependant_components::*;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub struct EcsRelationshipsPlugin;
|
||||||
|
impl Plugin for EcsRelationshipsPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub fn insert_dependant_component<
|
||||||
|
Dependant: Component,
|
||||||
|
Dependency: Component + std::default::Default,
|
||||||
|
>(
|
||||||
|
mut commands: Commands,
|
||||||
|
entities_without_depency: Query<(Entity, &Name), (With<Dependant>, Without<Dependency>)>,
|
||||||
|
) {
|
||||||
|
for (entity, name) in entities_without_depency.iter() {
|
||||||
|
let name = name.clone().to_string();
|
||||||
|
commands.entity(entity).insert(Dependency::default());
|
||||||
|
warn!("found an entity called {} with a {} component but without an {}, please check your assets", name.clone(), std::any::type_name::<Dependant>(), std::any::type_name::<Dependency>());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
assets::GameAssets,
|
||||||
|
state::{GameState, InAppRunning},
|
||||||
|
};
|
||||||
|
use bevy_gltf_blueprints::{BluePrintBundle, BlueprintName, GameWorldTag};
|
||||||
|
|
||||||
|
use bevy_rapier3d::prelude::Velocity;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
pub fn setup_game(
|
||||||
|
mut commands: Commands,
|
||||||
|
game_assets: Res<GameAssets>,
|
||||||
|
models: Res<Assets<bevy::gltf::Gltf>>,
|
||||||
|
mut next_game_state: ResMut<NextState<GameState>>,
|
||||||
|
) {
|
||||||
|
println!("setting up all stuff");
|
||||||
|
// here we actually spawn our game world/level
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
SceneBundle {
|
||||||
|
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
||||||
|
scene: models
|
||||||
|
.get(game_assets.world.id())
|
||||||
|
.expect("main level should have been loaded")
|
||||||
|
.scenes[0]
|
||||||
|
.clone(),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
bevy::prelude::Name::from("world"),
|
||||||
|
GameWorldTag,
|
||||||
|
InAppRunning,
|
||||||
|
));
|
||||||
|
|
||||||
|
next_game_state.set(GameState::InGame)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_test(
|
||||||
|
keycode: Res<Input<KeyCode>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
|
||||||
|
mut game_world: Query<(Entity, &Children), With<GameWorldTag>>,
|
||||||
|
) {
|
||||||
|
if keycode.just_pressed(KeyCode::T) {
|
||||||
|
let world = game_world.single_mut();
|
||||||
|
let world = world.1[0];
|
||||||
|
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let range = 5.5;
|
||||||
|
let x: f32 = rng.gen_range(-range..range);
|
||||||
|
let y: f32 = rng.gen_range(-range..range);
|
||||||
|
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let range = 0.8;
|
||||||
|
let vel_x: f32 = rng.gen_range(-range..range);
|
||||||
|
let vel_y: f32 = rng.gen_range(2.0..2.5);
|
||||||
|
let vel_z: f32 = rng.gen_range(-range..range);
|
||||||
|
|
||||||
|
let name_index: u64 = rng.gen();
|
||||||
|
|
||||||
|
let new_entity = commands
|
||||||
|
.spawn((
|
||||||
|
BluePrintBundle {
|
||||||
|
blueprint: BlueprintName("Health_Pickup".to_string()),
|
||||||
|
transform: TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
bevy::prelude::Name::from(format!("test{}", name_index)),
|
||||||
|
// BlueprintName("Health_Pickup".to_string()),
|
||||||
|
// SpawnHere,
|
||||||
|
// TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
|
||||||
|
Velocity {
|
||||||
|
linvel: Vec3::new(vel_x, vel_y, vel_z),
|
||||||
|
angvel: Vec3::new(0.0, 0.0, 0.0),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.id();
|
||||||
|
commands.entity(world).add_child(new_entity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::state::{AppState, GameState, InMainMenu};
|
||||||
|
|
||||||
|
pub fn setup_main_menu(mut commands: Commands) {
|
||||||
|
commands.spawn((Camera2dBundle::default(), InMainMenu));
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
TextBundle::from_section(
|
||||||
|
"SOME GAME TITLE !!",
|
||||||
|
TextStyle {
|
||||||
|
//font: asset_server.load("fonts/FiraMono-Medium.ttf"),
|
||||||
|
font_size: 18.0,
|
||||||
|
color: Color::WHITE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_style(Style {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
top: Val::Px(100.0),
|
||||||
|
left: Val::Px(200.0),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
InMainMenu,
|
||||||
|
));
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
TextBundle::from_section(
|
||||||
|
"New Game (press Enter to start, press T once the game is started for demo spawning)",
|
||||||
|
TextStyle {
|
||||||
|
//font: asset_server.load("fonts/FiraMono-Medium.ttf"),
|
||||||
|
font_size: 18.0,
|
||||||
|
color: Color::WHITE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_style(Style {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
top: Val::Px(200.0),
|
||||||
|
left: Val::Px(200.0),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
InMainMenu,
|
||||||
|
));
|
||||||
|
|
||||||
|
/*
|
||||||
|
commands.spawn((
|
||||||
|
TextBundle::from_section(
|
||||||
|
"Load Game",
|
||||||
|
TextStyle {
|
||||||
|
//font: asset_server.load("fonts/FiraMono-Medium.ttf"),
|
||||||
|
font_size: 18.0,
|
||||||
|
color: Color::WHITE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_style(Style {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
top: Val::Px(250.0),
|
||||||
|
left: Val::Px(200.0),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
InMainMenu
|
||||||
|
));
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
TextBundle::from_section(
|
||||||
|
"Exit Game",
|
||||||
|
TextStyle {
|
||||||
|
//font: asset_server.load("fonts/FiraMono-Medium.ttf"),
|
||||||
|
font_size: 18.0,
|
||||||
|
color: Color::WHITE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_style(Style {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
top: Val::Px(300.0),
|
||||||
|
left: Val::Px(200.0),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
InMainMenu
|
||||||
|
));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn teardown_main_menu(bla: Query<Entity, With<InMainMenu>>, mut commands: Commands) {
|
||||||
|
for bli in bla.iter() {
|
||||||
|
commands.entity(bli).despawn_recursive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main_menu(
|
||||||
|
keycode: Res<Input<KeyCode>>,
|
||||||
|
|
||||||
|
mut next_app_state: ResMut<NextState<AppState>>,
|
||||||
|
// mut next_game_state: ResMut<NextState<GameState>>,
|
||||||
|
// mut save_requested_events: EventWriter<SaveRequest>,
|
||||||
|
// mut load_requested_events: EventWriter<LoadRequest>,
|
||||||
|
) {
|
||||||
|
if keycode.just_pressed(KeyCode::Return) {
|
||||||
|
next_app_state.set(AppState::AppLoading);
|
||||||
|
// next_game_state.set(GameState::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
if keycode.just_pressed(KeyCode::L) {
|
||||||
|
next_app_state.set(AppState::AppLoading);
|
||||||
|
// load_requested_events.send(LoadRequest { path: "toto".into() })
|
||||||
|
}
|
||||||
|
|
||||||
|
if keycode.just_pressed(KeyCode::S) {
|
||||||
|
// save_requested_events.send(SaveRequest { path: "toto".into() })
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
pub mod in_game;
|
||||||
|
pub use in_game::*;
|
||||||
|
|
||||||
|
pub mod in_main_menu;
|
||||||
|
pub use in_main_menu::*;
|
||||||
|
|
||||||
|
pub mod picking;
|
||||||
|
pub use picking::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
insert_dependant_component,
|
||||||
|
state::{AppState, GameState},
|
||||||
|
};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
|
// this file is just for demo purposes, contains various types of components, systems etc
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub enum SoundMaterial {
|
||||||
|
Metal,
|
||||||
|
Wood,
|
||||||
|
Rock,
|
||||||
|
Cloth,
|
||||||
|
Squishy,
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// Demo marker component
|
||||||
|
pub struct Player;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// Demo component showing auto injection of components
|
||||||
|
pub struct ShouldBeWithPlayer;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// Demo marker component
|
||||||
|
pub struct Interactible;
|
||||||
|
|
||||||
|
fn player_move_demo(
|
||||||
|
keycode: Res<Input<KeyCode>>,
|
||||||
|
mut players: Query<&mut Transform, With<Player>>,
|
||||||
|
) {
|
||||||
|
let speed = 0.2;
|
||||||
|
if let Ok(mut player) = players.get_single_mut() {
|
||||||
|
if keycode.pressed(KeyCode::Left) {
|
||||||
|
player.translation.x += speed;
|
||||||
|
}
|
||||||
|
if keycode.pressed(KeyCode::Right) {
|
||||||
|
player.translation.x -= speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if keycode.pressed(KeyCode::Up) {
|
||||||
|
player.translation.z += speed;
|
||||||
|
}
|
||||||
|
if keycode.pressed(KeyCode::Down) {
|
||||||
|
player.translation.z -= speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collision tests/debug
|
||||||
|
pub fn test_collision_events(
|
||||||
|
mut collision_events: EventReader<CollisionEvent>,
|
||||||
|
mut contact_force_events: EventReader<ContactForceEvent>,
|
||||||
|
) {
|
||||||
|
for collision_event in collision_events.read() {
|
||||||
|
println!("collision");
|
||||||
|
match collision_event {
|
||||||
|
CollisionEvent::Started(_entity1, _entity2, _) => {
|
||||||
|
println!("collision started")
|
||||||
|
}
|
||||||
|
CollisionEvent::Stopped(_entity1, _entity2, _) => {
|
||||||
|
println!("collision ended")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for contact_force_event in contact_force_events.read() {
|
||||||
|
println!("Received contact force event: {:?}", contact_force_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GamePlugin;
|
||||||
|
impl Plugin for GamePlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_plugins(PickingPlugin)
|
||||||
|
.register_type::<Interactible>()
|
||||||
|
.register_type::<SoundMaterial>()
|
||||||
|
.register_type::<Player>()
|
||||||
|
// little helper utility, to automatically inject components that are dependant on an other component
|
||||||
|
// ie, here an Entity with a Player component should also always have a ShouldBeWithPlayer component
|
||||||
|
// you get a warning if you use this, as I consider this to be stop-gap solution (usually you should have either a bundle, or directly define all needed components)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
// insert_dependant_component::<Player, ShouldBeWithPlayer>,
|
||||||
|
player_move_demo, //.run_if(in_state(AppState::Running)),
|
||||||
|
// test_collision_events
|
||||||
|
spawn_test,
|
||||||
|
)
|
||||||
|
.run_if(in_state(GameState::InGame)),
|
||||||
|
)
|
||||||
|
.add_systems(OnEnter(AppState::MenuRunning), setup_main_menu)
|
||||||
|
.add_systems(OnExit(AppState::MenuRunning), teardown_main_menu)
|
||||||
|
.add_systems(Update, main_menu.run_if(in_state(AppState::MenuRunning)))
|
||||||
|
.add_systems(OnEnter(AppState::AppRunning), setup_game);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
use super::Player;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_gltf_blueprints::GltfBlueprintsSet;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct Pickable;
|
||||||
|
|
||||||
|
// very simple, crude picking (as in picking up objects) implementation
|
||||||
|
|
||||||
|
pub fn picking(
|
||||||
|
players: Query<&GlobalTransform, With<Player>>,
|
||||||
|
pickables: Query<(Entity, &GlobalTransform), With<Pickable>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for player_transforms in players.iter() {
|
||||||
|
for (pickable, pickable_transforms) in pickables.iter() {
|
||||||
|
let distance = player_transforms
|
||||||
|
.translation()
|
||||||
|
.distance(pickable_transforms.translation());
|
||||||
|
if distance < 2.5 {
|
||||||
|
commands.entity(pickable).despawn_recursive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PickingPlugin;
|
||||||
|
impl Plugin for PickingPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.register_type::<Pickable>()
|
||||||
|
.add_systems(Update, (picking.after(GltfBlueprintsSet::AfterSpawn),));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_editor_pls::prelude::*;
|
||||||
|
|
||||||
|
mod core;
|
||||||
|
use crate::core::*;
|
||||||
|
|
||||||
|
pub mod assets;
|
||||||
|
use assets::*;
|
||||||
|
|
||||||
|
pub mod state;
|
||||||
|
use state::*;
|
||||||
|
|
||||||
|
mod game;
|
||||||
|
use game::*;
|
||||||
|
|
||||||
|
mod test_components;
|
||||||
|
use test_components::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins((
|
||||||
|
DefaultPlugins.set(AssetPlugin::default()),
|
||||||
|
// editor
|
||||||
|
EditorPlugin::default(),
|
||||||
|
// our custom plugins
|
||||||
|
StatePlugin,
|
||||||
|
AssetsPlugin,
|
||||||
|
CorePlugin, // reusable plugins
|
||||||
|
GamePlugin, // specific to our game
|
||||||
|
ComponentsTestPlugin, // Showcases different type of components /structs
|
||||||
|
))
|
||||||
|
.run();
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
use bevy::app::AppExit;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default, States)]
|
||||||
|
pub enum AppState {
|
||||||
|
#[default]
|
||||||
|
CoreLoading,
|
||||||
|
MenuRunning,
|
||||||
|
AppLoading,
|
||||||
|
AppRunning,
|
||||||
|
AppEnding,
|
||||||
|
|
||||||
|
// FIXME: not sure
|
||||||
|
LoadingGame,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default, States)]
|
||||||
|
pub enum GameState {
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
|
||||||
|
InMenu,
|
||||||
|
InGame,
|
||||||
|
|
||||||
|
InGameOver,
|
||||||
|
|
||||||
|
InSaving,
|
||||||
|
InLoading,
|
||||||
|
}
|
||||||
|
|
||||||
|
// tag components for all entities within a certain state (for despawning them if needed) , FIXME: seems kinda hack-ish
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct InCoreLoading;
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct InMenuRunning;
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct InAppLoading;
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct InAppRunning;
|
||||||
|
|
||||||
|
// components for tagging in game vs in game menu stuff
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct InMainMenu;
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct InMenu;
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct InGame;
|
||||||
|
|
||||||
|
pub struct StatePlugin;
|
||||||
|
impl Plugin for StatePlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_state::<AppState>().add_state::<GameState>();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct UnitTest;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug, Deref, DerefMut)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct TuppleTestF32(f32);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug, Deref, DerefMut)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct TuppleTestU64(u64);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug, Deref, DerefMut)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct TuppleTestStr(String);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct TuppleTest2(f32, u64, String);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct TuppleTestBool(bool);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct TuppleVec2(Vec2);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct TuppleVec3(Vec3);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct TuppleVec(Vec<String>);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct TuppleTestColor(Color);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct BasicTest {
|
||||||
|
a: f32,
|
||||||
|
b: u64,
|
||||||
|
c: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub enum EnumTest {
|
||||||
|
Metal,
|
||||||
|
Wood,
|
||||||
|
Rock,
|
||||||
|
Cloth,
|
||||||
|
Squishy,
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ComponentsTestPlugin;
|
||||||
|
impl Plugin for ComponentsTestPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.register_type::<BasicTest>()
|
||||||
|
.register_type::<UnitTest>()
|
||||||
|
.register_type::<TuppleTestF32>()
|
||||||
|
.register_type::<TuppleTestU64>()
|
||||||
|
.register_type::<TuppleTestStr>()
|
||||||
|
.register_type::<TuppleTestBool>()
|
||||||
|
.register_type::<TuppleTest2>()
|
||||||
|
.register_type::<TuppleVec2>()
|
||||||
|
.register_type::<TuppleVec3>()
|
||||||
|
.register_type::<EnumTest>()
|
||||||
|
.register_type::<TuppleTestColor>()
|
||||||
|
.register_type::<TuppleVec>()
|
||||||
|
.register_type::<Vec<String>>();
|
||||||
|
}
|
||||||
|
}
|
@ -44,6 +44,9 @@ This [Blender addon](./)
|
|||||||
|
|
||||||
|
|
||||||
- export folder: root folder to export models too
|
- export folder: root folder to export models too
|
||||||
|
- export scene settings: exports "global"/scene settings like ambient color, bloom, ao, etc
|
||||||
|
|
||||||
|
This automatically generates additional components at the scene level
|
||||||
- pick your main (level) scenes and library scenes (see the chapter about Blueprints below)
|
- pick your main (level) scenes and library scenes (see the chapter about Blueprints below)
|
||||||
- click in the scene picker & select your scene
|
- click in the scene picker & select your scene
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "gltf_auto_export",
|
"name": "gltf_auto_export",
|
||||||
"author": "kaosigh",
|
"author": "kaosigh",
|
||||||
"version": (0, 6, 0),
|
"version": (0, 7, 0),
|
||||||
"blender": (3, 4, 0),
|
"blender": (3, 4, 0),
|
||||||
"location": "File > Import-Export",
|
"location": "File > Import-Export",
|
||||||
"description": "glTF/glb auto-export",
|
"description": "glTF/glb auto-export",
|
||||||
|
@ -7,6 +7,8 @@ from .helpers_collections import (get_exportable_collections, get_collections_pe
|
|||||||
from .helpers_export import (export_main_scene, export_blueprints_from_collections)
|
from .helpers_export import (export_main_scene, export_blueprints_from_collections)
|
||||||
from .helpers import (check_if_blueprints_exist, check_if_blueprint_on_disk)
|
from .helpers import (check_if_blueprints_exist, check_if_blueprint_on_disk)
|
||||||
from .materials import cleanup_materials, clear_material_info, clear_materials_scene, export_materials, generate_materials_scenes, get_all_materials
|
from .materials import cleanup_materials, clear_material_info, clear_materials_scene, export_materials, generate_materials_scenes, get_all_materials
|
||||||
|
from .scene_components import upsert_scene_components
|
||||||
|
|
||||||
from .config import scene_key
|
from .config import scene_key
|
||||||
|
|
||||||
"""Main function"""
|
"""Main function"""
|
||||||
@ -46,6 +48,8 @@ def auto_export(changes_per_scene, changed_export_parameters):
|
|||||||
print("error setting preferences from saved settings", error)
|
print("error setting preferences from saved settings", error)
|
||||||
bpy.context.window_manager['__gltf_auto_export_initialized'] = True
|
bpy.context.window_manager['__gltf_auto_export_initialized'] = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# have the export parameters (not auto export, just gltf export) have changed: if yes (for example switch from glb to gltf, compression or not, animations or not etc), we need to re-export everything
|
# have the export parameters (not auto export, just gltf export) have changed: if yes (for example switch from glb to gltf, compression or not, animations or not etc), we need to re-export everything
|
||||||
print ("changed_export_parameters", changed_export_parameters)
|
print ("changed_export_parameters", changed_export_parameters)
|
||||||
try:
|
try:
|
||||||
@ -58,12 +62,18 @@ def auto_export(changes_per_scene, changed_export_parameters):
|
|||||||
export_output_folder = getattr(addon_prefs,"export_output_folder")
|
export_output_folder = getattr(addon_prefs,"export_output_folder")
|
||||||
|
|
||||||
export_materials_library = getattr(addon_prefs,"export_materials_library")
|
export_materials_library = getattr(addon_prefs,"export_materials_library")
|
||||||
|
export_scene_settings = getattr(addon_prefs,"export_scene_settings")
|
||||||
|
|
||||||
|
|
||||||
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
|
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
|
||||||
|
|
||||||
print("main scenes", main_scene_names, "library_scenes", library_scene_names)
|
print("main scenes", main_scene_names, "library_scenes", library_scene_names)
|
||||||
print("export_output_folder", export_output_folder)
|
print("export_output_folder", export_output_folder)
|
||||||
|
|
||||||
|
if export_scene_settings:
|
||||||
|
# inject/ update scene components
|
||||||
|
upsert_scene_components(bpy.context.scene, world = bpy.context.scene.world)
|
||||||
|
|
||||||
# export everything everytime
|
# export everything everytime
|
||||||
if export_blueprints:
|
if export_blueprints:
|
||||||
print("EXPORTING")
|
print("EXPORTING")
|
||||||
@ -125,7 +135,8 @@ def auto_export(changes_per_scene, changed_export_parameters):
|
|||||||
# first export any main/level/world scenes
|
# first export any main/level/world scenes
|
||||||
print("export MAIN scenes")
|
print("export MAIN scenes")
|
||||||
for scene_name in main_scene_names:
|
for scene_name in main_scene_names:
|
||||||
do_export_main_scene = changed_export_parameters or (scene_name in changes_per_scene.keys() and len(changes_per_scene[scene_name].keys()) > 0) or not check_if_blueprint_on_disk(scene_name, export_levels_path, gltf_extension)
|
# we have more relaxed rules to determine if the main scenes have changed : any change is ok, (allows easier handling of changes, render settings etc)
|
||||||
|
do_export_main_scene = changed_export_parameters or scene_name in changes_per_scene.keys() or not check_if_blueprint_on_disk(scene_name, export_levels_path, gltf_extension)
|
||||||
if do_export_main_scene:
|
if do_export_main_scene:
|
||||||
print(" exporting scene:", scene_name)
|
print(" exporting scene:", scene_name)
|
||||||
export_main_scene(bpy.data.scenes[scene_name], folder_path, addon_prefs, collections)
|
export_main_scene(bpy.data.scenes[scene_name], folder_path, addon_prefs, collections)
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@ -54,6 +54,13 @@ class AutoExportGltfAddonPreferences(AddonPreferences):
|
|||||||
description='The name of the library scene to auto export',
|
description='The name of the library scene to auto export',
|
||||||
default='Library'
|
default='Library'
|
||||||
)
|
)
|
||||||
|
# scene components
|
||||||
|
export_scene_settings: BoolProperty(
|
||||||
|
name='Export scene settings',
|
||||||
|
description='Export scene settings ie AmbientLighting, Bloom, AO etc',
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
# blueprint settings
|
# blueprint settings
|
||||||
export_blueprints: BoolProperty(
|
export_blueprints: BoolProperty(
|
||||||
name='Export Blueprints',
|
name='Export Blueprints',
|
||||||
|
67
tools/gltf_auto_export/scene_components.py
Normal file
67
tools/gltf_auto_export/scene_components.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import bpy
|
||||||
|
from .helpers import make_empty3
|
||||||
|
# helpers to export scene level data
|
||||||
|
|
||||||
|
def upsert_scene_components(scene, world):
|
||||||
|
|
||||||
|
lighting_components = None
|
||||||
|
for object in scene.objects:
|
||||||
|
if object.name == "lighting_components":
|
||||||
|
lighting_components = object
|
||||||
|
break
|
||||||
|
|
||||||
|
if lighting_components is None:
|
||||||
|
lighting_components = make_empty3('lighting_components', [0,0,0], [0,0,0], [0,0,0], None)
|
||||||
|
|
||||||
|
if world is not None:
|
||||||
|
lighting_components['AmbientLightSettings'] = ambient_color_to_component(world)
|
||||||
|
|
||||||
|
lighting_components['ShadowmapSettings'] = scene_shadows_to_component(scene)
|
||||||
|
|
||||||
|
|
||||||
|
if scene.eevee.use_bloom:
|
||||||
|
lighting_components['BloomSettings'] = scene_bloom_to_component(scene)
|
||||||
|
elif 'BloomSettings' in lighting_components:
|
||||||
|
del lighting_components['BloomSettings']
|
||||||
|
|
||||||
|
if scene.eevee.use_gtao:
|
||||||
|
lighting_components['SSAOSettings'] = scene_ao_to_component(scene)
|
||||||
|
elif 'SSAOSettings' in lighting_components:
|
||||||
|
del lighting_components['SSAOSettings']
|
||||||
|
|
||||||
|
|
||||||
|
def ambient_color_to_component(world):
|
||||||
|
color = None
|
||||||
|
strength = None
|
||||||
|
try:
|
||||||
|
color = world.node_tree.nodes['Background'].inputs[0].default_value
|
||||||
|
strength = world.node_tree.nodes['Background'].inputs[1].default_value
|
||||||
|
except Exception as ex:
|
||||||
|
print("failed to parse ambient color: Only backgroud is supported")
|
||||||
|
|
||||||
|
|
||||||
|
if color is not None and strength is not None:
|
||||||
|
#print("color", color[0], color[1], color[2], color[3])
|
||||||
|
# print("strength", strength)
|
||||||
|
|
||||||
|
colorRgba = "Rgba(red: "+ str(color[0]) + ", green: "+ str(color[1]) + ", blue: " + str(color[2]) + ", alpha: "+ str(color[3]) + ")" # TODO: YIKES clean this up
|
||||||
|
#colorRgba = "Rgba(red: 0.0, green: 0.0, blue:0.0, alpha:0.0)"
|
||||||
|
component = "( color:"+ str(colorRgba) +", brightness:"+str(strength)+")"
|
||||||
|
|
||||||
|
print("component", component)
|
||||||
|
return component
|
||||||
|
return None
|
||||||
|
|
||||||
|
def scene_shadows_to_component(scene):
|
||||||
|
cascade_resolution = scene.eevee.shadow_cascade_size
|
||||||
|
component = "(size: "+ cascade_resolution +")"
|
||||||
|
return component
|
||||||
|
|
||||||
|
def scene_bloom_to_component(scene):
|
||||||
|
component = "BloomSettings(intensity: "+ str(scene.eevee.bloom_intensity) +")"
|
||||||
|
return component
|
||||||
|
|
||||||
|
def scene_ao_to_component(scene):
|
||||||
|
ssao = scene.eevee.use_gtao
|
||||||
|
component= "SSAOSettings()"
|
||||||
|
return component
|
@ -203,6 +203,7 @@ class GLTF_PT_auto_export_root(bpy.types.Panel):
|
|||||||
layout.active = operator.auto_export
|
layout.active = operator.auto_export
|
||||||
layout.prop(operator, 'will_save_settings')
|
layout.prop(operator, 'will_save_settings')
|
||||||
layout.prop(operator, "export_output_folder")
|
layout.prop(operator, "export_output_folder")
|
||||||
|
layout.prop(operator, "export_scene_settings")
|
||||||
|
|
||||||
# scene selectors
|
# scene selectors
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
|
Loading…
Reference in New Issue
Block a user