Merge branch 'blenvy' of github.com:kaosat-dev/Blender_bevy_components_worklflow into blenvy

This commit is contained in:
kaosat.dev 2024-08-07 01:39:24 +02:00
commit c4d8e02a9d
52 changed files with 803 additions and 30 deletions

View File

@ -2,7 +2,7 @@
[![License](https://img.shields.io/crates/l/blenvy)](https://github.com/kaosat-dev/Blenvy/blob/main/LICENSE.md) [![License](https://img.shields.io/crates/l/blenvy)](https://github.com/kaosat-dev/Blenvy/blob/main/LICENSE.md)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/F1F5TO32O) [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/F1F5TO32O)
# BLENVY: a friendly Blender <=> Bevy workflow ! # BLENVY: a friendly Blender <=> Bevy workflow
![demo](./docs/blender_bevy.png) ![demo](./docs/blender_bevy.png)
@ -13,6 +13,10 @@ inside Blender. Aka "Blender as editor for Bevy"
It also allows you to setup 'blueprints' in Blender by using collections (the recomended way to go most of the time), or directly on single use objects . It also allows you to setup 'blueprints' in Blender by using collections (the recomended way to go most of the time), or directly on single use objects .
## Quickstart
Want to jump right in? See the [quickstart guide](./docs/quickstart/readme.md) for how to setup a basic project as fast as possible.
## Features ## Features
* Useful if you want to use Blender as your Editor * Useful if you want to use Blender as your Editor
@ -23,7 +27,7 @@ It also allows you to setup 'blueprints' in Blender by using collections (the re
* automatically load all assets for each blueprint (gltf files, manually added assets), with no setup required * automatically load all assets for each blueprint (gltf files, manually added assets), with no setup required
* hot reload of your levels & blueprints * hot reload of your levels & blueprints
* minimal setup & code, you can have something basic running fast * minimal setup & code, you can have something basic running fast
* minimal dependencies: Bevy, Serde & Ron only ! * minimal dependencies: Bevy, Serde & RON only!
* opensource * opensource
> If you were previously using the individual bevy_gltf_xxx crates & Blender add-ons please see the [migration guide](./Migration_guide.md) > If you were previously using the individual bevy_gltf_xxx crates & Blender add-ons please see the [migration guide](./Migration_guide.md)
@ -32,11 +36,11 @@ It also allows you to setup 'blueprints' in Blender by using collections (the re
One crate to rule them all ! One crate to rule them all !
- [blenvy](./crates/blenvy/) This crate allows you to * [blenvy](./crates/blenvy/) This crate allows you to
* define components direclty inside gltf files and instanciate/inject the components on the Bevy side. * define components direclty inside gltf files and instanciate/inject the components on the Bevy side.
* export your project's Bevy registry to json, in order to be able to generate custom component UIs on the Blender side in the Blender [blenvy](./tools/blenvy/README.md) add-on * export your project's Bevy registry to json, in order to be able to generate custom component UIs on the Blender side in the Blender [blenvy](./tools/blenvy/README.md) add-on
* define Blueprints/Prefabs for Bevy inside gltf files and spawn them in Bevy. With the ability to override and add components when spawning, efficient "level" loading etc * define Blueprints/Prefabs for Bevy inside gltf files and spawn them in Bevy. With the ability to override and add components when spawning, efficient "level" loading etc
* the ability to save & load your game state in a relatively simple way, by leveraging the blueprint functionality to only save a minimal subset of dynamic data, seperating dynamic & static parts of levels etc. * the ability to save & load your game state in a relatively simple way, by leveraging the blueprint functionality to only save a minimal subset of dynamic data, seperating dynamic & static parts of levels etc.
OLD videos: OLD videos:
There is a [video tutorial/explanation](https://youtu.be/-lcScjQCA3c) if you want, or you can read the crate docs. There is a [video tutorial/explanation](https://youtu.be/-lcScjQCA3c) if you want, or you can read the crate docs.
@ -48,10 +52,10 @@ One crate to rule them all !
### Blender: blenvy ### Blender: blenvy
- an all in one [Blender addon](./tools/blenvy/README.md) for the Blender side of the workflow: * an all in one [Blender addon](./tools/blenvy/README.md) for the Blender side of the workflow:
- allow easilly adding & editing Bevy components , using automatically generated UIs for each component * allow easilly adding & editing Bevy components , using automatically generated UIs for each component
- automatically exports your level/world from Blender to gltf whenever you save your Blend file * automatically exports your level/world from Blender to gltf whenever you save your Blend file
- automatically export your [Gltf blueprints](./crates/blenvy/README.md) & assets * automatically export your [Gltf blueprints](./crates/blenvy/README.md) & assets
## Examples ## Examples
@ -67,37 +71,42 @@ you can find all examples, [here](./examples/blenvy)
The workflow goes as follows (once you got your Bevy code setup) The workflow goes as follows (once you got your Bevy code setup)
* create & register all your components you want to be able to set from the Blender side (this is basic Bevy, no specific work needed)
- create & register all your components you want to be able to set from the Blender side (this is basic Bevy, no specific work needed)
![component registration](./docs/component_registration.png) ![component registration](./docs/component_registration.png)
- setup & then use the Blenvy [Bevy crate](./crates/blenvy/README.md) * setup & then use the Blenvy [Bevy crate](./crates/blenvy/README.md)
- setup & then use the Blenvy [Blender add-on](./tools/blenvy/README.md) * setup & then use the Blenvy [Blender add-on](./tools/blenvy/README.md)
- iterate * iterate
- have fun ! * have fun !
- then add your components to objects in Blender **with a nice UI** see [here](./README-workflow-ui.md) for more details * then add your components to objects in Blender **with a nice UI** see [here](./README-workflow-ui.md) for more details
See the [quickstart](./docs/quickstart/readme.md) for a full step-by-step guide.
## Third Party Integration
Read about the [Avian Physics Integration](docs/avian/readme.md) to learn how to setup colliders in Blender that will be used by the Avian physics engine in Bevy.
## Limitations / issues ## Limitations / issues
- Some of `avian` or `bevy_rapier` /physics code / ways to define colliders could perhaps be done better/visually within Blender * Some of `avian` or `bevy_rapier` /physics code / ways to define colliders could perhaps be done better/visually within Blender
## Contributors ## Contributors
Thanks to all the contributors helping out with this project ! Big kudos to you, contributions are always appreciated ! :) Thanks to all the contributors helping out with this project ! Big kudos to you, contributions are always appreciated ! :)
- [GitGhillie](https://github.com/GitGhillie) * [GitGhillie](https://github.com/GitGhillie)
- [Azorlogh](https://github.com/Azorlogh) * [Azorlogh](https://github.com/Azorlogh)
- [BSDGuyShawn](https://github.com/BSDGuyShawn) * [BSDGuyShawn](https://github.com/BSDGuyShawn)
- [yukkop](https://github.com/yukkop) * [yukkop](https://github.com/yukkop)
- [killercup](https://github.com/killercup) * [killercup](https://github.com/killercup)
- [janhohenheim ](https://github.com/janhohenheim) * [janhohenheim](https://github.com/janhohenheim)
- [BUGO07](https://github.com/BUGO07) * [BUGO07](https://github.com/BUGO07)
## License ## License
This repo, all its code, contents & assets is Dual-licensed under either of This repo, all its code, contents & assets is Dual-licensed under either of
- Apache License, Version 2.0, ([LICENSE-APACHE](./LICENSE_APACHE.md) or https://www.apache.org/licenses/LICENSE-2.0) * Apache License, Version 2.0, ([LICENSE-APACHE](./LICENSE_APACHE.md) or <https://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](./LICENSE_MIT.md) or https://opensource.org/licenses/MIT) * MIT license ([LICENSE-MIT](./LICENSE_MIT.md) or <https://opensource.org/licenses/MIT>)

BIN
docs/avian/img/board.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
docs/avian/img/data.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
docs/avian/img/dynamic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
docs/avian/img/falling.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
docs/avian/img/hiding.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
docs/avian/img/torus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

446
docs/avian/readme.md Normal file
View File

@ -0,0 +1,446 @@
# Avian Physics Integration
This guide assumes that you have a basic Blenvy setup ready to tinker in.
If you don't have that yet, please refer to the [quickstart](../quickstart/readme.md) guide.
## Table of Contents
- [Add Avian to Bevy](#add-avian-to-bevy)
- [Prepare your Scenes](#prepare-your-scenes)
- [Create a Rigid Body](#create-a-rigid-body)
- [Add Primitive Colliders](#add-primitive-colliders)
- [Direct](#direct)
- [With Empty](#with-empty)
- [Wireframes](#wireframes)
- [Add Dynamic Colliders](#add-dynamic-colliders)
- [Convex](#convex)
- [Concave](#concave)
- [Other useful components](#other-useful-components)
## Add Avian to Bevy
No big surprises here. Simply add `avian3d` as a dependency by running the following from your project root:
```sh
cargo add avian3d
```
Then, where you add plugins to your Bevy app, add the `PhysicsPlugins::default()`.
The most basic `main.rs` that contains a full setup looks like this:
```rust
use avian3d::prelude::*;
use bevy::prelude::*;
use blenvy::*;
fn main() -> AppExit {
App::new()
.add_plugins((
DefaultPlugins,
BlenvyPlugin::default(),
PhysicsPlugins::default(),
))
.add_systems(Startup, setup)
.run()
}
fn setup(mut commands: Commands) {
commands.spawn((
BlueprintInfo::from_path("levels/World.glb"),
SpawnBlueprint,
HideUntilReady,
GameWorldTag,
));
}
```
Run this once with `cargo.run` to generate a `registry.json` that contains the Avian components.
## Prepare your Scenes
Set up your `World` and `Library` scenes in Blender.
Go into your `World` scene. If you are coming from the [quickstart guide](../quickstart/readme.md), you can remove the `Player` instance as we don't need it in this guide.
If you have created this scene yourself in advance, make sure that it contains a camera, a light, and some kind of ground.
Since the objects are quite big, you may need to move the camera a bit further away to see them all.
We set its Y location to `-15` and the X rotation to `90` for this reason.
Pressing `0` on your numpad will show you a preview of what the camera sees.
For reference, this is how our world setup looks:
<details>
<summary>The world setup before adding any physics</summary>
<img src="img/empty_world.png" width = 100%/>
</details>
Now switch to the `Library` scene.
If you're coming from the [quickstart](../quickstart/readme.md) guide, you may now delete the `Player` collection by
right-clicking it in the outliner and selecting `Delete Hierarchy`.
Remember, you can find the outliner all the way to the right.
## Create a Rigid Body
Create a new collection with `rightclick` -> `New Collection` and name it `Direct`. This name will make sense in the next section.
Click on the `Direct` collection we just created to select it. Then, go to `Add` -> `Mesh` -> `Cube` in the upper left corner to add a cube to the collection. Leave it at the default transform.
Avian makes a distinction between a *rigid body* and its associated *colliders*.
In general, the best practice is to have a parent object be a rigid body and then have at least one descendant object be a collider.
Add the `RigidBody` as follows:
- select the collection named `Direct` in the outliner.
- go to the Blenvy menu's component manager. Remember, if are missing the side menu, you can open it with `N`.
- type `rigidbody` in the search bar
- select `avian3d::dynamics::rigid_body::RigidBody`
- add it
> [!TIP]
> If you do not see `avian3d::dynamics::rigid_body::RigidBody` in the list of components, make sure you have run a `cargo run` after the `PhysicsPlugins::default()` was added to your Bevy app as described above.
> If you still do not see the component, manually refresh the registry as described in the [quickstart section "Create a blueprint"](../quickstart/readme.md#create-a-blueprint).
The result should look like this:
<details>
<summary>A rigid body on the cube</summary>
<img src="img/dynamic.png" width = 50%/>
</details>
The default value for `RigidBody` is `Dynamic`, which is what we want for all three objects.
It means that they will be affected by gravity and other forces.
## Add Primitive Colliders
Colliders come in two flavors: primitive and dynamic. Primitives are made up of simple shapes like cubes, spheres, and cylinders. Dynamic colliders are created at runtime from the mesh of the object they are attached to. In general, it is *way* more efficient to use primitives and placing them manually. You may think that this is a lot of work, but usually you can get away with a very rough more or less boxy shape. We will show you how this approach first.
There are three different ways to add primitive colliders to the objects, in order of increasing complexity.
### Direct
Select the collection named `Direct` and search in the component manager for `colliderconstructor`.
Select `avian3d::collision::collider::constructor::ColliderConstructor` and add it.
By default, the collider will be of the variant `Sphere`. Change it to `Cuboid`.
Since the standard cube in Blender is of size 2 m, set the `x_length`, `y_length`, and `z_length` all to `2.0`:
<details>
<summary>A collider on the cube</summary>
<img src="img/cube_primitive.png" width = 50%/>
</details>
That's already it.
> [!CAUTION]
> This method brings a major footgun: Blender uses Z-up coordinates, while Bevy uses Y-up coordinates.
> The information you enter into the `ColliderConstructor` is in Bevy's coordinate system, so don't mix them up!
To see it in action, we switch to the `World` scene and add and instance of our `Direct` collection with `Add` -> `Collection Instance`.
<details>
<summary>The world scene with the direct collider cube</summary>
<img src="img/direct_in_world.png" width = 50%/>
</details>
Save the scene to let Blenvy export everything and run the game with `cargo run`.
<details>
<summary>The cube falls down</summary>
<img src="img/falling_direct.gif" width = 50%/>
</details>
If everything went right, your cube should fall into the void due to gravity.
Note that it phases right through the ground because we have not yet added a rigid body and collider to it yet.
Click on the ground object and add a `RigidBody` component as described before to it, but this time set it to `Static`.
This means that the ground itself will not react to forces such as gravity, but will still affect other rigid bodies.
Note that since we are not working with a blueprint here, you'll need to add the component to the object itself rather than a collection.
Also add a collider to the ground as before. Make sure that the dimensions of the collider match the dimensions of the ground.
<details>
<summary>Ground collider</summary>
<img src="img/ground collider.png" width = 100%/>
</details>
> [!CAUTION]
> As mentioned before, when using this method you should be aware that the component
> is in Bevy's coordinate system, so set the `y_length` to the *height* of the ground.
Run your game again with `cargo run` to see the cube landing on the ground.
<details>
<summary>The cube falls onto the ground</summary>
<img src="img/falling_direct_on_static.gif" width = 50%/>
</details>
> [!TIP]
> If your scene is doing something weird, try adding Avian's
> [`PhysicsDebugPlugin`](https://docs.rs/avian3d/latest/avian3d/debug_render/struct.PhysicsDebugPlugin.html)
> to your Bevy app to see the colliders at runtime.
> If the collider looks flipped, try switching the Y and Z lengths.
### With Empty
You'll notice that the last variant does not actually show you a preview of the collider. Let's fix that.
Go back to the `Library` scene. Add a collection named `With Empty`.
> [!TIP]
> If you accidentally created a collection as a child of another, simply drag-and-drop them around to reorder them
Click on the `With Empty` collection to select it. Add a `RigidBody` to it as described before, but do not add a collider to it.
With the new collection selected, go to `Add` -> `Mesh` -> `Cube`. Name the new object `Board`.
This time, scale it until it looks like a flat board:
<details>
<summary>The board in Blender</summary>
<img src="img/board.png" width = 50%/>
</details>
> [!TIP]
> The above screenshot was made after disabling the visibility of the `Direct` collection by clicking the eye icon in the outliner.
>
> <details>
> <summary>Hiding objects</summary>
> <img src="img/hiding.png" width = 50%/>
> </details>
>
> Hiding other collections becomes quickly essential when working with blueprints.
The scaling we used was the following:
- X: `2.5`
- Y: `0.5`
- Z: `1.5`
Now spawn an [*empty*](https://docs.blender.org/manual/en/latest/modeling/empties.html) with `Add` -> `Empty` -> `Cube`.
To make its properties a bit nice to work with, go to the `Data` tab of the `Properties` window in the lower right:
<details>
<summary>Where to find the data tab</summary>
<img src="img/data.png" width = 50%/>
</details>
You'll notice that it says "Size: 1m". This is a little bit misleading, as we've seen before, since the default cube is actually 2x2x2. The "Size" actually refers to the half-extent of the cube. Set it to `0.5` to make the cube a nice 1x1x1 cube.
<details>
<summary>Where to find the data tab</summary>
<img src="img/data.png" width = 50%/>
</details>
Select the empty in the outliner and add collider to this empty like you did in the ["Direct" section](#direct).
Note that you are now adding the collider to the empty itself, not the overarching collection.
Set the cuboid collider's lengths to `1` this time.
If you have only the `Empty` set to visible and selected it, your viewport should now look as follows:
<details>
<summary>The empty with the right size and collider</summary>
<img src="img/empty_selected.png" width = 50%/>
</details>
The important bit to realize here is that the empty's outlines perferctly match the attached collider's size.
Now, drag and drop the empty into the `With Empty` collection. With the empty selected, hold `CTRL` and select the `Board` object.
> [!IMPORTANT]
> It is essential that you *first* select the `Empty` and *then* select the `Board`. The order is key!
With both objects selected, press `CTRL P` to bring up the parenting menu:
<details>
<summary>The screen after creating a new empty</summary>
<img src="img/parenting.png" width = 50%/>
</details>
> [!NOTE]
> Note how the color-coding in the screenshot above shows how `Board` has been selected last.
> Make sure this looks the same on your screen.
In the popup, select the first option, namely `Object`. If everything went right, you should be able to "fold open" the `Board` to find your `Empty` as a child in there:
<details>
<summary>The board is the parent of the empty</summary>
<img src="img/empty_child.png" width = 50%/>
</details>
This hierarchy will exported to Bevy as well!
After this setup, we now have visible collider outlines that we can freely transform. Simply select the empty and transform it however you want. Whatever you do with this empty, the collider generated by Avian will look exactly like the outlines visible in Blender.
While you could (and sometimes should) scale this manually, there is a nice way of finding the right scale. Click on the `Board` object. Then, in the side menu, head to the `Item` tab. Check out the `Dimensions` reported there:
<details>
<summary>The dimensionality of the board</summary>
<img src="img/dimensions.png" width = 50%/>
</details>
> [!TIP]
> If you are not seeing this screen, you have probably clicked on the `With Empty` collection, and not on the item within it.
As you can see, its dimensions are:
- X: `5`
- Y: `1`
- Z: `3`
You can just use these values as the scale for the `Empty`. After everything is done, your final object should look like this in the viewport, when only the `Board` and its children are visible:
<details>
<summary>Finished board</summary>
<img src="img/empty_scaled.png" width = 100%/>
</details>
Note that the orange collider outlines should align nicely with the board's mesh.
Add an instance of the `With Empty` collection to the `World` scene just as before and run the game.
You should now see both objects fall to the ground.
<details>
<summary>The cube and board falling to the ground</summary>
<img src="img/falling_empty.gif" width = 50%/>
</details>
### Wireframes
Add a new collection named `Wireframe`. With it selected, add a `RigidBody` to it.
Then go to `Add` -> `Mesh` -> `Cylinder`. Leave it at the default transform.
The last variant is a bit of a workaround for the fact that empties in Blender cannot have an arbitrary shape.
For example, a cylinder is not supported. So, we are going to create a new cylinder preview by hand.
Click on `Add` -> `Mesh` -> `Cylinder`. Don't click away yet!
Right after you create an object in Blender, you can modify how it should be generated. In the lower left, you should see the following popup:
<details>
<summary>Post-creation popup</summary>
<img src="img/create_cylinder.png" width = 50%/>
</details>
> [!NOTE]
> If you cannot see this popup, you cae changed Blender's focus after creating the object.
> You have to remove the cylinder and recreate it again.
Open up the popup to reveal a menu with some options for how to create a cylinder.
To again have a collider that nicely fits into a 1x1x1 space, set the `Radius` to `0.5` and the `Depth` to `1`.
To improve performance in Blender, you can also reduce the vertices, but this is not really important until you have hundreds of these colliders.
<details>
<summary>Settings for the cylinder</summary>
<img src="img/create_cylinder_options.png" width = 50%/>
</details>
Hide everything except the newly created cylinder. Press `Tab` to enter the edit mode. Press `A` to select all vertices.
Press `X` to open the deletion menu. Select `Only Faces`. Press `Tab` again to go back into object mode.
You should now have the wireframe of a cylinder.
<details>
<summary>Wireframe</summary>
<img src="img/wireframe.png" width = 50%/>
</details>
Now add a `ColliderConstructor` to it. This time, use the `Cylinder` variant. Set its `height` to `1` and `radius` to `0.5`, just as you did in the menu before.
<details>
<summary>Cylinder collider</summary>
<img src="img/cylinder_collider.png" width = 50%/>
</details>
The rest of the steps are identical to the empty: Drag-and-drop the cylinder collider into the `Wireframe` collection, make it a child of your `Cylinder` object and scale it accordingly. The result should look like this:
<details>
<summary>Cylinder collider on mesh</summary>
<img src="img/cylinder_collider_on_mesh.png" width = 50%/>
</details>
> [!TIP]
> Blender does not support creating all shapes that a collider would want.
> A notable omission is a capsule.
> You can use the builtin [Add Mesh Extra Objects](https://docs.blender.org/manual/en/latest/addons/add_mesh/mesh_extra_objects.html)
> extension to fill this gap.
Add an instance of the `Wireframe` collection to the `World` scene and run the game to see all kinds of primitive colliders tumble around.
<details>
<summary>Cylinder collider falling down</summary>
<img src="img/falling_wireframe.gif" width = 50%/>
</details>
## Add Dynamic Colliders
Now let's go for some more complex shapes.
Remember, most of the time you'll want to approximate the shape with a primitive collider, but sometimes you need the exact shape
or just quickly want to test something. For this, we are going to use dynamic colliders.
### Convex
Go back to the `Library` scene, add a new collection, and name it `Convex`. Add a `RigidBody` to it.
Select `Add` -> `Mesh` -> `Torus`. Leave it at the default transform. Your scene should now look like this:
<details>
<summary>A simple torus</summary>
<img src="img/torus.png" width = 100%/>
</details>
We will now dynamically generate a convex hull around this torus.
You can imagine the result like how it would look like if you tightly wrapped the torus up as a christmas present.
This means that the hole in the middle will be treated as solid, which is okay for our case.
When using dynamic colliders, try to prefer convex shapes, as they are much faster to calculate than concave shapes.
To use a dynamic collider, we must proceed a bit differently from before.
Instead of adding the component to the torus *object*, we add it to the *mesh*.
You can access it by expanding your object in the outliner. Its icon is a green triangle:
<details>
<summary>The selected mesh</summary>
<img src="img/select_mesh.png" width = 50%/>
</details>
With the *mesh* selected, add a `ColliderConstructor` to it. Set the variant to `ConvexHullFromMesh`.
If you did everything correctly, the component manager should say "Components for Torus (MESH)" at the top:
<details>
<summary>The component manager for the torus mesh</summary>
<img src="img/torus_component.png" width = 50%/>
</details>
Go to the `World` scene and add an instance of the `Convex` collection. Save the scene, then run the game to see the torus fall down.
<details>
<summary>The convex collider falling</summary>
<img src="img/falling_convex.gif" width = 50%/>
</details>
> [!TIP]
> Is your game crashing with `Tried to add a collider to entity Torus via ConvexHullFromMesh that requires a mesh, but no mesh handle was found`?
> That means you added your `ColliderConstructor` to the object instead of the mesh.
> Go back to the screenshots above and make sure you have the mesh selected when adding the component.
### Concave
Add a new collection and name it `Concave`. Add a `RigidBody` to it. Select `Add` -> `Mesh` -> `Monkey`.
Yes, Blender has a builtin method for creating Suzanne, its monkey mascot. Isn't it great?
Anyways, just as before, select the *mesh* of the monkey.
Add a `ColliderConstructor` to it. This time, set the variant to `TrimeshFromMesh`.
> [!CAUTION]
> While `TrimeshFromMesh` can deal with any kind of mesh, it is also the slowest collider to run.
> Additionally, the generated collider will always be treated as if it was hollow.
> That means that any objects that are completely inside the mesh will not collide with it.
> Only use a concave collider if you *really* need it.
Just as before, go to the `World` scene and add an instance of the `Concave` collection. Save the scene, then run the game to see the torus fall down.
<details>
<summary>The concave collider falling</summary>
<img src="img/falling_concave.gif" width = 50%/>
</details>
## Other useful components
The object holding the `ColliderConstructor` can hold some additional components that are useful for tweaking the physics behavior.
- `ColliderDensity` will set the density of the collider and indirectly change the rigid body's mass.
- `Sensor` allow other objects to pass through the collider. It will still report the collision to the physics system so you can react to it.
- `CollisionLayers` controls which other colliders this collider will interact with. Note that since this is a bitflag, manipulating it in Blender is a bit cumbersome. You probably want to set up some kind of `enum` that can be used in Blender and then add the proper `CollisionLayers` in Bevy.
This is just a small selection. Refer to the [Avian documentation](https://docs.rs/avian3d/latest/avian3d/) for more information.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

318
docs/quickstart/readme.md Normal file
View File

@ -0,0 +1,318 @@
# Quickstart
This guide assumes you use Blender 4.2 or newer and have set it to English.
> [!NOTE]
> This is not a Blender tutorial. No worries, we will make sure you find all necessary buttons to click, but we will not explain in detail what Blender concepts like "collections" or "scenes" are. If you are not familiar with Blender, you might want to look up some basic tutorials first.
## Table of Contents
- [Install the Blender Addon](#install-the-blender-addon)
- [Setup the Bevy side](#setup-the-bevy-side)
- [Setup the Blender addon for your project](#setup-the-blender-addon-for-your-project)
- [Create a blueprint](#create-a-blueprint)
- [Compose the world](#compose-the-world)
- [Run your game](#run-your-game)
- [Next Steps](#next-steps)
## Install the Blender Addon
- Download `blenvy.zip` from the [release page](https://github.com/kaosat-dev/Blenvy/releases/tag/blenvy_v0.1.0_pre_alpha)
- Open Blender
- Drag and drop `blenvy.zip` into Blender
- <details>
<summary>This window should show up</summary>
<img src="img/install.png" width=50%>
</summary>
</details>
- Leave all settings as is and click on `OK`
Leave the scene open, we will get back to it later.
## Setup the Bevy side
Run the following commands:
```sh
cargo new my_game
cd my_game
cargo add bevy
cargo add blenvy --git https://github.com/kaosat-dev/Blenvy/ --branch blenvy
```
This guide will tell you to `cargo run` at multiple points. We expect that you are still in the `my_game` directory when you do so.
Now, replace the contents of `src/main.rs` with the following:
<details>
<summary>src/main.rs</summary>
```rust
use bevy::prelude::*;
use blenvy::*;
fn main() -> AppExit {
App::new()
.add_plugins((DefaultPlugins, BlenvyPlugin::default()))
// We need to register components to make them visible to Blenvy
.register_type::<Player>()
.add_systems(Startup, setup)
.run()
}
#[derive(Component, Reflect)]
#[reflect(Component)]
struct Player {
strength: f32,
perception: f32,
endurance: f32,
charisma: f32,
intelligence: f32,
agility: f32,
luck: f32,
}
fn setup(mut commands: Commands) {
commands.spawn((
BlueprintInfo::from_path("levels/World.glb"),
SpawnBlueprint,
HideUntilReady,
GameWorldTag,
));
}
```
</details>
`Player` is the component that we will add to our entities in Blender. It can contain any fields you want, but you need to remember to call `register_type` with it.
Running this won't work yet because the `levels/World.glb` we reference doesn't exist yet. We will create it in the next step.
## Setup the Blender addon for your project
Create a directory under `my_game` called `art`. Hop back into Blender and save the default scene as `my_game.blend` in the `art` directory we just created. Your file structure should now look like this:
<details>
<summary>File structure</summary>
<img src="img/art_file_structure.png" width = 50%/>
</details>
Now, clear the default scene of any objects or collections.
The fastest way to do this is to look for the collection named simply `Collection` all the way on the right of Blender. Right-click on it and select `Delete Hierachy`. For future reference, the place where you just did this is called the *outliner*.
> [!TIP]
> Technically, we could leave the default setup as-is since we are going to recreate it later anyway.
> However, we are starting from a clean slate in order to make it explicit what we are doing
> and which data is being exported to Bevy.
<details>
<summary>The default collection to delete</summary>
<img src="img/default_collection.png" width = 50%/>
</details>
Rename the default scene from `Scene` to `World` by clicking on "Scene" in the upper right corner of Blender and typing a new name.
<details>
<summary>Where to rename the scene</summary>
<img src="img/scene_name.png" width = 50%/>
</details>
Next, create a new scene by clicking on the icon that looks a bit like two pages, next to where you just renamed the scene, and then selecting `New`. Rename this scene to `Library`.
<details>
<summary>Where to create a new scene</summary>
<img src="img/create_scene.png" width = 50%/>
</details>
If everything went alright, entering the scene selector by pressing the icon next to the scene name should look like this:
<details>
<summary>Scene selector</summary>
<img src="img/scenes.png" width = 50%/>
</details>
If you switched around scenes to see if everything worked, make sure to switch back to the `Library` scene now.
Press `N`. This will open a side window. In it, click on the tab `Blenvy`. This is the main window through which you will interact with Blenvy.
<details>
<summary>Blenvy menu</summary>
<img src="img/blenvy_menu.png" width = 50%/>
</details>
You will see that two options are highlighted red because they are not yet configured.
For `level scenes`, click on the selector, select `World` and hit `+`. For `library scenes`, select `Library` and again hit `+`.
Your menu should now look like this:
<details>
<summary>Correctly setup Blenvy</summary>
<img src="img/blenvy_after_setup.png" width = 50%/>
</details>
Save your Blender file by pressing `Ctrl + S` on Windows or Linux and `Cmd + S` on macOS. You should now have a new asset under `my_game/assets/levels/World.glb` and a companion file containing metadata.
<details>
<summary>The newly created level assets</summary>
<img src="img/level_asset.png" width = 50%/>
</details>
Now run your game with `cargo run`. It may crash because the scene is empty, but don't worry. The point is that now will have generated another new file, namely `assets/registry.json`. This file contains the information about all components exported by your game so that Blenvy can pso them in Blender.
<details>
<summary>The final file structure for an empty world</summary>
<img src="img/registry.png" width = 50%/>
</details>
This concludes the setup portion of the guide.
## Create a blueprint
Alright, let's jump into the actual workflow you'll be using to create your game.
We will first create an object for the `Player` component we defined earlier.
While still in the `Library` scene, right-click on the `Scene Collection` in the outliner to the right. Select `New Collection`. Double-click on the new collection that appeared and rename it to `Player`. Click on it to have it selected.
<details>
<summary>The player collection</summary>
<img src="img/player_collection.png" width = 50%/>
</details>
Now, on the upper left of Blender, click on `Add` -> `Mesh` -> `Cube`. This will be our player.
Select the `Player` collection again. We will now add the `Player` component to it.
Go to the Blenvy menu we opened earlier. Select the icon in its upper left corner. This is where components are managed.
<details>
<summary>The component manager</summary>
<img src="img/component_manager.png" width = 50%/>
</details>
If your component manager says "Select an object to edit its components", make sure you have the `Player` collection we just created selected by clicking on it in the outliner.
Click on `Components`. If it says "No results found", we need to explicitly reload the registry. In the Blenvy menu, click on the gear icon (the fourth one from the left). In the submenu, click on the second icon. Your menu should now look like this:
<details>
<summary>The registry settings</summary>
<img src="img/registry_settings.png" width = 50%/>
</details>
Click on `reload registry` to reload it manually.
Go back to the component manager and you should now be greeted by a whole bunch of components:
<details>
<summary>The registry settings</summary>
<img src="img/lots_of_components.png" width = 50%/>
</details>
Type in `Player` and click on `my_game::Player`.
> [!TIP]
> If this does not show up, you have forgotten to call `register_type` with it.
Now click `Add`. You can now set all the player's fields in a neat Blender UI. Note that while we are only using `f32` here, you can use any kind of field, even complicated nested enums or structs.
<details>
<summary>The player component in Blender</summary>
<img src="img/player_component.png" width = 50%/>
</details>
Congratulations, you have just created your first blueprint.
## Compose the world
Let's populate our world now. Switch back to the `World` scene in Blender as described before.
We will add the following kinds of objects to our world:
- Some basic ground, which we will create directly in the world
- A camera
- A light
- The player character, which will be a blueprint instance
First, let's add a camera through `Add` -> `Camera`. Blender will make the camera face whatever direction the viewport is aimed at, which will probably be completely arbitrary.
Move the camera a bit so that it faces the world origin and is rotated the right way.
Pressing `0` on your numpad will show you a preview of what the camera sees.
You can just copy our transform if you like:
- Location:
- X: `0`
- Y: `-10`
- Z: `2`
- Rotation
- X: `80`
- Y: `0`
- Z: `0`
- Scale
- X: `1`
- Y: `1`
- Z: `1`
All transforms we are using assume that you are using the `XYZ Euler` mode for rotation.
<details>
<summary>The camera transform in Blender</summary>
<img src="img/camera_transform.png" width = 50%/>
</details>
Now, let's add a ground with `Add` -> `Mesh` -> `Cube`. Again scale and move it so that it lies neatly under the camera. Our transform looks like this:
- Location:
- X: `0`
- Y: `0`
- Z: `0`
- Rotation
- X: `0`
- Y: `0`
- Z: `0`
- Scale
- X: `5`
- Y: `5`
- Z: `0.1`
Add a directional light with `Add` -> `Light` -> `Sun`.
This light's position and scale do not matter, only its rotation is actually used. We are using the following:
- Rotation
- X: `20`
- Y: `20`
- Z: `0`
Finally, it is time to create an instance of our player blueprint! For this, go to `Add` -> `Collection Instance` and select `Player`. It will spawn at origin, which means directly inside the ground for us. Move it a bit up. A location of `Z: 1.1` should placed it just a tiny bit above the ground.
And with that, our Blender scene is finished! The final result should look like this:
<details>
<summary>The final Blender world scene</summary>
<img src="img/final_blender.png" width = 100%/>
</details>
Save your Blender file again. This will update the `World.glb` file in the `assets` directory and create a new file for our player blueprint under `assets/blueprints/Player.glb`, including again a metadata file.
<details>
<summary>The new blueprint files</summary>
<img src="img/blueprint_file.png" width = 50%/>
</details>
## Run your game
Congrats, you're done! Just run your game with `cargo run` and you should see your world in all its glory:
<details>
<summary>The final Bevy render</summary>
<img src="img/final_bevy.png" width = 50%/>
</details>
Okay, maybe not that much glory. But the important part is that the player is visible in the scene and has a `Player` component on it. You can now add more components to the player, create more blueprints, and populate your world with them. They can have animations, materials, etc. Have fun!
## Next Steps
- Read the [Blenvy for Bevy](../../crates/blenvy/README.md) documentation for more features on the Bevy side.
- Read the [Blenvy for Blender](../../tools/blenvy/README.md) documentation for more features on the Blender side.
- Read about the [Avian Physics Integration](../avian/readme.md) to learn how to setup colliders in Blender that will be used by the Avian physics engine in Bevy.