Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 15 additions & 1 deletion crates/bevy_math/src/affine3.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
use glam::{Affine3, Affine3A, Vec3Swizzles, Vec4};
use glam::{vec3, Affine3, Affine3A, Mat3, Vec3Swizzles, Vec4, Vec4Swizzles};

/// Extension trait for [`Affine3`]
pub trait Affine3Ext {
/// Generates an [`Affine3`] from a transposed 3x4 matrix.
///
/// This is the inverse of [`Self::to_transpose`].
fn from_transpose(transposed: [Vec4; 3]) -> Self;
/// Calculates the transpose of the affine 4x3 matrix to a 3x4 and formats it for packing into GPU buffers
fn to_transpose(self) -> [Vec4; 3];
/// Calculates the inverse transpose of the 3x3 matrix and formats it for packing into GPU buffers
fn inverse_transpose_3x3(self) -> ([Vec4; 2], f32);
}

impl Affine3Ext for Affine3 {
fn from_transpose(transposed: [Vec4; 3]) -> Self {
let transpose_3x3 = Mat3::from_cols(
transposed[0].xyz(),
transposed[1].xyz(),
transposed[2].xyz(),
);
let translation = vec3(transposed[0].w, transposed[1].w, transposed[2].w);
Affine3::from_mat3_translation(transpose_3x3.transpose(), translation)
}

#[inline]
fn to_transpose(self) -> [Vec4; 3] {
let transpose_3x3 = self.matrix3.transpose();
Expand Down
66 changes: 64 additions & 2 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use bevy_material::{
labels::{DrawFunctionLabel, InternedShaderLabel, ShaderLabel},
MaterialProperties, OpaqueRendererMethod, RenderPhaseType,
};
use bevy_math::{Affine3, Affine3Ext as _};
use bevy_mesh::{
mark_3d_meshes_as_changed_if_their_assets_changed, Mesh3d, MeshVertexBufferLayoutRef,
};
Expand All @@ -37,6 +38,7 @@ use bevy_platform::collections::{HashMap, HashSet};
use bevy_platform::hash::FixedHasher;
use bevy_reflect::std_traits::ReflectDefault;
use bevy_reflect::Reflect;
use bevy_render::batching::gpu_preprocessing::BatchedInstanceBuffers;
use bevy_render::camera::{DirtySpecializationSystems, DirtySpecializations, PendingQueues};
use bevy_render::erased_render_asset::{
ErasedRenderAsset, ErasedRenderAssetPlugin, ErasedRenderAssets, PrepareAssetError,
Expand Down Expand Up @@ -1114,8 +1116,12 @@ pub fn queue_material_meshes(
render_materials: Res<ErasedRenderAssets<PreparedMaterial>>,
render_mesh_instances: Res<RenderMeshInstances>,
render_material_instances: Res<RenderMaterialInstances>,
mesh_assets: Res<RenderAssets<RenderMesh>>,
mesh_allocator: Res<MeshAllocator>,
gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
maybe_batched_instance_buffers: Option<
Res<BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>,
>,
mut opaque_render_phases: ResMut<ViewBinnedRenderPhases<Opaque3d>>,
mut alpha_mask_render_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3d>>,
mut transmissive_render_phases: ResMut<ViewSortedRenderPhases<Transmissive3d>>,
Expand Down Expand Up @@ -1227,7 +1233,18 @@ pub fn queue_material_meshes(
};
transmissive_phase.add(Transmissive3d {
sorting_info: TransparentSortingInfo3d::Sorted {
mesh_center: mesh_instance.center,
mesh_center: get_mesh_instance_world_from_local(
*visible_entity,
mesh_instance.current_uniform_index,
&render_mesh_instances,
maybe_batched_instance_buffers.as_deref(),
)
.transform_point3(
mesh_assets
.get(mesh_instance.mesh_asset_id())
.unwrap()
.aabb_center,
),
depth_bias: material.properties.depth_bias,
},
entity: (Entity::PLACEHOLDER, *visible_entity),
Expand Down Expand Up @@ -1316,7 +1333,18 @@ pub fn queue_material_meshes(
};
transparent_phase.add(Transparent3d {
sorting_info: TransparentSortingInfo3d::Sorted {
mesh_center: mesh_instance.center,
mesh_center: get_mesh_instance_world_from_local(
*visible_entity,
mesh_instance.current_uniform_index,
&render_mesh_instances,
maybe_batched_instance_buffers.as_deref(),
)
.transform_point3(
mesh_assets
.get(mesh_instance.mesh_asset_id())
.unwrap()
.aabb_center,
),
depth_bias: material.properties.depth_bias,
},
entity: (Entity::PLACEHOLDER, *visible_entity),
Expand Down Expand Up @@ -1784,3 +1812,37 @@ pub fn write_material_bind_group_buffers(
allocator.write_buffers(&render_device, &render_queue);
}
}

/// Returns the world-from-local transform for the given mesh instance.
pub fn get_mesh_instance_world_from_local(
entity: MainEntity,
current_uniform_index: InputUniformIndex,
render_mesh_instances: &RenderMeshInstances,
maybe_batched_instance_buffers: Option<&BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>,
) -> Affine3 {
// The way we fetch the world-from-local transform depends on whether we're
// doing CPU or GPU preprocessing. If we're doing CPU preprocessing, we have
// the world-from-local transform handy in `RenderMeshInstancesCpu`.
// Otherwise, if we're doing GPU preprocessing, we need to pull the
// transform out of the `MeshInputUniform` GPU buffer.
match *render_mesh_instances {
RenderMeshInstances::CpuBuilding(ref render_mesh_instances_cpu) => {
let Some(render_mesh_instance) = render_mesh_instances_cpu.get(&entity) else {
return Affine3::IDENTITY;
};
render_mesh_instance.transforms.world_from_local
}
RenderMeshInstances::GpuBuilding(_) => {
let Some(batched_instance_buffers) = maybe_batched_instance_buffers else {
return Affine3::IDENTITY;
};
let Some(mesh_input_uniform) = batched_instance_buffers
.current_input_buffer
.get(current_uniform_index.0)
else {
return Affine3::IDENTITY;
};
Affine3::from_transpose(mesh_input_uniform.world_from_local)
}
}
}
65 changes: 8 additions & 57 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,7 @@ pub struct RenderMeshInstanceSharedFlat {
asset_id: MeshAssetIdFlat,
material_bindings_index: MaterialBindingId,
lightmap_slab_index: LightmapSlabIndexFlat,
// FIXME: Remove this. This should be a field on `Mesh`.
model_space_center: Vec3,
tag: u32,
// FIXME: Remove this. This should be recomputed on demand, not cached here.
world_space_center: Vec3,
current_uniform_index: u32,
flags: RenderMeshInstanceFlags,
}
Expand All @@ -858,7 +854,6 @@ impl_atomic_pod!(
lightmap_slab_index_flat,
set_lightmap_slab_index_flat
),
field(model_space_center: Vec3, model_space_center, set_model_space_center),
field(tag: u32, tag, set_tag),
field(flags: RenderMeshInstanceFlags, flags, set_flags),
);
Expand Down Expand Up @@ -896,15 +891,12 @@ impl RenderMeshInstanceSharedFlatBlob {
#[derive(Clone, Copy, Default, Pod, Zeroable)]
#[repr(C)]
pub struct RenderMeshInstanceGpuFlat {
// FIXME: Remove this. This should be recomputed on demand, not cached here.
world_space_center: Vec3,
current_uniform_index: u32,
}

impl_atomic_pod!(
RenderMeshInstanceGpuFlat,
RenderMeshInstanceGpuFlatBlob,
field(world_space_center: Vec3, world_space_center, set_world_space_center),
field(current_uniform_index: u32, current_uniform_index, set_current_uniform_index),
);

Expand Down Expand Up @@ -1105,7 +1097,6 @@ impl RenderMeshInstanceSharedFlat {
not_shadow_caster: bool,
no_automatic_batching: bool,
no_cpu_culling: bool,
aabb: Option<&Aabb>,
) -> Self {
Self::new(
previous_transform,
Expand All @@ -1115,7 +1106,6 @@ impl RenderMeshInstanceSharedFlat {
not_shadow_caster,
no_automatic_batching,
no_cpu_culling,
aabb,
)
}

Expand All @@ -1127,7 +1117,6 @@ impl RenderMeshInstanceSharedFlat {
material_bindings_index: MaterialBindingId,
not_shadow_caster: bool,
no_automatic_batching: bool,
aabb: Option<&Aabb>,
) -> Self {
Self::new(
previous_transform,
Expand All @@ -1137,7 +1126,6 @@ impl RenderMeshInstanceSharedFlat {
not_shadow_caster,
no_automatic_batching,
false,
aabb,
)
}

Expand All @@ -1149,7 +1137,6 @@ impl RenderMeshInstanceSharedFlat {
not_shadow_caster: bool,
no_automatic_batching: bool,
no_cpu_culling: bool,
aabb: Option<&Aabb>,
) -> Self {
let mut mesh_instance_flags = RenderMeshInstanceFlags::empty();
mesh_instance_flags.set(RenderMeshInstanceFlags::SHADOW_CASTER, !not_shadow_caster);
Expand All @@ -1166,14 +1153,11 @@ impl RenderMeshInstanceSharedFlat {
RenderMeshInstanceSharedFlat {
asset_id: mesh.id().into(),
material_bindings_index,
model_space_center: aabb.map_or(Vec3::ZERO, |aabb| aabb.center.into()),
tag: tag.map_or(0, |i| **i),
flags: mesh_instance_flags,
// Filled in later.
lightmap_slab_index: LightmapSlabIndexFlat::default(),
// Filled in later.
world_space_center: Vec3::ZERO,
// Filled in later.
current_uniform_index: 0,
}
}
Expand Down Expand Up @@ -1254,20 +1238,12 @@ impl RenderMeshInstancesCpu {
}

fn render_mesh_queue_data(&self, entity: MainEntity) -> Option<RenderMeshQueueData<'_>> {
self.get(&entity).map(|render_mesh_instance| {
let world_from_local = &render_mesh_instance.transforms.world_from_local;
let center = world_from_local
.matrix3
.mul_vec3(render_mesh_instance.shared.model_space_center())
+ world_from_local.translation;

RenderMeshQueueData {
self.get(&entity)
.map(|render_mesh_instance| RenderMeshQueueData {
shared: &render_mesh_instance.shared,
render_layers: render_mesh_instance.render_layers.clone(),
center,
current_uniform_index: InputUniformIndex::default(),
}
})
})
}

/// Inserts the given flags into the render mesh instance data for the given
Expand All @@ -1290,7 +1266,6 @@ impl RenderMeshInstancesGpu {
.map(|render_mesh_instance| RenderMeshQueueData {
shared: &render_mesh_instance.shared,
render_layers: render_mesh_instance.render_layers.clone(),
center: render_mesh_instance.gpu_specific.world_space_center(),
current_uniform_index: InputUniformIndex(
render_mesh_instance.gpu_specific.current_uniform_index(),
),
Expand Down Expand Up @@ -1528,16 +1503,9 @@ impl RenderMeshInstanceGpuBuilder {
morph_descriptor_index,
};

let world_from_local = &self.world_from_local;
let center = world_from_local
.matrix3
.mul_vec3(self.shared.model_space_center)
+ world_from_local.translation;

Some(RenderMeshInstanceGpuPrepared {
shared: self.shared,
mesh_input_uniform,
center,
render_layers: self.render_layers,
})
}
Expand All @@ -1549,8 +1517,6 @@ pub struct RenderMeshInstanceGpuPrepared {
shared: RenderMeshInstanceSharedFlat,
/// The data that will be uploaded to the GPU as a [`MeshInputUniform`].
mesh_input_uniform: MeshInputUniform,
/// The world-space center of the mesh instance, used for culling and sorting.
center: Vec3,
/// The render layers that this mesh instance belongs to.
render_layers: Option<RenderLayers>,
}
Expand Down Expand Up @@ -1590,9 +1556,6 @@ impl RenderMeshInstanceGpuPrepared {
// Write the instance.
let existing_instance = occupied_entry.get_mut();
self.shared.write_to_blob(&existing_instance.shared);
existing_instance
.gpu_specific
.set_world_space_center(self.center);
existing_instance
.gpu_specific
.set_current_uniform_index(current_uniform_index);
Expand All @@ -1610,7 +1573,6 @@ impl RenderMeshInstanceGpuPrepared {
});
self.shared.write_to_blob(&new_instance.shared);
RenderMeshInstanceGpuFlat {
world_space_center: self.center,
current_uniform_index,
}
.write_to_blob(&new_instance.gpu_specific);
Expand Down Expand Up @@ -1690,11 +1652,6 @@ pub struct RenderMeshQueueData<'a> {
pub shared: &'a RenderMeshInstanceSharedFlatBlob,
/// The render layers that this mesh instance belongs to.
pub render_layers: Option<RenderLayers>,
/// The representative position of the mesh instance in world-space.
///
/// This world-space center is used as a spatial proxy for view-dependent
/// operations such as distance computation and render-order sorting.
pub center: Vec3,
/// The index of the [`MeshInputUniform`] in the GPU buffer for this mesh
/// instance.
pub current_uniform_index: InputUniformIndex,
Expand Down Expand Up @@ -1815,7 +1772,6 @@ pub fn extract_meshes_for_cpu_building(
Has<NoAutomaticBatching>,
Option<&VisibilityRange>,
Option<&RenderLayers>,
Option<&Aabb>,
)>,
>,
) {
Expand All @@ -1836,7 +1792,6 @@ pub fn extract_meshes_for_cpu_building(
no_automatic_batching,
visibility_range,
render_layers,
aabb,
)| {
if !view_visibility.get() {
return;
Expand Down Expand Up @@ -1870,19 +1825,19 @@ pub fn extract_meshes_for_cpu_building(
material_bindings_index,
not_shadow_caster,
no_automatic_batching,
aabb,
);

let world_from_local = transform.affine();
let previous_world_from_local = previous_transform
.map(|previous_transform| previous_transform.0)
.unwrap_or(world_from_local);

queue.push((
entity,
RenderMeshInstanceCpu {
transforms: MeshTransforms {
world_from_local: world_from_local.into(),
previous_world_from_local: (previous_transform
.map(|t| t.0)
.unwrap_or(world_from_local))
.into(),
previous_world_from_local: previous_world_from_local.into(),
flags: mesh_flags.bits(),
},
shared: (&shared).into(),
Expand Down Expand Up @@ -2178,7 +2133,6 @@ fn extract_mesh_for_gpu_building(
not_shadow_caster,
no_automatic_batching,
no_cpu_culling,
aabb,
);

// Calculate the lightmap UV rect, if applicable.
Expand Down Expand Up @@ -2626,9 +2580,6 @@ pub fn collect_meshes_for_gpu_building(
// only fields that changed are POD fields.

prepared.shared.write_to_blob(&render_mesh_instance.shared);
render_mesh_instance
.gpu_specific
.set_world_space_center(prepared.center);

let current_uniform_index =
render_mesh_instance.gpu_specific.current_uniform_index();
Expand Down
Loading