Skip to content
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
280 changes: 243 additions & 37 deletions crates/bevy_asset/src/assets.rs

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions crates/bevy_asset/src/render_asset.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
use core::marker::PhantomData;

use bevy_ecs::resource::Resource;
use bevy_platform::collections::HashMap;
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
use serde::{Deserialize, Serialize};

use crate::{Asset, AssetId};

bitflags::bitflags! {
/// Defines where the asset will be used.
///
Expand Down Expand Up @@ -50,3 +56,57 @@ impl Default for RenderAssetUsages {
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD
}
}

/// Declares that this type is a retained asset of the source asset.
pub trait RetainedAsset: Send + Sync {
type SourceAsset: Asset;
}

/// A special [`RetainedAsset`] that won't be stored in [`RetainedAssets`].
pub struct EmptyRetainedAsset<A: Asset>(PhantomData<A>);

impl<A: Asset> Default for EmptyRetainedAsset<A> {
fn default() -> Self {
Self(PhantomData::<A>)
}
}

impl<A: Asset> RetainedAsset for EmptyRetainedAsset<A> {
type SourceAsset = A;
}

/// Stores all ([`RetainedAsset`]) of extracted `RenderAsset` if they exist and are not [`EmptyRetainedAsset`].
#[derive(Resource)]
pub struct RetainedAssets<R: RetainedAsset>(HashMap<AssetId<R::SourceAsset>, R>);

impl<R: RetainedAsset> Default for RetainedAssets<R> {
fn default() -> Self {
Self(Default::default())
}
}

impl<R: RetainedAsset> RetainedAssets<R> {
pub fn get(&self, id: impl Into<AssetId<R::SourceAsset>>) -> Option<&R> {
self.0.get(&id.into())
}

pub fn get_mut(&mut self, id: impl Into<AssetId<R::SourceAsset>>) -> Option<&mut R> {
self.0.get_mut(&id.into())
}

pub fn insert(&mut self, id: impl Into<AssetId<R::SourceAsset>>, value: R) -> Option<R> {
self.0.insert(id.into(), value)
}

pub fn remove(&mut self, id: impl Into<AssetId<R::SourceAsset>>) -> Option<R> {
self.0.remove(&id.into())
}

pub fn iter(&self) -> impl Iterator<Item = (AssetId<R::SourceAsset>, &R)> {
self.0.iter().map(|(k, v)| (*k, v))
}

pub fn iter_mut(&mut self) -> impl Iterator<Item = (AssetId<R::SourceAsset>, &mut R)> {
self.0.iter_mut().map(|(k, v)| (*k, v))
}
}
26 changes: 0 additions & 26 deletions crates/bevy_camera/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,8 @@ use bevy_math::{
primitives::{HalfSpace, ViewFrustum},
Affine3A, Mat3A, Vec3, Vec3A,
};
use bevy_mesh::{Mesh, VertexAttributeValues};
use bevy_reflect::prelude::*;

pub trait MeshAabb {
/// Compute the Axis-Aligned Bounding Box of the mesh vertices in model space
///
/// Returns `None` if `self` doesn't have [`Mesh::ATTRIBUTE_POSITION`] of
/// type [`VertexAttributeValues::Float32x3`], or if `self` doesn't have any vertices.
fn compute_aabb(&self) -> Option<Aabb>;
}

impl MeshAabb for Mesh {
fn compute_aabb(&self) -> Option<Aabb> {
if let Some(aabb) = self.final_aabb {
// use precomputed extents
return Some(aabb.into());
}

let Ok(VertexAttributeValues::Float32x3(values)) =
self.try_attribute(Mesh::ATTRIBUTE_POSITION)
else {
return None;
};

Aabb::enclosing(values.iter().map(|p| Vec3::from_slice(p)))
}
}

/// An axis-aligned bounding box, defined by:
/// - a center,
/// - the distances from the center to each faces along the axis,
Expand Down
26 changes: 13 additions & 13 deletions crates/bevy_camera/src/visibility/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub use render_layers::*;

use bevy_app::{Plugin, PostUpdate, ValidateParentHasComponentPlugin};
use bevy_asset::prelude::AssetChanged;
use bevy_asset::{AssetEventSystems, Assets};
use bevy_asset::{AssetEventSystems, Assets, RetainedAssets};
use bevy_ecs::prelude::*;
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_transform::{components::GlobalTransform, TransformSystems};
Expand All @@ -53,17 +53,17 @@ use smallvec::SmallVec;

