2020-04-19 17:08:47 +00:00
|
|
|
[package]
|
|
|
|
name = "bevy_gltf"
|
2024-07-08 12:54:08 +00:00
|
|
|
version = "0.15.0-dev"
|
2021-10-27 00:12:14 +00:00
|
|
|
edition = "2021"
|
2020-08-10 00:24:27 +00:00
|
|
|
description = "Bevy Engine GLTF loading"
|
|
|
|
homepage = "https://bevyengine.org"
|
|
|
|
repository = "https://github.com/bevyengine/bevy"
|
2021-07-23 21:11:51 +00:00
|
|
|
license = "MIT OR Apache-2.0"
|
2020-08-10 00:24:27 +00:00
|
|
|
keywords = ["bevy"]
|
2020-04-19 17:08:47 +00:00
|
|
|
|
`StandardMaterial` Light Transmission (#8015)
# Objective
<img width="1920" alt="Screenshot 2023-04-26 at 01 07 34"
src="https://user-images.githubusercontent.com/418473/234467578-0f34187b-5863-4ea1-88e9-7a6bb8ce8da3.png">
This PR adds both diffuse and specular light transmission capabilities
to the `StandardMaterial`, with support for screen space refractions.
This enables realistically representing a wide range of real-world
materials, such as:
- Glass; (Including frosted glass)
- Transparent and translucent plastics;
- Various liquids and gels;
- Gemstones;
- Marble;
- Wax;
- Paper;
- Leaves;
- Porcelain.
Unlike existing support for transparency, light transmission does not
rely on fixed function alpha blending, and therefore works with both
`AlphaMode::Opaque` and `AlphaMode::Mask` materials.
## Solution
- Introduces a number of transmission related fields in the
`StandardMaterial`;
- For specular transmission:
- Adds logic to take a view main texture snapshot after the opaque
phase; (in order to perform screen space refractions)
- Introduces a new `Transmissive3d` phase to the renderer, to which all
meshes with `transmission > 0.0` materials are sent.
- Calculates a light exit point (of the approximate mesh volume) using
`ior` and `thickness` properties
- Samples the snapshot texture with an adaptive number of taps across a
`roughness`-controlled radius enabling “blurry” refractions
- For diffuse transmission:
- Approximates transmitted diffuse light by using a second, flipped +
displaced, diffuse-only Lambertian lobe for each light source.
## To Do
- [x] Figure out where `fresnel_mix()` is taking place, if at all, and
where `dielectric_specular` is being calculated, if at all, and update
them to use the `ior` value (Not a blocker, just a nice-to-have for more
correct BSDF)
- To the _best of my knowledge, this is now taking place, after
964340cdd. The fresnel mix is actually "split" into two parts in our
implementation, one `(1 - fresnel(...))` in the transmission, and
`fresnel()` in the light implementations. A surface with more
reflectance now will produce slightly dimmer transmission towards the
grazing angle, as more of the light gets reflected.
- [x] Add `transmission_texture`
- [x] Add `diffuse_transmission_texture`
- [x] Add `thickness_texture`
- [x] Add `attenuation_distance` and `attenuation_color`
- [x] Connect values to glTF loader
- [x] `transmission` and `transmission_texture`
- [x] `thickness` and `thickness_texture`
- [x] `ior`
- [ ] `diffuse_transmission` and `diffuse_transmission_texture` (needs
upstream support in `gltf` crate, not a blocker)
- [x] Add support for multiple screen space refraction “steps”
- [x] Conditionally create no transmission snapshot texture at all if
`steps == 0`
- [x] Conditionally enable/disable screen space refraction transmission
snapshots
- [x] Read from depth pre-pass to prevent refracting pixels in front of
the light exit point
- [x] Use `interleaved_gradient_noise()` function for sampling blur in a
way that benefits from TAA
- [x] Drill down a TAA `#define`, tweak some aspects of the effect
conditionally based on it
- [x] Remove const array that's crashing under HLSL (unless a new `naga`
release with https://github.com/gfx-rs/naga/pull/2496 comes out before
we merge this)
- [ ] Look into alternatives to the `switch` hack for dynamically
indexing the const array (might not be needed, compilers seem to be
decent at expanding it)
- [ ] Add pipeline keys for gating transmission (do we really want/need
this?)
- [x] Tweak some material field/function names?
## A Note on Texture Packing
_This was originally added as a comment to the
`specular_transmission_texture`, `thickness_texture` and
`diffuse_transmission_texture` documentation, I removed it since it was
more confusing than helpful, and will likely be made redundant/will need
to be updated once we have a better infrastructure for preprocessing
assets_
Due to how channels are mapped, you can more efficiently use a single
shared texture image
for configuring the following:
- R - `specular_transmission_texture`
- G - `thickness_texture`
- B - _unused_
- A - `diffuse_transmission_texture`
The `KHR_materials_diffuse_transmission` glTF extension also defines a
`diffuseTransmissionColorTexture`,
that _we don't currently support_. One might choose to pack the
intensity and color textures together,
using RGB for the color and A for the intensity, in which case this
packing advice doesn't really apply.
---
## Changelog
- Added a new `Transmissive3d` render phase for rendering specular
transmissive materials with screen space refractions
- Added rendering support for transmitted environment map light on the
`StandardMaterial` as a fallback for screen space refractions
- Added `diffuse_transmission`, `specular_transmission`, `thickness`,
`ior`, `attenuation_distance` and `attenuation_color` to the
`StandardMaterial`
- Added `diffuse_transmission_texture`, `specular_transmission_texture`,
`thickness_texture` to the `StandardMaterial`, gated behind a new
`pbr_transmission_textures` cargo feature (off by default, for maximum
hardware compatibility)
- Added `Camera3d::screen_space_specular_transmission_steps` for
controlling the number of “layers of transparency” rendered for
transmissive objects
- Added a `TransmittedShadowReceiver` component for enabling shadows in
(diffusely) transmitted light. (disabled by default, as it requires
carefully setting up the `thickness` to avoid self-shadow artifacts)
- Added support for the `KHR_materials_transmission`,
`KHR_materials_ior` and `KHR_materials_volume` glTF extensions
- Renamed items related to temporal jitter for greater consistency
## Migration Guide
- `SsaoPipelineKey::temporal_noise` has been renamed to
`SsaoPipelineKey::temporal_jitter`
- The `TAA` shader def (controlled by the presence of the
`TemporalAntiAliasSettings` component in the camera) has been replaced
with the `TEMPORAL_JITTER` shader def (controlled by the presence of the
`TemporalJitter` component in the camera)
- `MeshPipelineKey::TAA` has been replaced by
`MeshPipelineKey::TEMPORAL_JITTER`
- The `TEMPORAL_NOISE` shader def has been consolidated with
`TEMPORAL_JITTER`
2023-10-31 20:59:02 +00:00
|
|
|
[features]
|
2024-07-20 17:55:25 +00:00
|
|
|
dds = ["bevy_render/dds", "bevy_core_pipeline/dds"]
|
2024-05-03 13:00:18 +00:00
|
|
|
pbr_transmission_textures = ["bevy_pbr/pbr_transmission_textures"]
|
Implement clearcoat per the Filament and the `KHR_materials_clearcoat` specifications. (#13031)
Clearcoat is a separate material layer that represents a thin
translucent layer of a material. Examples include (from the [Filament
spec]) car paint, soda cans, and lacquered wood. This commit implements
support for clearcoat following the Filament and Khronos specifications,
marking the beginnings of support for multiple PBR layers in Bevy.
The [`KHR_materials_clearcoat`] specification describes the clearcoat
support in glTF. In Blender, applying a clearcoat to the Principled BSDF
node causes the clearcoat settings to be exported via this extension. As
of this commit, Bevy parses and reads the extension data when present in
glTF. Note that the `gltf` crate has no support for
`KHR_materials_clearcoat`; this patch therefore implements the JSON
semantics manually.
Clearcoat is integrated with `StandardMaterial`, but the code is behind
a series of `#ifdef`s that only activate when clearcoat is present.
Additionally, the `pbr_feature_layer_material_textures` Cargo feature
must be active in order to enable support for clearcoat factor maps,
clearcoat roughness maps, and clearcoat normal maps. This approach
mirrors the same pattern used by the existing transmission feature and
exists to avoid running out of texture bindings on platforms like WebGL
and WebGPU. Note that constant clearcoat factors and roughness values
*are* supported in the browser; only the relatively-less-common maps are
disabled on those platforms.
This patch refactors the lighting code in `StandardMaterial`
significantly in order to better support multiple layers in a natural
way. That code was due for a refactor in any case, so this is a nice
improvement.
A new demo, `clearcoat`, has been added. It's based on [the
corresponding three.js demo], but all the assets (aside from the skybox
and environment map) are my original work.
[Filament spec]:
https://google.github.io/filament/Filament.html#materialsystem/clearcoatmodel
[`KHR_materials_clearcoat`]:
https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md
[the corresponding three.js demo]:
https://threejs.org/examples/webgl_materials_physical_clearcoat.html
![Screenshot 2024-04-19
101143](https://github.com/bevyengine/bevy/assets/157897/3444bcb5-5c20-490c-b0ad-53759bd47ae2)
![Screenshot 2024-04-19
102054](https://github.com/bevyengine/bevy/assets/157897/6e953944-75b8-49ef-bc71-97b0a53b3a27)
## Changelog
### Added
* `StandardMaterial` now supports a clearcoat layer, which represents a
thin translucent layer over an underlying material.
* The glTF loader now supports the `KHR_materials_clearcoat` extension,
representing materials with clearcoat layers.
## Migration Guide
* The lighting functions in the `pbr_lighting` WGSL module now have
clearcoat parameters, if `STANDARD_MATERIAL_CLEARCOAT` is defined.
* The `R` reflection vector parameter has been removed from some
lighting functions, as it was unused.
2024-05-05 22:57:05 +00:00
|
|
|
pbr_multi_layer_material_textures = []
|
2024-07-02 18:02:05 +00:00
|
|
|
pbr_anisotropy_texture = []
|
`StandardMaterial` Light Transmission (#8015)
# Objective
<img width="1920" alt="Screenshot 2023-04-26 at 01 07 34"
src="https://user-images.githubusercontent.com/418473/234467578-0f34187b-5863-4ea1-88e9-7a6bb8ce8da3.png">
This PR adds both diffuse and specular light transmission capabilities
to the `StandardMaterial`, with support for screen space refractions.
This enables realistically representing a wide range of real-world
materials, such as:
- Glass; (Including frosted glass)
- Transparent and translucent plastics;
- Various liquids and gels;
- Gemstones;
- Marble;
- Wax;
- Paper;
- Leaves;
- Porcelain.
Unlike existing support for transparency, light transmission does not
rely on fixed function alpha blending, and therefore works with both
`AlphaMode::Opaque` and `AlphaMode::Mask` materials.
## Solution
- Introduces a number of transmission related fields in the
`StandardMaterial`;
- For specular transmission:
- Adds logic to take a view main texture snapshot after the opaque
phase; (in order to perform screen space refractions)
- Introduces a new `Transmissive3d` phase to the renderer, to which all
meshes with `transmission > 0.0` materials are sent.
- Calculates a light exit point (of the approximate mesh volume) using
`ior` and `thickness` properties
- Samples the snapshot texture with an adaptive number of taps across a
`roughness`-controlled radius enabling “blurry” refractions
- For diffuse transmission:
- Approximates transmitted diffuse light by using a second, flipped +
displaced, diffuse-only Lambertian lobe for each light source.
## To Do
- [x] Figure out where `fresnel_mix()` is taking place, if at all, and
where `dielectric_specular` is being calculated, if at all, and update
them to use the `ior` value (Not a blocker, just a nice-to-have for more
correct BSDF)
- To the _best of my knowledge, this is now taking place, after
964340cdd. The fresnel mix is actually "split" into two parts in our
implementation, one `(1 - fresnel(...))` in the transmission, and
`fresnel()` in the light implementations. A surface with more
reflectance now will produce slightly dimmer transmission towards the
grazing angle, as more of the light gets reflected.
- [x] Add `transmission_texture`
- [x] Add `diffuse_transmission_texture`
- [x] Add `thickness_texture`
- [x] Add `attenuation_distance` and `attenuation_color`
- [x] Connect values to glTF loader
- [x] `transmission` and `transmission_texture`
- [x] `thickness` and `thickness_texture`
- [x] `ior`
- [ ] `diffuse_transmission` and `diffuse_transmission_texture` (needs
upstream support in `gltf` crate, not a blocker)
- [x] Add support for multiple screen space refraction “steps”
- [x] Conditionally create no transmission snapshot texture at all if
`steps == 0`
- [x] Conditionally enable/disable screen space refraction transmission
snapshots
- [x] Read from depth pre-pass to prevent refracting pixels in front of
the light exit point
- [x] Use `interleaved_gradient_noise()` function for sampling blur in a
way that benefits from TAA
- [x] Drill down a TAA `#define`, tweak some aspects of the effect
conditionally based on it
- [x] Remove const array that's crashing under HLSL (unless a new `naga`
release with https://github.com/gfx-rs/naga/pull/2496 comes out before
we merge this)
- [ ] Look into alternatives to the `switch` hack for dynamically
indexing the const array (might not be needed, compilers seem to be
decent at expanding it)
- [ ] Add pipeline keys for gating transmission (do we really want/need
this?)
- [x] Tweak some material field/function names?
## A Note on Texture Packing
_This was originally added as a comment to the
`specular_transmission_texture`, `thickness_texture` and
`diffuse_transmission_texture` documentation, I removed it since it was
more confusing than helpful, and will likely be made redundant/will need
to be updated once we have a better infrastructure for preprocessing
assets_
Due to how channels are mapped, you can more efficiently use a single
shared texture image
for configuring the following:
- R - `specular_transmission_texture`
- G - `thickness_texture`
- B - _unused_
- A - `diffuse_transmission_texture`
The `KHR_materials_diffuse_transmission` glTF extension also defines a
`diffuseTransmissionColorTexture`,
that _we don't currently support_. One might choose to pack the
intensity and color textures together,
using RGB for the color and A for the intensity, in which case this
packing advice doesn't really apply.
---
## Changelog
- Added a new `Transmissive3d` render phase for rendering specular
transmissive materials with screen space refractions
- Added rendering support for transmitted environment map light on the
`StandardMaterial` as a fallback for screen space refractions
- Added `diffuse_transmission`, `specular_transmission`, `thickness`,
`ior`, `attenuation_distance` and `attenuation_color` to the
`StandardMaterial`
- Added `diffuse_transmission_texture`, `specular_transmission_texture`,
`thickness_texture` to the `StandardMaterial`, gated behind a new
`pbr_transmission_textures` cargo feature (off by default, for maximum
hardware compatibility)
- Added `Camera3d::screen_space_specular_transmission_steps` for
controlling the number of “layers of transparency” rendered for
transmissive objects
- Added a `TransmittedShadowReceiver` component for enabling shadows in
(diffusely) transmitted light. (disabled by default, as it requires
carefully setting up the `thickness` to avoid self-shadow artifacts)
- Added support for the `KHR_materials_transmission`,
`KHR_materials_ior` and `KHR_materials_volume` glTF extensions
- Renamed items related to temporal jitter for greater consistency
## Migration Guide
- `SsaoPipelineKey::temporal_noise` has been renamed to
`SsaoPipelineKey::temporal_jitter`
- The `TAA` shader def (controlled by the presence of the
`TemporalAntiAliasSettings` component in the camera) has been replaced
with the `TEMPORAL_JITTER` shader def (controlled by the presence of the
`TemporalJitter` component in the camera)
- `MeshPipelineKey::TAA` has been replaced by
`MeshPipelineKey::TEMPORAL_JITTER`
- The `TEMPORAL_NOISE` shader def has been consolidated with
`TEMPORAL_JITTER`
2023-10-31 20:59:02 +00:00
|
|
|
|
2020-04-19 17:08:47 +00:00
|
|
|
[dependencies]
|
2020-08-10 00:39:28 +00:00
|
|
|
# bevy
|
2024-07-08 12:54:08 +00:00
|
|
|
bevy_animation = { path = "../bevy_animation", version = "0.15.0-dev", optional = true }
|
|
|
|
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
|
|
|
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
|
|
|
|
bevy_color = { path = "../bevy_color", version = "0.15.0-dev" }
|
|
|
|
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
|
|
|
|
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.15.0-dev" }
|
|
|
|
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
|
|
|
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev" }
|
|
|
|
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
|
|
|
|
bevy_pbr = { path = "../bevy_pbr", version = "0.15.0-dev" }
|
|
|
|
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
|
2023-11-21 01:04:14 +00:00
|
|
|
"bevy",
|
|
|
|
] }
|
2024-07-08 12:54:08 +00:00
|
|
|
bevy_render = { path = "../bevy_render", version = "0.15.0-dev" }
|
|
|
|
bevy_scene = { path = "../bevy_scene", version = "0.15.0-dev", features = [
|
2023-11-21 01:04:14 +00:00
|
|
|
"bevy_render",
|
|
|
|
] }
|
2024-07-08 12:54:08 +00:00
|
|
|
bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" }
|
|
|
|
bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev" }
|
|
|
|
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
2020-04-19 17:08:47 +00:00
|
|
|
|
2020-08-10 00:39:28 +00:00
|
|
|
# other
|
GLTF extension support (#11138)
# Objective
Adds support for accessing raw extension data of loaded GLTF assets
## Solution
Via the GLTF loader settings, you can specify whether or not to include
the GLTF source. While not the ideal way of solving this problem,
modeling all of GLTF within Bevy just for extensions adds a lot of
complexity to the way Bevy handles GLTF currently. See the example GLTF
meta file and code
```
(
meta_format_version: "1.0",
asset: Load(
loader: "bevy_gltf::loader::GltfLoader",
settings: (
load_meshes: true,
load_cameras: true,
load_lights: true,
include_source: true,
),
),
)
```
```rs
pub fn load_gltf(mut commands: Commands, assets: Res<AssetServer>) {
let my_gltf = assets.load("test_platform.gltf");
commands.insert_resource(MyAssetPack {
spawned: false,
handle: my_gltf,
});
}
#[derive(Resource)]
pub struct MyAssetPack {
pub spawned: bool,
pub handle: Handle<Gltf>,
}
pub fn spawn_gltf_objects(
mut commands: Commands,
mut my: ResMut<MyAssetPack>,
assets_gltf: Res<Assets<Gltf>>,
) {
// This flag is used to because this system has to be run until the asset is loaded.
// If there's a better way of going about this I am unaware of it.
if my.spawned {
return;
}
if let Some(gltf) = assets_gltf.get(&my.handle) {
info!("spawn");
my.spawned = true;
// spawn the first scene in the file
commands.spawn(SceneBundle {
scene: gltf.scenes[0].clone(),
..Default::default()
});
let source = gltf.source.as_ref().unwrap();
info!("materials count {}", &source.materials().size_hint().0);
info!(
"materials ext is some {}",
&source.materials().next().unwrap().extensions().is_some()
);
}
}
```
---
## Changelog
Added support for GLTF extensions through including raw GLTF source via
loader flag `GltfLoaderSettings::include_source == true`, stored in
`Gltf::source: Option<gltf::Gltf>`
## Migration Guide
This will have issues with "asset migrations", as there is currently no
way for .meta files to be migrated. Attempting to migrate .meta files
without the new flag will yield the following error:
```
bevy_asset::server: Failed to deserialize meta for asset test_platform.gltf: Failed to deserialize asset meta: SpannedError { code: MissingStructField { field: "include_source", outer: Some("GltfLoaderSettings") }, position: Position { line: 9, col: 9 } }
```
This means users who want to migrate their .meta files will have to add
the `include_source: true,` setting to their meta files by hand.
2024-01-15 15:38:01 +00:00
|
|
|
gltf = { version = "1.4.0", default-features = false, features = [
|
2023-11-21 01:04:14 +00:00
|
|
|
"KHR_lights_punctual",
|
|
|
|
"KHR_materials_transmission",
|
|
|
|
"KHR_materials_ior",
|
|
|
|
"KHR_materials_volume",
|
|
|
|
"KHR_materials_unlit",
|
|
|
|
"KHR_materials_emissive_strength",
|
2024-02-21 01:11:28 +00:00
|
|
|
"KHR_texture_transform",
|
2023-11-21 01:04:14 +00:00
|
|
|
"extras",
|
GLTF extension support (#11138)
# Objective
Adds support for accessing raw extension data of loaded GLTF assets
## Solution
Via the GLTF loader settings, you can specify whether or not to include
the GLTF source. While not the ideal way of solving this problem,
modeling all of GLTF within Bevy just for extensions adds a lot of
complexity to the way Bevy handles GLTF currently. See the example GLTF
meta file and code
```
(
meta_format_version: "1.0",
asset: Load(
loader: "bevy_gltf::loader::GltfLoader",
settings: (
load_meshes: true,
load_cameras: true,
load_lights: true,
include_source: true,
),
),
)
```
```rs
pub fn load_gltf(mut commands: Commands, assets: Res<AssetServer>) {
let my_gltf = assets.load("test_platform.gltf");
commands.insert_resource(MyAssetPack {
spawned: false,
handle: my_gltf,
});
}
#[derive(Resource)]
pub struct MyAssetPack {
pub spawned: bool,
pub handle: Handle<Gltf>,
}
pub fn spawn_gltf_objects(
mut commands: Commands,
mut my: ResMut<MyAssetPack>,
assets_gltf: Res<Assets<Gltf>>,
) {
// This flag is used to because this system has to be run until the asset is loaded.
// If there's a better way of going about this I am unaware of it.
if my.spawned {
return;
}
if let Some(gltf) = assets_gltf.get(&my.handle) {
info!("spawn");
my.spawned = true;
// spawn the first scene in the file
commands.spawn(SceneBundle {
scene: gltf.scenes[0].clone(),
..Default::default()
});
let source = gltf.source.as_ref().unwrap();
info!("materials count {}", &source.materials().size_hint().0);
info!(
"materials ext is some {}",
&source.materials().next().unwrap().extensions().is_some()
);
}
}
```
---
## Changelog
Added support for GLTF extensions through including raw GLTF source via
loader flag `GltfLoaderSettings::include_source == true`, stored in
`Gltf::source: Option<gltf::Gltf>`
## Migration Guide
This will have issues with "asset migrations", as there is currently no
way for .meta files to be migrated. Attempting to migrate .meta files
without the new flag will yield the following error:
```
bevy_asset::server: Failed to deserialize meta for asset test_platform.gltf: Failed to deserialize asset meta: SpannedError { code: MissingStructField { field: "include_source", outer: Some("GltfLoaderSettings") }, position: Position { line: 9, col: 9 } }
```
This means users who want to migrate their .meta files will have to add
the `include_source: true,` setting to their meta files by hand.
2024-01-15 15:38:01 +00:00
|
|
|
"extensions",
|
2023-11-21 01:04:14 +00:00
|
|
|
"names",
|
|
|
|
"utils",
|
2022-01-03 07:59:25 +00:00
|
|
|
] }
|
2020-05-15 23:55:44 +00:00
|
|
|
thiserror = "1.0"
|
2024-03-18 06:42:58 +00:00
|
|
|
base64 = "0.22.0"
|
2021-04-13 21:30:32 +00:00
|
|
|
percent-encoding = "2.1"
|
Add morph targets (#8158)
# Objective
- Add morph targets to `bevy_pbr` (closes #5756) & load them from glTF
- Supersedes #3722
- Fixes #6814
[Morph targets][1] (also known as shape interpolation, shape keys, or
blend shapes) allow animating individual vertices with fine grained
controls. This is typically used for facial expressions. By specifying
multiple poses as vertex offset, and providing a set of weight of each
pose, it is possible to define surprisingly realistic transitions
between poses. Blending between multiple poses also allow composition.
Morph targets are part of the [gltf standard][2] and are a feature of
Unity and Unreal, and babylone.js, it is only natural to implement them
in bevy.
## Solution
This implementation of morph targets uses a 3d texture where each pixel
is a component of an animated attribute. Each layer is a different
target. We use a 2d texture for each target, because the number of
attribute×components×animated vertices is expected to always exceed the
maximum pixel row size limit of webGL2. It copies fairly closely the way
skinning is implemented on the CPU side, while on the GPU side, the
shader morph target implementation is a relatively trivial detail.
We add an optional `morph_texture` to the `Mesh` struct. The
`morph_texture` is built through a method that accepts an iterator over
attribute buffers.
The `MorphWeights` component, user-accessible, controls the blend of
poses used by mesh instances (so that multiple copy of the same mesh may
have different weights), all the weights are uploaded to a uniform
buffer of 256 `f32`. We limit to 16 poses per mesh, and a total of 256
poses.
More literature:
* Old babylone.js implementation (vertex attribute-based):
https://www.eternalcoding.com/dev-log-1-morph-targets/
* Babylone.js implementation (similar to ours):
https://www.youtube.com/watch?v=LBPRmGgU0PE
* GPU gems 3:
https://developer.nvidia.com/gpugems/gpugems3/part-i-geometry/chapter-3-directx-10-blend-shapes-breaking-limits
* Development discord thread
https://discord.com/channels/691052431525675048/1083325980615114772
https://user-images.githubusercontent.com/26321040/231181046-3bca2ab2-d4d9-472e-8098-639f1871ce2e.mp4
https://github.com/bevyengine/bevy/assets/26321040/d2a0c544-0ef8-45cf-9f99-8c3792f5a258
## Acknowledgements
* Thanks to `storytold` for sponsoring the feature
* Thanks to `superdump` and `james7132` for guidance and help figuring
out stuff
## Future work
- Handling of less and more attributes (eg: animated uv, animated
arbitrary attributes)
- Dynamic pose allocation (so that zero-weighted poses aren't uploaded
to GPU for example, enables much more total poses)
- Better animation API, see #8357
----
## Changelog
- Add morph targets to bevy meshes
- Support up to 64 poses per mesh of individually up to 116508 vertices,
animation currently strictly limited to the position, normal and tangent
attributes.
- Load a morph target using `Mesh::set_morph_targets`
- Add `VisitMorphTargets` and `VisitMorphAttributes` traits to
`bevy_render`, this allows defining morph targets (a fairly complex and
nested data structure) through iterators (ie: single copy instead of
passing around buffers), see documentation of those traits for details
- Add `MorphWeights` component exported by `bevy_render`
- `MorphWeights` control mesh's morph target weights, blending between
various poses defined as morph targets.
- `MorphWeights` are directly inherited by direct children (single level
of hierarchy) of an entity. This allows controlling several mesh
primitives through a unique entity _as per GLTF spec_.
- Add `MorphTargetNames` component, naming each indices of loaded morph
targets.
- Load morph targets weights and buffers in `bevy_gltf`
- handle morph targets animations in `bevy_animation` (previously, it
was a `warn!` log)
- Add the `MorphStressTest.gltf` asset for morph targets testing, taken
from the glTF samples repo, CC0.
- Add morph target manipulation to `scene_viewer`
- Separate the animation code in `scene_viewer` from the rest of the
code, reducing `#[cfg(feature)]` noise
- Add the `morph_targets.rs` example to show off how to manipulate morph
targets, loading `MorpStressTest.gltf`
## Migration Guide
- (very specialized, unlikely to be touched by 3rd parties)
- `MeshPipeline` now has a single `mesh_layouts` field rather than
separate `mesh_layout` and `skinned_mesh_layout` fields. You should
handle all possible mesh bind group layouts in your implementation
- You should also handle properly the new `MORPH_TARGETS` shader def and
mesh pipeline key. A new function is exposed to make this easier:
`setup_moprh_and_skinning_defs`
- The `MeshBindGroup` is now `MeshBindGroups`, cached bind groups are
now accessed through the `get` method.
[1]: https://en.wikipedia.org/wiki/Morph_target_animation
[2]:
https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#morph-targets
---------
Co-authored-by: François <mockersf@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-22 20:00:01 +00:00
|
|
|
serde = { version = "1.0", features = ["derive"] }
|
|
|
|
serde_json = "1"
|
2024-03-07 02:30:15 +00:00
|
|
|
smallvec = "1.11"
|
2023-11-18 20:58:48 +00:00
|
|
|
|
Make gLTF node children Handle instead of objects (#13707)
Part of #13681
# Objective
gLTF Assets shouldn't be duplicated between Assets resource and node
children.
Also changed `asset_label` to be a method as [per previous PR
comment](https://github.com/bevyengine/bevy/pull/13558).
## Solution
- Made GltfNode children be Handles instead of asset copies.
## Testing
- Added tests that actually test loading and hierarchy as previous ones
unit tested only one function and that makes little sense.
- Made circular nodes an actual loading failure instead of a warning
no-op. You [_MUST NOT_ have cycles in
gLTF](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#nodes-and-hierarchy)
according to the spec.
- IMO this is a bugfix, not a breaking change. But in an extremely
unlikely event in which you relied on invalid behavior for loading gLTF
with cyclic children, you will not be able to do that anymore. You
should fix your gLTF file as it's not valid according to gLTF spec. For
it to for work someone, it had to be bevy with bevy_animation flag off.
---
## Changelog
### Changed
- `GltfNode.children` are now `Vec<Handle<GltfNode>>` instead of
`Vec<GltfNode>`
- Having children cycles between gLTF nodes in a gLTF document is now an
explicit asset loading failure.
## Migration Guide
If accessing children, use `Assets<GltfNode>` resource to get the actual
child object.
#### Before
```rs
fn gltf_print_first_node_children_system(gltf_component_query: Query<Handle<Gltf>>, gltf_assets: Res<Assets<Gltf>>, gltf_nodes: Res<Assets<GltfNode>>) {
for gltf_handle in gltf_component_query.iter() {
let gltf_root = gltf_assets.get(gltf_handle).unwrap();
let first_node_handle = gltf_root.nodes.get(0).unwrap();
let first_node = gltf_nodes.get(first_node_handle).unwrap();
let first_child = first_node.children.get(0).unwrap();
println!("First nodes child node name is {:?)", first_child.name);
}
}
```
#### After
```rs
fn gltf_print_first_node_children_system(gltf_component_query: Query<Handle<Gltf>>, gltf_assets: Res<Assets<Gltf>>, gltf_nodes: Res<Assets<GltfNode>>) {
for gltf_handle in gltf_component_query.iter() {
let gltf_root = gltf_assets.get(gltf_handle).unwrap();
let first_node_handle = gltf_root.nodes.get(0).unwrap();
let first_node = gltf_nodes.get(first_node_handle).unwrap();
let first_child_handle = first_node.children.get(0).unwrap();
let first_child = gltf_nodes.get(first_child_handle).unwrap();
println!("First nodes child node name is {:?)", first_child.name);
}
}
```
2024-07-01 14:05:16 +00:00
|
|
|
[dev-dependencies]
|
2024-07-08 12:54:08 +00:00
|
|
|
bevy_log = { path = "../bevy_log", version = "0.15.0-dev" }
|
Make gLTF node children Handle instead of objects (#13707)
Part of #13681
# Objective
gLTF Assets shouldn't be duplicated between Assets resource and node
children.
Also changed `asset_label` to be a method as [per previous PR
comment](https://github.com/bevyengine/bevy/pull/13558).
## Solution
- Made GltfNode children be Handles instead of asset copies.
## Testing
- Added tests that actually test loading and hierarchy as previous ones
unit tested only one function and that makes little sense.
- Made circular nodes an actual loading failure instead of a warning
no-op. You [_MUST NOT_ have cycles in
gLTF](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#nodes-and-hierarchy)
according to the spec.
- IMO this is a bugfix, not a breaking change. But in an extremely
unlikely event in which you relied on invalid behavior for loading gLTF
with cyclic children, you will not be able to do that anymore. You
should fix your gLTF file as it's not valid according to gLTF spec. For
it to for work someone, it had to be bevy with bevy_animation flag off.
---
## Changelog
### Changed
- `GltfNode.children` are now `Vec<Handle<GltfNode>>` instead of
`Vec<GltfNode>`
- Having children cycles between gLTF nodes in a gLTF document is now an
explicit asset loading failure.
## Migration Guide
If accessing children, use `Assets<GltfNode>` resource to get the actual
child object.
#### Before
```rs
fn gltf_print_first_node_children_system(gltf_component_query: Query<Handle<Gltf>>, gltf_assets: Res<Assets<Gltf>>, gltf_nodes: Res<Assets<GltfNode>>) {
for gltf_handle in gltf_component_query.iter() {
let gltf_root = gltf_assets.get(gltf_handle).unwrap();
let first_node_handle = gltf_root.nodes.get(0).unwrap();
let first_node = gltf_nodes.get(first_node_handle).unwrap();
let first_child = first_node.children.get(0).unwrap();
println!("First nodes child node name is {:?)", first_child.name);
}
}
```
#### After
```rs
fn gltf_print_first_node_children_system(gltf_component_query: Query<Handle<Gltf>>, gltf_assets: Res<Assets<Gltf>>, gltf_nodes: Res<Assets<GltfNode>>) {
for gltf_handle in gltf_component_query.iter() {
let gltf_root = gltf_assets.get(gltf_handle).unwrap();
let first_node_handle = gltf_root.nodes.get(0).unwrap();
let first_node = gltf_nodes.get(first_node_handle).unwrap();
let first_child_handle = first_node.children.get(0).unwrap();
let first_child = gltf_nodes.get(first_child_handle).unwrap();
println!("First nodes child node name is {:?)", first_child.name);
}
}
```
2024-07-01 14:05:16 +00:00
|
|
|
|
2023-11-18 20:58:48 +00:00
|
|
|
[lints]
|
|
|
|
workspace = true
|
2024-03-08 20:03:09 +00:00
|
|
|
|
|
|
|
[package.metadata.docs.rs]
|
2024-07-22 18:58:04 +00:00
|
|
|
rustdoc-args = ["-Zunstable-options"]
|
2024-03-08 20:03:09 +00:00
|
|
|
all-features = true
|