use crate::{
camera::Camera,
primitives::{Aabb, Frustum, MeshAabb, Sphere},
primitives::{Aabb, Frustum, Sphere},
Projection,
};
use bevy_mesh::{mark_3d_meshes_as_changed_if_their_assets_changed, Mesh, Mesh2d, Mesh3d};
use bevy_mesh::{mark_3d_meshes_as_changed_if_their_assets_changed, Mesh2d, Mesh3d, RetainedMesh};

/// Use this component to opt-out of the built-in CPU frustum culling, see
/// [`Frustum`]. This can be attached to a [`Camera`] or to individual entities.
///
/// It can be used for example:
/// - disabling CPU culling completely for a [`Camera`], using only GPU culling.
/// - when overwriting a [`Mesh`]'s transform on the GPU side (e.g. overwriting `MeshInputUniform`'s
/// - when overwriting a `Mesh`'s transform on the GPU side (e.g. overwriting `MeshInputUniform`'s
/// `world_from_local`), resulting in stale CPU-side positions.
#[derive(Component, Default)]
pub struct NoCpuCulling;
Expand Down Expand Up @@ -310,9 +310,9 @@ impl<'a> SetViewVisibility for Mut<'a, ViewVisibility> {
/// [`Frustum`].
///
/// It can be used for example:
/// - when a [`Mesh`] is updated but its [`Aabb`] is not, which might happen with animations,
/// - when using some light effects, like wanting a [`Mesh`] out of the [`Frustum`]
/// to appear in the reflection of a [`Mesh`] within.
/// - when a `Mesh` is updated but its [`Aabb`] is not, which might happen with animations,
/// - when using some light effects, like wanting a `Mesh` out of the [`Frustum`]
/// to appear in the reflection of a `Mesh` within.
#[derive(Debug, Component, Default, Reflect, Clone, PartialEq)]
#[reflect(Component, Default, Debug)]
pub struct NoFrustumCulling;
Expand Down Expand Up @@ -556,7 +556,7 @@ pub struct NoAutoAabb;
/// This system is used in system set [`VisibilitySystems::CalculateBounds`].
pub fn calculate_bounds(
mut commands: Commands,
meshes: Res<Assets<Mesh>>,
meshes: Res<RetainedAssets<RetainedMesh>>,
new_aabb: Query<
(Entity, &Mesh3d),
(
Expand All @@ -576,17 +576,17 @@ pub fn calculate_bounds(
) {
for (entity, mesh_handle) in &new_aabb {
if let Some(mesh) = meshes.get(mesh_handle)
&& let Some(aabb) = mesh.compute_aabb()
&& let Some(aabb) = mesh.aabb
{
commands.entity(entity).try_insert(aabb);
commands.entity(entity).try_insert(Aabb::from(aabb));
}
}

update_aabb
.par_iter_mut()
.for_each(|(mesh_handle, mut old_aabb)| {
if let Some(aabb) = meshes.get(mesh_handle).and_then(MeshAabb::compute_aabb) {
*old_aabb = aabb;
if let Some(aabb) = meshes.get(mesh_handle).and_then(|m| m.aabb) {
*old_aabb = aabb.into();
}
});
}
Expand All @@ -595,7 +595,7 @@ pub fn calculate_bounds(
// component.
fn update_skinned_mesh_bounds(
inverse_bindposes_assets: Res<Assets<SkinnedMeshInverseBindposes>>,
mesh_assets: Res<Assets<Mesh>>,
mesh_assets: Res<RetainedAssets<RetainedMesh>>,
mut mesh_entities: Query<
(&mut Aabb, &Mesh3d, &SkinnedMesh, Option<&GlobalTransform>),
With<DynamicSkinnedMeshBounds>,
Expand Down
12 changes: 6 additions & 6 deletions crates/bevy_gizmos/src/skinned_mesh_bounds.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! A module adding debug visualization of [`DynamicSkinnedMeshBounds`].

use bevy_app::{Plugin, PostUpdate};
use bevy_asset::Assets;
use bevy_asset::{Assets, RetainedAssets};
use bevy_camera::visibility::DynamicSkinnedMeshBounds;
use bevy_color::Color;
use bevy_ecs::{
Expand All @@ -15,7 +15,7 @@ use bevy_math::Affine3A;
use bevy_mesh::{
mark_3d_meshes_as_changed_if_their_assets_changed,
skinning::{SkinnedMesh, SkinnedMeshInverseBindposes},
Mesh, Mesh3d,
Mesh3d, RetainedMesh,
};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_transform::{components::GlobalTransform, TransformSystems};
Expand Down Expand Up @@ -85,14 +85,14 @@ pub struct ShowSkinnedMeshBoundsGizmo {
fn draw(
color: Color,
mesh: &Mesh3d,
mesh_assets: &Res<Assets<Mesh>>,
mesh_assets: &Res<RetainedAssets<RetainedMesh>>,
skinned_mesh: &SkinnedMesh,
joint_entities: &Query<&GlobalTransform>,
inverse_bindposes_assets: &Res<Assets<SkinnedMeshInverseBindposes>>,
gizmos: &mut Gizmos<SkinnedMeshBoundsGizmoConfigGroup>,
) {
if let Some(mesh_asset) = mesh_assets.get(mesh)
&& let Some(bounds) = mesh_asset.skinned_mesh_bounds()
&& let Some(bounds) = &mesh_asset.skinned_mesh_bounds
&& let Some(inverse_bindposes_asset) =
inverse_bindposes_assets.get(&skinned_mesh.inverse_bindposes)
{
Expand All @@ -118,7 +118,7 @@ fn draw_skinned_mesh_bounds(
With<DynamicSkinnedMeshBounds>,
>,
joint_entities: Query<&GlobalTransform>,
mesh_assets: Res<Assets<Mesh>>,
mesh_assets: Res<RetainedAssets<RetainedMesh>>,
inverse_bindposes_assets: Res<Assets<SkinnedMeshInverseBindposes>>,
mut gizmos: Gizmos<SkinnedMeshBoundsGizmoConfigGroup>,
) {
Expand Down Expand Up @@ -146,7 +146,7 @@ fn draw_all_skinned_mesh_bounds(
),
>,
joint_entities: Query<&GlobalTransform>,
mesh_assets: Res<Assets<Mesh>>,
mesh_assets: Res<RetainedAssets<RetainedMesh>>,
inverse_bindposes_assets: Res<Assets<SkinnedMeshInverseBindposes>>,
mut gizmos: Gizmos<SkinnedMeshBoundsGizmoConfigGroup>,
) {
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_gizmos_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod pipeline_2d;
mod pipeline_3d;

use bevy_app::{App, Plugin};
use bevy_asset::EmptyRetainedAsset;
use bevy_ecs::{
name::Name,
resource::Resource,
Expand Down Expand Up @@ -253,8 +254,13 @@ struct GpuLineGizmo {

impl RenderAsset for GpuLineGizmo {
type SourceAsset = GizmoAsset;
type RetainedAsset = EmptyRetainedAsset<GizmoAsset>;
type Param = SRes<RenderDevice>;

fn retain_main_world_asset(_source: &mut Self::SourceAsset) -> Self::RetainedAsset {
EmptyRetainedAsset::default()
}

fn prepare_asset(
gizmo: Self::SourceAsset,
_: AssetId<Self::SourceAsset>,
Expand Down
12 changes: 6 additions & 6 deletions crates/bevy_mesh/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ use serde::{Deserialize, Serialize};
use thiserror::Error;
use wgpu_types::IndexFormat;

use crate::MeshAccessError;

/// A disjunction of four iterators. This is necessary to have a well-formed type for the output
/// of [`Mesh::triangles`](super::Mesh::triangles), which produces iterators of four different types depending on the
/// branch taken.
Expand Down Expand Up @@ -58,8 +56,6 @@ pub enum MeshWindingInvertError {
/// * [`PrimitiveTopology::LineList`](super::PrimitiveTopology::LineList), but the indices are not in chunks of 2.
#[error("Indices weren't in chunks according to topology")]
AbruptIndicesEnd,
#[error("Mesh access error: {0}")]
MeshAccessError(#[from] MeshAccessError),
}

/// An error that occurred while trying to extract a collection of triangles from a [`Mesh`](super::Mesh).
Expand All @@ -73,8 +69,12 @@ pub enum MeshTrianglesError {

#[error("Face index data references vertices that do not exist")]
BadIndices,
#[error("mesh access error: {0}")]
MeshAccessError(#[from] MeshAccessError),

#[error("Source mesh lacks position data")]
MissingPositions,

#[error("Source mesh lacks face index data")]
MissingIndices,
}

/// An array of indices into the [`VertexAttributeValues`](super::VertexAttributeValues) for a mesh.
Expand Down
Loading
Loading